Skip to content

ledger: UndoTransaction takes a journalId that no action in the wire surface returns #428

Description

@Yaraslaut

Split out of morph#362, which recorded the problem but could not fix this half.

What is wrong

UndoTransaction{ledgerId, journalId} reverses a journal entry, and no action
in the ledger rung's wire surface returns a journalId
. StoreTransaction
returns GetLedgerResult — the accounts list — and so does GetLedger. There
is no GetJournal or ListTransactions. So a client can only ever call
UndoTransaction with an id it guessed.

Verified by enumerating the wire surface rather than by inspection: JournalId
appears in exactly one DTO, examples/ledger/dto/transaction_dto.hpp:112, which
is UndoTransaction's own input. No result type carries one.

This matters because undo is in the rung's own "What to implement" (step 6) and
its journal-derived-undo story is one of the subsystems the rung exists to
exercise. The in-process tests get the id from the database; the client-side
half is unreachable.

Why it is a separate ticket

morph#362 closed by documenting both unreachable actions in
examples/ledger/README.md, which is what a client author needed and what that
issue's acceptance asked for. Actually making UndoTransaction drivable is a
different change, and it cannot be done inside examples/ alone — see below.

The constraint that makes this cross-lane

Whichever direction is chosen, two files under scripts/ must change, and they
are outside the examples/ lane:

  • scripts/scenario/scenarios/ledger/undo-needs-a-journal-id-nothing-hands-out.scenario
    asserts expect ok field @body !~ "journalId" — it pins the current
    absence
    and would fail the moment a result carries one.
  • scripts/scenario/coverage_allowlist.json exempts UndoTransaction from
    workflow coverage on the stated grounds that it cannot be driven.

Both are the record of the current contract, so both are load-bearing rather
than incidental.

The two directions

  1. Make it drivable — a GetJournal/ListTransactions action, or a receipt
    carrying the journalId on StoreTransaction's result. This is the option
    the rung's own step 6 implies, and it is the larger change: it adds wire
    surface, which needs a DTO, a schema, scenario coverage and a spec sentence.
  2. Record undo as administrative — state in the rung's documentation that
    UndoTransaction is an operator action driven out of band, like
    RunReportJob is a service-principal action. Cheaper, and consistent with
    how the sibling unreachable action was resolved, but it closes off a
    capability the rung says it demonstrates.

morph#362's README section says the question is open and cites that issue; this
one now carries it.

Verification status: reproduced

The JournalId enumeration above, run over the rung's DTO headers. The
!~ "journalId" assertion read from the scenario file on master. Both
recorded by the N ladder lane while closing morph#362.

Not verified: whether any consumer outside the rung depends on
StoreTransaction's result shape, which direction 1 would change. The rung's
own GUI and tests are the only known consumers, but that was not exhaustively
checked.

What would close this

A decision, recorded in examples/ledger/README.md, plus whichever follows:

  • If drivable: an out-of-process client can complete store → read id → undo,
    demonstrated by a scenario that asserts the reversal, and the
    undo-needs-a-journal-id-nothing-hands-out.scenario and
    coverage_allowlist.json entries are retired rather than left asserting a
    contract that no longer holds.
  • If administrative: the README says so in the same terms it uses for
    RunReportJob, and the allowlist entry's stated reason is updated to name the
    decision rather than the absence.

Not closable by adding a GetJournal action while leaving the scenario
asserting journalId is absent — the two would contradict, and the scenario
would fail.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: ladderSubsystem: ladderenhancementNew feature or requesttriage: rescopeReal problem, wrong framing; rewrite before building

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions