Files
werkregie/doc/prs/2026-10-14-PR#85-journal-summary.md
claude-code c8a1de77df
werkator build succeeded after 02:10
werkator/deploy build succeeded after 00:51
An AI summary as the description of a Werkjournal entry (#85)
Co-authored-by: claude-code <claude-code@javagil.de>
2026-10-14 22:34:04 +02:00

134 lines
6.6 KiB
Markdown

# PR#85: An AI Summary as the Description of a Werkjournal Entry
Version: minor
> **WARNING:** This document describes only the change applied in this PR.
> It may already be outdated once the next PR is merged.
> Historic PR documentation is not maintained along with new PRs; treat it as a snapshot.
## Related Links
- [werkregie PR#84](https://git.javagil.de/mi/werkregie/pulls/84): `JournalProposer` at a Mutation-CRAP of at most 15, the prerequisite.
## Problem
The description of a proposed Werkjournal entry is built by rules: the story, the pull requests, the tasks,
the sessions and the Matrix rooms, joined by semicolons.
It names what happened, but reads as a list, not as a description of the work.
Werkjournal adds a changed entry as a new one, so the same data must give the same text.
## Non-Goals
- No transcripts as input; the model gets the evidence of the entry only, as the rules do.
- No change of the rule text.
## Specification
### Feature: an AI summary as the description of a Werkjournal entry
#### Scenario#85.01: the switch takes the AI summary into the entries and the file
&hellip; so that the human imports a readable description.
- **Given** a day with an entry of the project Werkregie and a configured `journal.summary`
- **When** the human selects "KI" in the tab Journal
- **Then** the entry shows the AI summary of its evidence, and the copied or downloaded file holds it
##### Verified by
- [JournalProposerTest "each entry of the file gets the AI summary of its evidence; the file keeps the rule text"](../../dashboard/src/test/kotlin/de/hoennig/werkregie/dashboard/journal/JournalProposerTest.kt)
- [journal.test.js "the rules take the rule text, the AI its summary"](../../dashboard/src/test/js/journal.test.js)
- [EntrySummariesTest "the chat model gets the instructions and the evidence with the key, and its text is the summary"](../../dashboard/src/test/kotlin/de/hoennig/werkregie/dashboard/journal/EntrySummariesTest.kt)
- manual check in the browser, see "Solution"
#### Scenario#85.02: the same data gives the same summary
&hellip; so that a second import adds no entry to Werkjournal.
- **Given** a day whose proposal was summarized once
- **When** the human opens the proposal of that day again, also after a restart of the server
- **Then** each entry shows the same summary, and the model is not asked again
##### Verified by
- [EntrySummariesTest "the same input gives the same summary, after a restart too, and the model is asked once"](../../dashboard/src/test/kotlin/de/hoennig/werkregie/dashboard/journal/EntrySummariesTest.kt)
- [EntrySummariesTest "a summary in use is kept beyond the time since it was written"](../../dashboard/src/test/kotlin/de/hoennig/werkregie/dashboard/journal/EntrySummariesTest.kt)
- [EntrySummariesTest "the model gets the project, the story and the evidence of the entry, in the order of the proposal"](../../dashboard/src/test/kotlin/de/hoennig/werkregie/dashboard/journal/EntrySummariesTest.kt)
#### Scenario#85.03: without a model the rules stay
&hellip; so that a configuration without a model works as before.
- **Given** no `journal.summary` in the configuration
- **When** the human opens the tab Journal
- **Then** the tab shows no switch, and each entry the rule text
##### Verified by
- [EntrySummariesTest "no model configured is no summaries; a missing key is their problem; a key from the environment works"](../../dashboard/src/test/kotlin/de/hoennig/werkregie/dashboard/journal/EntrySummariesTest.kt)
- [journal.test.js "an entry without summary keeps the rule text under the AI too"](../../dashboard/src/test/js/journal.test.js)
#### Scenario#85.04: a failing model leaves the rule text and names the cause
&hellip; so that the human can import the day all the same.
- **Given** a configured `journal.summary` whose model fails
- **When** the human selects "KI"
- **Then** each entry keeps the rule text, and the tab names the cause
##### Verified by
- [JournalProposerTest "a failing model leaves the entries without summary and names the cause"](../../dashboard/src/test/kotlin/de/hoennig/werkregie/dashboard/journal/JournalProposerTest.kt)
- [EntrySummariesTest "without a model, or with an empty answer, there is no summary and the cause is named"](../../dashboard/src/test/kotlin/de/hoennig/werkregie/dashboard/journal/EntrySummariesTest.kt)
- manual check in the browser, see "Solution"
#### Scenario#85.05: the choice stays
&hellip; so that the human does not select it for each day.
- **Given** the tab Journal with "KI" selected
- **When** the human picks another day or opens the page again
- **Then** "KI" stays selected
##### Verified by
- manual check in the browser, see "Solution"
## Solution
- `journal.summary` configures the chat model, as `claude.summary` does; without it, nothing changes.
- `EntrySummaries` asks the model for each entry of the file, in parallel, with the project, the story and the evidence;
the instructions ask for one or two German sentences of at most 300 characters, without invented facts.
It keeps each summary by the SHA-256 of its input in `<stateDir>/journal-summaries.json`, 400 days after its last use;
one lock per input keeps two requests of the same day from two answers.
- `ProposedEntry.summary` carries the summary; `Proposal.summaryError` the first failure, e.g. a missing key.
The file of the server keeps the rule text; the page builds the imported file from the text the switch picks.
- The tab Journal shows the switch "Regeln | KI" when an entry has a summary or the proposal an error;
the page keeps the choice, and a correction of the human stays with the text it corrected.
- `journalDescription` and `journalField` move into `static/journal.js`, tested by `jsTest` (ADR 0002).
### Manual Check
On 2026-10-14, a local dashboard with the recorded day 2026-10-13 and `journal.summary` with Haiku through OpenRouter:
- The first proposal took 6 s and gave, e.g. for the project Werk:
"Werkjournal-Import pro Kalendertag, Kunden-, Projekt- und Gewohnheitsangaben aus importierten Einträgen (PR#6), …";
the second took 0.03 s and gave the same texts from `journal-summaries.json`.
- "KI" showed the summaries in the entries, "Regeln" the rule texts; the choice stayed after a reload.
- Without the key, the switch stayed, the entries kept the rule text,
and the tab said "Keine KI-Zusammenfassung: kein Schlüssel in OPENROUTER_API_KEY".
## Release Notes
The tab Journal offers an AI summary of each entry beside the rule text, with the switch "Regeln | KI";
the server needs `journal.summary` for it.
## Additional Changes
- `dashboard.server.example.yml` names `journal.summary`.
## Open Questions
None.