[GH-ISSUE #8165] [Design] Preserve and reopen owned Ghidra analysis with a packed-program checkpoint #4691

Open
opened 2026-10-31 00:52:31 +00:00 by bsakaguchi · 7 comments
Owner

Originally created by @morluto on GitHub (Oct 30, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/8165

Before submitting

  • I searched the open and closed issues and pull requests for a related discussion.
  • I understand the contribution scope must be reviewed before integration; open questions are welcome here.
  • This discussion does not include credentials, private samples, or sensitive target data.

Decision needed

Should REA support an explicit, caller-directed checkpoint and later reopening of an owned Ghidra program, including session edits, without modifying the selected source project or executable? Is a Ghidra packed program (.gzf) an appropriate first format?

Context and evidence

At REA commit 47fa6ab3795d547207001ffb01643c0aa39dcad8, fresh-import Ghidra sessions are temporary. Metadata edits are discarded on close, and cancellation of an active operation ends the session. Existing-project mode copies a caller-selected .gpr/.rep into an owned runtime, validates the program's recorded import SHA-256, and opens it read-only without reanalysis; REA does not allow edits in that mode. An Evidence bundle or REA analysis snapshot is not a resumable Ghidra database.

Observed on macOS arm64, Ghidra 12.1.4 and JDK 21: a small self-built Mach-O was imported with analyzeHeadless -readOnly; a post-script renamed one function and called currentProgram.saveToPackedFile after ending the script transaction. A second headless invocation imported the .gzf into a new project with -noanalysis: the renamed function was present, two functions were reported, and the recorded executable SHA-256 matched the fixture. The initial attempt without ending the script transaction failed with Unable to lock due to active transaction. That script error was logged even though the headless process exited zero. REA's bridge already ends its script transaction before serving requests.

A real stdio MCP session then selected the restored project via the existing environment settings: procedure_pseudo_code returned the renamed function; annotate_native_function returned capability_unavailable with reason Existing Ghidra project sessions are read-only. The packed export itself was not produced by REA. No large-target, cross-version, cancellation or failure-recovery results were measured.

Expected interaction with targets

Read existing files; launch the user-supplied Ghidra process; mutate metadata in an owned analysis program; write a caller-selected new artifact. The target executable and source project would remain unchanged. Other effects and applicable platform scope need review.

Boundary details (optional)

Preserve the selected target and provider identity, source project fingerprint, Ghidra version, explicit unknown analysis completeness and the origin of prior edits. Avoid implying that a .gzf is a full project archive. Do not conflate Evidence export or REA snapshots with an editable engine database. Windows P0 currently has no database-mutation authority.

Options and tradeoffs

Investigate exporting a single packed program after edits, with exclusive destination creation and a verified reopen/import path. An alternative is a new owned project or exporting/replaying only analyst annotations (#6405). Decide whether a private copy of an existing project may be edited and checkpointed, and how to select it for an individual CLI/MCP session; #3751 already discusses project and .gzf selection. Direct writes to the original project and arbitrary script execution are separate scope decisions.

Verification available so far

I have a prototype or observed results

Success criteria and open questions

Establish real Ghidra CLI/MCP round trips for fresh and existing-project sessions, including comments, names, function/type data and import identity. Verify version and format compatibility, concurrency/transaction boundaries, failed or interrupted writes, cancellation during finalization, destination conflicts, and cleanup retry. Determine what cannot be preserved and when the latest edits are at risk. Measure a representative repeated investigation before claiming time savings. A maintainer scope decision is required before substantial implementation intended for integration.

References

Additional cancellation observation

On a self-built Mach-O with a separate slow function, a real REA/Ghidra 12.1.4 stdio MCP session renamed fast_audit and added an entry comment; pseudocode showed both. Cancelling a different 1,200-branch decompile after 300 ms returned an SDK timeout; a later query returned the original function name without the comment, and close_binary succeeded. This establishes lost unsaved annotations on one active-operation cancellation, not every cancellation/finalization path.

A second run exported an Evidence bundle after cancellation and before querying again. That bundle contained the completed annotation record and pseudocode with the prior name/comment, even though the next live Ghidra query returned the original name. This preserves historical observations, not a resumable edited Ghidra program; it can mitigate loss of recorded context.

Existing immutable snapshot behavior verified

In a real Ghidra 12.1.4 stdio MCP session on a self-owned Mach-O, analyze_function returned a summary with a retained complete Evidence ID. close_binary(snapshot_path=...) succeeded without session edits and reported one primitive cache entry and two Evidence records. In a fresh MCP server, open_binary(snapshot_path=...) succeeded for the same target/profile; inspect_analysis_view returned the retained dossier's pseudocode using the original Evidence ID before any new decompile request. This demonstrates a useful existing way to carry completed observations forward. It does not save an editable Ghidra database or establish that a later provider operation is served without recomputation. The separate edited-session snapshot refusal and packed-program experiment described above still apply.

Originally created by @morluto on GitHub (Oct 30, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/8165 ### Before submitting - [x] I searched the open and closed issues and pull requests for a related discussion. - [x] I understand the [contribution scope](https://github.com/morluto/rea/blob/main/CONTRIBUTING.md#contribution-scope) must be reviewed before integration; open questions are welcome here. - [x] This discussion does not include credentials, private samples, or sensitive target data. ### Decision needed Should REA support an explicit, caller-directed checkpoint and later reopening of an owned Ghidra program, including session edits, without modifying the selected source project or executable? Is a Ghidra packed program (`.gzf`) an appropriate first format? ### Context and evidence At REA commit `47fa6ab3795d547207001ffb01643c0aa39dcad8`, fresh-import Ghidra sessions are temporary. Metadata edits are discarded on close, and cancellation of an active operation ends the session. Existing-project mode copies a caller-selected `.gpr`/`.rep` into an owned runtime, validates the program's recorded import SHA-256, and opens it read-only without reanalysis; REA does not allow edits in that mode. An Evidence bundle or REA analysis snapshot is not a resumable Ghidra database. Observed on macOS arm64, Ghidra 12.1.4 and JDK 21: a small self-built Mach-O was imported with `analyzeHeadless -readOnly`; a post-script renamed one function and called `currentProgram.saveToPackedFile` after ending the script transaction. A second headless invocation imported the `.gzf` into a new project with `-noanalysis`: the renamed function was present, two functions were reported, and the recorded executable SHA-256 matched the fixture. The initial attempt without ending the script transaction failed with `Unable to lock due to active transaction`. That script error was logged even though the headless process exited zero. REA's bridge already ends its script transaction before serving requests. A real stdio MCP session then selected the restored project via the existing environment settings: `procedure_pseudo_code` returned the renamed function; `annotate_native_function` returned `capability_unavailable` with reason `Existing Ghidra project sessions are read-only`. The packed export itself was not produced by REA. No large-target, cross-version, cancellation or failure-recovery results were measured. ### Expected interaction with targets Read existing files; launch the user-supplied Ghidra process; mutate metadata in an owned analysis program; write a caller-selected new artifact. The target executable and source project would remain unchanged. Other effects and applicable platform scope need review. ### Boundary details (optional) Preserve the selected target and provider identity, source project fingerprint, Ghidra version, explicit unknown analysis completeness and the origin of prior edits. Avoid implying that a `.gzf` is a full project archive. Do not conflate Evidence export or REA snapshots with an editable engine database. Windows P0 currently has no database-mutation authority. ### Options and tradeoffs Investigate exporting a single packed program after edits, with exclusive destination creation and a verified reopen/import path. An alternative is a new owned project or exporting/replaying only analyst annotations (#6405). Decide whether a private copy of an existing project may be edited and checkpointed, and how to select it for an individual CLI/MCP session; #3751 already discusses project and `.gzf` selection. Direct writes to the original project and arbitrary script execution are separate scope decisions. ### Verification available so far I have a prototype or observed results ### Success criteria and open questions Establish real Ghidra CLI/MCP round trips for fresh and existing-project sessions, including comments, names, function/type data and import identity. Verify version and format compatibility, concurrency/transaction boundaries, failed or interrupted writes, cancellation during finalization, destination conflicts, and cleanup retry. Determine what cannot be preserved and when the latest edits are at risk. Measure a representative repeated investigation before claiming time savings. A maintainer scope decision is required before substantial implementation intended for integration. ### References - [Ghidra headless analyzer documentation](https://github.com/NationalSecurityAgency/ghidra/blob/master/Ghidra/RuntimeScripts/support/analyzeHeadlessREADME.md) - [Ghidra packed-program API](https://ghidra.re/ghidra_docs/api/ghidra/base/project/GhidraProject.html) - Related: #3751 (existing project / `.gzf` input), #6405 (annotation export and replay), #3136 (reuse benefit research), #5271 (long-running analysis), #3509 (transport failure). ### Additional cancellation observation On a self-built Mach-O with a separate slow function, a real REA/Ghidra 12.1.4 stdio MCP session renamed `fast_audit` and added an entry comment; pseudocode showed both. Cancelling a different 1,200-branch decompile after 300 ms returned an SDK timeout; a later query returned the original function name without the comment, and `close_binary` succeeded. This establishes lost unsaved annotations on one active-operation cancellation, not every cancellation/finalization path. A second run exported an Evidence bundle after cancellation and before querying again. That bundle contained the completed annotation record and pseudocode with the prior name/comment, even though the next live Ghidra query returned the original name. This preserves historical observations, not a resumable edited Ghidra program; it can mitigate loss of recorded context. ### Existing immutable snapshot behavior verified In a real Ghidra 12.1.4 stdio MCP session on a self-owned Mach-O, `analyze_function` returned a summary with a retained complete Evidence ID. `close_binary(snapshot_path=...)` succeeded without session edits and reported one primitive cache entry and two Evidence records. In a fresh MCP server, `open_binary(snapshot_path=...)` succeeded for the same target/profile; `inspect_analysis_view` returned the retained dossier's pseudocode using the original Evidence ID before any new decompile request. This demonstrates a useful existing way to carry completed observations forward. It does not save an editable Ghidra database or establish that a later provider operation is served without recomputation. The separate edited-session snapshot refusal and packed-program experiment described above still apply.
Author
Owner

@morluto commented on GitHub (Oct 30, 2026):

A follow-up headless round trip on macOS arm64/Ghidra 12.1.4 exercised more than a rename. On the same owned Mach-O (ffad1b70c6a5a7ef3f7c3f59126be516520210777d949b35e97c9067f272aa2d), a post-script renamed _evaluate, set an entry comment, created /audit_checkpoint_record with three fields, applied a pointer parameter and return type, ended the script transaction, and wrote a .gzf. A second headless import with -noanalysis into a new owned project observed the same name, comment, signature, structure and original executable SHA-256; its decompiler used record->flags and record->id.

With that restored project selected through REA_GHIDRA_PROJECT_PATH and its exact root program name, a real REA MCP session opened the original binary, returned the renamed/commented typed pseudocode, and inspect_native_data_type returned the saved structure and fields. annotate_native_function was refused because existing-project sessions are read-only. A before/after content digest inventory of the selected project's 10 regular files matched, and the source binary SHA-256 remained unchanged.

The .gzf was created and imported by separate user-owned headless scripts, not by REA. The initial Ghidra import logged unrecoverable DWARF expressions even though the manually applied facts survived; this is not proof that all debug information, project state, formats, versions or cleanup-failure cases round-trip. Ghidra's script log was checked for the explicit success markers rather than relying on exit status alone.

<!-- gh-comment-id:6533513994 --> @morluto commented on GitHub (Oct 30, 2026): A follow-up headless round trip on macOS arm64/Ghidra 12.1.4 exercised more than a rename. On the same owned Mach-O (`ffad1b70c6a5a7ef3f7c3f59126be516520210777d949b35e97c9067f272aa2d`), a post-script renamed `_evaluate`, set an entry comment, created `/audit_checkpoint_record` with three fields, applied a pointer parameter and return type, ended the script transaction, and wrote a `.gzf`. A second headless import with `-noanalysis` into a new owned project observed the same name, comment, signature, structure and original executable SHA-256; its decompiler used `record->flags` and `record->id`. With that restored project selected through `REA_GHIDRA_PROJECT_PATH` and its exact root program name, a real REA MCP session opened the original binary, returned the renamed/commented typed pseudocode, and `inspect_native_data_type` returned the saved structure and fields. `annotate_native_function` was refused because existing-project sessions are read-only. A before/after content digest inventory of the selected project's 10 regular files matched, and the source binary SHA-256 remained unchanged. The `.gzf` was created and imported by separate user-owned headless scripts, not by REA. The initial Ghidra import logged unrecoverable DWARF expressions even though the manually applied facts survived; this is not proof that all debug information, project state, formats, versions or cleanup-failure cases round-trip. Ghidra's script log was checked for the explicit success markers rather than relying on exit status alone.
Author
Owner

@morluto commented on GitHub (Oct 30, 2026):

A related manual recovery control is recorded in #6405: completed annotation Evidence can be imported into a fresh session and a caller-selected name/comment can be reapplied after target and profile checks, but importing it does not restore the Ghidra database. Two sessions applying the same two edits in opposite orders produced identical annotation Evidence IDs in identical canonical bundle order despite ending with different live names/comments. Evidence alone is therefore not a chronological edit log. This narrows the existing mitigation; it does not replace an explicit checkpoint or prove general replay safety.

<!-- gh-comment-id:6534371791 --> @morluto commented on GitHub (Oct 30, 2026): A related manual recovery control is recorded in #6405: completed annotation Evidence can be imported into a fresh session and a caller-selected name/comment can be reapplied after target and profile checks, but importing it does not restore the Ghidra database. Two sessions applying the same two edits in opposite orders produced identical annotation Evidence IDs in identical canonical bundle order despite ending with different live names/comments. Evidence alone is therefore not a chronological edit log. This narrows the existing mitigation; it does not replace an explicit checkpoint or prove general replay safety.
Author
Owner

@morluto commented on GitHub (Oct 31, 2026):

Looping in @gensokyo-dev @kaoru0822-kitauji @N0zoM1z0 for visibility on the Ghidra, Kuna, and REA tool-design investigation.

<!-- gh-comment-id:6538780202 --> @morluto commented on GitHub (Oct 31, 2026): Looping in @gensokyo-dev @kaoru0822-kitauji @N0zoM1z0 for visibility on the Ghidra, Kuna, and REA tool-design investigation.
Author
Owner

@morluto commented on GitHub (Oct 31, 2026):

Real MCP/TypeScript SDK close-finalization control on a source-owned, unexecuted Mach-O with Ghidra 12.1.4 and REA b43c329: after collecting a complete function dossier, call close_binary({snapshot_path:<new path>}). A test-only scheduling barrier in a disposable built runtime held the operation after the Ghidra client reported successful retirement, but before the remaining session/file/candidate cleanup and record clearing finished. At the barrier the snapshot file already existed.

In the cancellation run, the SDK aborted the close request and rejected with the caller's cancellation; the barrier was then released. A subsequent binary_session reported open:false and cleanup_pending:false. Reopening the same target with the saved snapshot succeeded, and inspect_analysis_view retrieved the original dossier's pseudocode by its retained Evidence ID. A separate no-cancellation barrier control returned the snapshot receipt (one primitive entry, one Evidence record) and recovered the same view. Both snapshot files had the same SHA-256 in this fixture, both sessions closed, and the target hash remained unchanged.

This is a positive result for one specific, deliberately delayed finalization boundary. The cancelled client received no close receipt, and the test does not establish whether the server transmitted a final response, cancellation behavior before snapshot publication, concurrent cleanup failures, or natural timing. The snapshot carries completed Evidence; it is not an edited Ghidra project. This complements the existing selected-project and packed-program continuity discussion.

<!-- gh-comment-id:6542026809 --> @morluto commented on GitHub (Oct 31, 2026): Real MCP/TypeScript SDK close-finalization control on a source-owned, unexecuted Mach-O with Ghidra 12.1.4 and REA `b43c329`: after collecting a complete function dossier, call `close_binary({snapshot_path:<new path>})`. A test-only scheduling barrier in a disposable built runtime held the operation after the Ghidra client reported successful retirement, but before the remaining session/file/candidate cleanup and record clearing finished. At the barrier the snapshot file already existed. In the cancellation run, the SDK aborted the close request and rejected with the caller's cancellation; the barrier was then released. A subsequent `binary_session` reported `open:false` and `cleanup_pending:false`. Reopening the same target with the saved snapshot succeeded, and `inspect_analysis_view` retrieved the original dossier's pseudocode by its retained Evidence ID. A separate no-cancellation barrier control returned the snapshot receipt (one primitive entry, one Evidence record) and recovered the same view. Both snapshot files had the same SHA-256 in this fixture, both sessions closed, and the target hash remained unchanged. This is a positive result for one specific, deliberately delayed finalization boundary. The cancelled client received no close receipt, and the test does not establish whether the server transmitted a final response, cancellation behavior before snapshot publication, concurrent cleanup failures, or natural timing. The snapshot carries completed Evidence; it is not an edited Ghidra project. This complements the existing selected-project and packed-program continuity discussion.
Author
Owner

@morluto commented on GitHub (Oct 31, 2026):

Pre-publication counterpart to the earlier close-finalization control: a disposable built-runtime scheduling barrier held close_binary({snapshot_path:<new path>}) after snapshot capture but immediately before its write. The destination did not yet exist when the TypeScript MCP SDK cancelled the request. After releasing the barrier, the SDK had already rejected with cancellation, but REA continued the close and published the snapshot. In the recorded run, status first reported open:false, cleanup_pending:true, then a later poll reported open:false, cleanup_pending:false. Reopening the target with that snapshot succeeded and its original function Evidence was retrievable. A no-cancellation control produced the same snapshot SHA-256; all closes succeeded and the unexecuted target hash was unchanged.

This is real SDK request cancellation at a test-delayed boundary, not proof of natural timing or a claim that cancellation always yields a snapshot. The close operation's existing implementation deliberately owns cleanup independently of the caller signal; the test also shows the snapshot write may complete after the caller stops waiting. A prior immediate sample observed open:true, cleanup_pending:false while the close was still in progress, so neither a single status sample nor the client rejection establishes the final write outcome. No server close receipt was available to the cancelled caller. This may inform recovery guidance and commit-boundary design without treating a REA Evidence snapshot as an editable Ghidra checkpoint.

<!-- gh-comment-id:6542043470 --> @morluto commented on GitHub (Oct 31, 2026): Pre-publication counterpart to the earlier close-finalization control: a disposable built-runtime scheduling barrier held `close_binary({snapshot_path:<new path>})` after snapshot capture but immediately before its write. The destination did not yet exist when the TypeScript MCP SDK cancelled the request. After releasing the barrier, the SDK had already rejected with cancellation, but REA continued the close and published the snapshot. In the recorded run, status first reported `open:false, cleanup_pending:true`, then a later poll reported `open:false, cleanup_pending:false`. Reopening the target with that snapshot succeeded and its original function Evidence was retrievable. A no-cancellation control produced the same snapshot SHA-256; all closes succeeded and the unexecuted target hash was unchanged. This is real SDK request cancellation at a test-delayed boundary, not proof of natural timing or a claim that cancellation always yields a snapshot. The close operation's existing implementation deliberately owns cleanup independently of the caller signal; the test also shows the snapshot write may complete after the caller stops waiting. A prior immediate sample observed `open:true, cleanup_pending:false` while the close was still in progress, so neither a single status sample nor the client rejection establishes the final write outcome. No server close receipt was available to the cancelled caller. This may inform recovery guidance and commit-boundary design without treating a REA Evidence snapshot as an editable Ghidra checkpoint.
Author
Owner

@morluto commented on GitHub (Oct 31, 2026):

Explicit snapshot overwrite and edited-session refusal

Real REA b43c329 stdio MCP on an owned, unexecuted Mach-O, Ghidra 12.1.4 and Kuna 1.986:

  • In separate clean sessions, I collected a complete function dossier and closed with snapshot_path pointing to an existing disposable test marker and overwrite:true. Both closes succeeded and replaced their markers with valid snapshots. Reopening each with the same provider and target allowed inspect_analysis_view to retrieve the original dossier by Evidence ID. Ghidra's receipt had one primitive entry; Kuna's had zero, so the Kuna result proves retained Evidence retrieval, not live-query cache reuse.
  • In a fresh Ghidra session, I renamed the function, then requested the same explicit overwrite of a different existing disposable marker. REA returned evidence_integrity_mismatch explaining that snapshots are unavailable after metadata changes. The marker's hash stayed unchanged, binary_session still reported open/no cleanup pending, and the edited name still resolved. Closing without a snapshot then succeeded.

The target hash remained unchanged and no target was executed. This tests an authorized overwrite and an early dirty-session refusal, not interrupted writes, permissions, cleanup failures or a resumable edited Ghidra project. Together with the earlier no-overwrite conflict control, it shows the practical recovery choice for these cases without implying snapshot support for live annotations.

<!-- gh-comment-id:6544072308 --> @morluto commented on GitHub (Oct 31, 2026): ### Explicit snapshot overwrite and edited-session refusal Real REA `b43c329` stdio MCP on an owned, unexecuted Mach-O, Ghidra 12.1.4 and Kuna 1.986: - In separate clean sessions, I collected a complete function dossier and closed with `snapshot_path` pointing to an existing **disposable test marker** and `overwrite:true`. Both closes succeeded and replaced their markers with valid snapshots. Reopening each with the same provider and target allowed `inspect_analysis_view` to retrieve the original dossier by Evidence ID. Ghidra's receipt had one primitive entry; Kuna's had zero, so the Kuna result proves retained Evidence retrieval, not live-query cache reuse. - In a fresh Ghidra session, I renamed the function, then requested the same explicit overwrite of a different existing disposable marker. REA returned `evidence_integrity_mismatch` explaining that snapshots are unavailable after metadata changes. The marker's hash stayed unchanged, `binary_session` still reported open/no cleanup pending, and the edited name still resolved. Closing without a snapshot then succeeded. The target hash remained unchanged and no target was executed. This tests an authorized overwrite and an early dirty-session refusal, not interrupted writes, permissions, cleanup failures or a resumable edited Ghidra project. Together with the earlier no-overwrite conflict control, it shows the practical recovery choice for these cases without implying snapshot support for live annotations.
Author
Owner

@morluto commented on GitHub (Oct 31, 2026):

Destination-permission and directory recovery controls

Real REA b43c329 stdio MCP on the owned Mach-O with Ghidra 12.1.4 and Kuna 1.986, running as an unprivileged macOS user: after collecting a dossier, I removed write permission from a disposable destination directory and tried both an existing marker with overwrite:true and a new filename in that directory. Both requests returned a file-access error advising a permission check; the existing marker hash was unchanged and the new file was absent. For both providers, binary_session remained open with no cleanup pending after each failure, and a procedure lookup still succeeded. Closing to a different writable path then succeeded; reopening the snapshot retrieved the original dossier. Ghidra recorded one primitive entry, Kuna zero, so the latter is Evidence retrieval rather than proof of provider-query replay. Directory permissions were restored afterward.

A separate Ghidra control selected an existing directory as the destination with overwrite:true. REA returned the distinct invalid_request / not-file error, preserved the directory's marker, kept the session usable, and closed successfully to a normal file. The target hash stayed unchanged throughout and no target was executed.

These are positive recovery checks for one host's directory-permission and destination-type failures. They do not cover disk-full, interrupted publication, cleanup failure, ACLs, Windows, or all I/O causes. The permission result's structured reason was the general io; no claim is made that every such error is a permission problem.

<!-- gh-comment-id:6544087495 --> @morluto commented on GitHub (Oct 31, 2026): ### Destination-permission and directory recovery controls Real REA `b43c329` stdio MCP on the owned Mach-O with Ghidra 12.1.4 and Kuna 1.986, running as an unprivileged macOS user: after collecting a dossier, I removed write permission from a disposable destination directory and tried both an existing marker with `overwrite:true` and a new filename in that directory. Both requests returned a file-access error advising a permission check; the existing marker hash was unchanged and the new file was absent. For both providers, `binary_session` remained open with no cleanup pending after each failure, and a procedure lookup still succeeded. Closing to a different writable path then succeeded; reopening the snapshot retrieved the original dossier. Ghidra recorded one primitive entry, Kuna zero, so the latter is Evidence retrieval rather than proof of provider-query replay. Directory permissions were restored afterward. A separate Ghidra control selected an existing directory as the destination with `overwrite:true`. REA returned the distinct `invalid_request` / `not-file` error, preserved the directory's marker, kept the session usable, and closed successfully to a normal file. The target hash stayed unchanged throughout and no target was executed. These are positive recovery checks for one host's directory-permission and destination-type failures. They do not cover disk-full, interrupted publication, cleanup failure, ACLs, Windows, or all I/O causes. The permission result's structured reason was the general `io`; no claim is made that every such error is a permission problem.
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#4691
No description provided.