Skip to content

let somebody read the journal the server has always written #94

Description

@haribo

Why

docs/design/product.md §6 promises that "I reported this three months ago, who removed it?" always has an answer. It does not: the answer is written and nothing reads it.

The journal table has been there since the first migration (00001_initial_schema.sql), and it is written on every transition (db/queries/intake.sql:80). It carries from_state, to_state, cause, actor_id, actor_kind, the inputs the computation consumed and the rule_version that produced it.

grep -rn "journal" apps/server/db/queries/*.sql returns one INSERT and three comments. No SELECT. No endpoint. The trace exists, is complete, and is unreachable.

Why it is not urgent, and why it is not optional

Nobody misses it in the first weeks: a reviewer looking at a case can see its current state, and the person who changed it is usually in the room. It starts mattering at the horizon the promise names — months — which is exactly when the answer becomes hard to reconstruct any other way.

So this can wait for real use to say what shape it should take. It cannot be dropped: a design that promises an answer and a database that holds it, with nothing between them, is the kind of gap that stays open for a year.

Build

Undecided on purpose — the shape should follow what somebody actually asks for. Two candidates:

  • GET /projects/{slug}/cases/{caseId}/history, which is what §9 already lists. A case's transitions, in order, each naming its actor and its cause.
  • Per comment, since the question in §6 is about a comment rather than a case. The journal keys on case_id, so answering it per comment means either a join through the case or a column that does not exist yet.

Whichever it is, it reads ReadProject on the project the case belongs to, like everything else (#71), and closed_test.go picks it up without being touched.

What it must not become

Not an audit export. §10 puts that out of scope for v1, and a history endpoint is not a way to smuggle it in.

Not a second source of truth for state. The current state is stored and computed by the server (ADR 0002). The journal says how it got there; it does not get to disagree about where it is.

Validation

  • A case that was validated, commented, delivered and accepted answers with those four transitions, in order, each naming who caused it.
  • actor_kind distinguishes a person from a program, since that is derived from how the caller authenticated and is the reason the journal is worth keeping (ADR 0018).
  • Rows written before identity existed still read, naming whatever they named. The journal is append-only and history is not rewritten to look answered.
  • A caller with no membership on the project gets the same refusal as on every other read of it.

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

    type: featurenew capability or improvement

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions