werkrevisor 0.19.1: billed calls as unknown repository, dry runs as local review #28

Merged
ai-reviewer merged 3 commits from claude-code/pseudo-repositories into main 2026-10-06 13:42:59 +02:00
Collaborator
See [docs/prs/2026-10-06-PR#28-pseudo-repositories.md](docs/prs/2026-10-06-PR%2328-pseudo-repositories.md). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
claude-code added 1 commit 2026-10-06 13:20:24 +02:00
docs: PR#28 doc for pseudo repositories of billed calls and dry runs
werkator build succeeded after 00:08
werkator/server build succeeded after 00:26
645ceaf9a0
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
claude-code marked the pull request as ready for review 2026-10-06 13:23:43 +02:00
mi added 1 commit 2026-10-06 13:23:44 +02:00
werkrevisor 0.19.1: billed calls as unknown repository, dry runs as local review
werkator build succeeded after 00:13
ai-review/assessment human review required; a human approval unlocks the merge; review requested from mi; merge scheduled for when the checks succeed
ai-review/gate build succeeded after 00:24
werkator/server build succeeded after 00:34
d4f112a5e4
The rows of the table per repository add up to the total; local reviews count in costs and reviews, not in pull requests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Collaborator
🟡 werkrevisor YELLOW for d4f112a, superseded by the result for 754ee60

🟡 werkrevisor: YELLOW / HUMAN_REVIEW

Change kind: mixed.

Reasons

  • YELLOW 1 changed file was given to the AI only as diff, not in full, so it could not check it against the rest of its file (each larger than [review] max_full_file_chars = 40000): werkrevisor/cli.py
  • hint writing rules violated in the changed docs: README.md:795: line longer than 128 characters (130)
  • hint 1 build change(s) of low risk according to Jev: server/build.gradle.kts (weakens checks 0.02, risk 0.00)
  • hint 3 finding(s) of low severity or rated minor by Jev: server/src/main/kotlin/de/hoennig/werkrevisor/server/Statistics.kt:203-220, server/src/main/kotlin/de/hoennig/werkrevisor/server/UsageStore.kt:172, docs/prs/2026-10-06-PR#28-pseudo-repositories.md:79
  • hint model recommends merge with caution

Findings

  1. [medium] Local rows missing from sums per period at server/src/main/kotlin/de/hoennig/werkrevisor/server/Statistics.kt:203-220, hint, as a line comment

  2. [medium] Local flag stored as boolean in integer column, old rows null at server/src/main/kotlin/de/hoennig/werkrevisor/server/UsageStore.kt:172, hint, as a line comment

  3. [low] Document mentions a token not in the diff at docs/prs/2026-10-06-PR#28-pseudo-repositories.md:79, hint, as a line comment

Classifier

8 of 8 units passed all questions (1 PR document(s)).
1 answer ignored because of a confidence below [classifier] min_confidence.

Usage: model `openrouter/anthropic/claude-sonnet-5.5`, LLM done, tokens counted before the call 68960, calls 1, tokens in 67863 / out 867 (reasoning included in out), duration 19.5 s, cost 0.1444 USD (reported), classifier `jev-1.13.0` calls 8, tokens in 6641, cost 0.0003 USD, finding judge `jev-1.13.0` calls 2, tokens in 2867, cost 0.0001 USD, build file judge `jev-1.13.0` calls 1, tokens in 560, cost 0.0000 USD, config: defaults + host + repository (.werkrevisor.toml at base f585223).
Reviewed head `d4f112a5e415ccf9307f295707e226cc65bc00ca` against base `f5852232e0b7cd9959c922c9ef081d90c029daf3`, werkrevisor 0.19.0.
<!-- werkrevisor:d4f112a5e415ccf9307f295707e226cc65bc00ca --> <!-- werkrevisor-verdict:YELLOW --> <!-- werkrevisor-folded --> <details><summary>🟡 werkrevisor YELLOW for <code>d4f112a</code>, superseded by <a href="http://git.javagil.de/mi/werkrevisor/pulls/28#issuecomment-1259">the result for <code>754ee60</code></a></summary> ## 🟡 werkrevisor: YELLOW / HUMAN_REVIEW Change kind: `mixed`. ### Reasons - **YELLOW** 1 changed file was given to the AI only as diff, not in full, so it could not check it against the rest of its file (each larger than [review] max_full_file_chars = 40000): werkrevisor/cli.py - **hint** writing rules violated in the changed docs: README.md:795: line longer than 128 characters (130) - **hint** 1 build change(s) of low risk according to Jev: server/build.gradle.kts (weakens checks 0.02, risk 0.00) - **hint** 3 finding(s) of low severity or rated minor by Jev: server/src/main/kotlin/de/hoennig/werkrevisor/server/Statistics.kt:203-220, server/src/main/kotlin/de/hoennig/werkrevisor/server/UsageStore.kt:172, docs/prs/2026-10-06-PR#28-pseudo-repositories.md:79 - **hint** model recommends merge with caution ### Findings 1. **[medium] Local rows missing from sums per period** at `server/src/main/kotlin/de/hoennig/werkrevisor/server/Statistics.kt:203-220`, hint, as a line comment 2. **[medium] Local flag stored as boolean in integer column, old rows null** at `server/src/main/kotlin/de/hoennig/werkrevisor/server/UsageStore.kt:172`, hint, as a line comment 3. **[low] Document mentions a token not in the diff** at `docs/prs/2026-10-06-PR#28-pseudo-repositories.md:79`, hint, as a line comment ### Classifier 8 of 8 units passed all questions (1 PR document(s)). 1 answer ignored because of a confidence below [classifier] min_confidence. <sub> Usage: model `openrouter/anthropic/claude-sonnet-5.5`, LLM done, tokens counted before the call 68960, calls 1, tokens in 67863 / out 867 (reasoning included in out), duration 19.5 s, cost 0.1444 USD (reported), classifier `jev-1.13.0` calls 8, tokens in 6641, cost 0.0003 USD, finding judge `jev-1.13.0` calls 2, tokens in 2867, cost 0.0001 USD, build file judge `jev-1.13.0` calls 1, tokens in 560, cost 0.0000 USD, config: defaults + host + repository (.werkrevisor.toml at base f585223).<br> Reviewed head `d4f112a5e415ccf9307f295707e226cc65bc00ca` against base `f5852232e0b7cd9959c922c9ef081d90c029daf3`, werkrevisor 0.19.0. </sub> </details>
ai-reviewer left a comment
Collaborator

werkrevisor: YELLOW / HUMAN_REVIEW for d4f112a5e415ccf9307f295707e226cc65bc00ca.
The result comment of werkrevisor holds the details.

werkrevisor: YELLOW / HUMAN_REVIEW for `d4f112a5e415ccf9307f295707e226cc65bc00ca`. The result comment of werkrevisor holds the details. <!-- werkrevisor-review:d4f112a5e415ccf9307f295707e226cc65bc00ca -->
@@ -0,0 +76,4 @@
- Each group of the table per repository holds `kind`: `repository`, `private`, `unknown` for the billed calls
or `local` for the dry runs; the Web Component names the last three in grey italics.
- The cards name the local reviews, e.g. "26 reviews (1 local)", and the recent reviews mark them with "local".
- The service gets a source token for dry runs; the operator keeps it in `WERKREVISOR_STATS_SOURCE_TOKEN_LOCAL`.
Collaborator

[low] Document mentions a token not in the diff (werkrevisor)

hint

The solution section says the service gets a source token for dry runs, kept in WERKREVISOR_STATS_SOURCE_TOKEN_LOCAL. No code in this PR adds or uses this variable; it is configuration of the operator. The statement is unclear about whether the PR changes anything for it.

**[low] Document mentions a token not in the diff** (werkrevisor) hint The solution section says the service gets a source token for dry runs, kept in `WERKREVISOR_STATS_SOURCE_TOKEN_LOCAL`. No code in this PR adds or uses this variable; it is configuration of the operator. The statement is unclear about whether the PR changes anything for it.
@@ -183,6 +200,25 @@ class StatisticsService(
.filterValues { runs -> runs.maxBy { it.timestamp }.repoPrivate == false }
.keys
private fun byRepo(
Collaborator

[medium] Local rows missing from sums per period (werkrevisor)

hint; Jev: real 0.22, severity 0.8 of 3

byRepo computes the "local" row from lastMonth records and lists repository rows with !it.local. The row "unknown repository" shows billed calls with 0 reviews. This is consistent, but byVerdict still includes local records and byModel too, while the table per verdict counts local reviews as pull requests via groups(...) and Sums.of. Since Sums.of excludes local records from pullRequests, this is fine. The remaining uncertainty is costPerPullRequestUsd, which subtracts localCostUsd from llmCostUsd + jevCostUsd. localCostUsd uses countedCostUsd, which equals the counted part, so the result is correct. No defect is confirmed here.

**[medium] Local rows missing from sums per period** (werkrevisor) hint; Jev: real 0.22, severity 0.8 of 3 `byRepo` computes the "local" row from `lastMonth` records and lists repository rows with `!it.local`. The row "unknown repository" shows billed calls with 0 reviews. This is consistent, but `byVerdict` still includes local records and `byModel` too, while the table per verdict counts local reviews as pull requests via `groups(...)` and `Sums.of`. Since `Sums.of` excludes local records from `pullRequests`, this is fine. The remaining uncertainty is `costPerPullRequestUsd`, which subtracts `localCostUsd` from `llmCostUsd + jevCostUsd`. `localCostUsd` uses `countedCostUsd`, which equals the counted part, so the result is correct. No defect is confirmed here.
@@ -162,6 +169,7 @@ class UsageStore(
llmOutputTokens = rs.getLong("llm_output_tokens").takeUnless { rs.wasNull() },
jevInputTokens = rs.getLong("jev_input_tokens").takeUnless { rs.wasNull() },
repoPrivate = rs.getBoolean("repo_private").takeUnless { rs.wasNull() },
local = rs.getBoolean("local"),
Collaborator

[medium] Local flag stored as boolean in integer column, old rows null (werkrevisor)

hint; Jev: real 0.23, severity 1.8 of 3

local is added as an integer column, so old rows hold NULL. rs.getBoolean("local") returns false for NULL, which is correct. However, the run_key does not include local: a dry run and a CI run of the same repo, PR, head and timestamp are practically unique. A real risk is low; this is only a note that a local run reporting the same key as a CI run would be dropped.

**[medium] Local flag stored as boolean in integer column, old rows null** (werkrevisor) hint; Jev: real 0.23, severity 1.8 of 3 `local` is added as an `integer` column, so old rows hold NULL. `rs.getBoolean("local")` returns false for NULL, which is correct. However, the `run_key` does not include `local`: a dry run and a CI run of the same repo, PR, head and timestamp are practically unique. A real risk is low; this is only a note that a local run reporting the same key as a CI run would be dropped.
ai-reviewer scheduled this pull request to auto merge when all checks succeed 2026-10-06 13:24:13 +02:00
ai-reviewer requested review from mi 2026-10-06 13:24:13 +02:00
Author
Collaborator

Assessment of the werkrevisor hints (as of the last commit):

Fixed:

  • PR doc: the source token for dry runs is operator configuration at the deployment; no code reads a dedicated variable.
  • README: line above 128 characters wrapped.

Not changed:

  • Statistics.kt:203-220, local rows in the period sums: the hint itself finds no defect; periods, verdicts and models count local reviews in costs and reviews, Sums.of leaves them out of the pull requests, and the cost per pull request subtracts their counted costs.
  • UsageStore.kt:172, local in an integer column: old rows hold NULL, which getBoolean reads as false, as intended. The run key holds repository, PR, head and timestamp in seconds; a dry run and a CI run with all four equal do not occur in practice.
  • YELLOW werkrevisor/cli.py given only as diff: the change is one line that marks a run without publishing as local; a test covers both cases.

The judged build path works: the version bump in server/build.gradle.kts is now a hint instead of YELLOW (weakens checks 0.02, risk 0.00).

🤖 Generated with Claude Code

Assessment of the werkrevisor hints (as of the last commit): Fixed: - PR doc: the source token for dry runs is operator configuration at the deployment; no code reads a dedicated variable. - README: line above 128 characters wrapped. Not changed: - `Statistics.kt:203-220`, local rows in the period sums: the hint itself finds no defect; periods, verdicts and models count local reviews in costs and reviews, `Sums.of` leaves them out of the pull requests, and the cost per pull request subtracts their counted costs. - `UsageStore.kt:172`, `local` in an integer column: old rows hold NULL, which `getBoolean` reads as false, as intended. The run key holds repository, PR, head and timestamp in seconds; a dry run and a CI run with all four equal do not occur in practice. - YELLOW `werkrevisor/cli.py` given only as diff: the change is one line that marks a run without publishing as local; a test covers both cases. The judged build path works: the version bump in `server/build.gradle.kts` is now a hint instead of YELLOW (weakens checks 0.02, risk 0.00). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
mi added 1 commit 2026-10-06 13:24:41 +02:00
review: PR#28 doc says that the dry-run token is operator configuration
werkator build succeeded after 00:11
ai-review/assessment human review required; a human approval unlocks the merge; a human review request is pending; merge already scheduled
ai-review/gate build succeeded after 00:19
werkator/server build succeeded after 00:29
754ee60c44
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Collaborator

🟡 werkrevisor: YELLOW / HUMAN_REVIEW

Change kind: mixed.

Reasons

  • YELLOW 1 changed file was given to the AI only as diff, not in full, so it could not check it against the rest of its file (each larger than [review] max_full_file_chars = 40000): werkrevisor/cli.py
  • hint 1 build change(s) of low risk according to Jev: server/build.gradle.kts (weakens checks 0.02, risk 0.00)
  • hint 3 finding(s) of low severity or rated minor by Jev: server/src/main/kotlin/de/hoennig/werkrevisor/server/UsageStore.kt:38, server/src/main/kotlin/de/hoennig/werkrevisor/server/UsageStore.kt:52, server/src/main/resources/static/werkrevisor-dashboard.js:227-229
  • hint model recommends merge with caution

Findings

  1. [medium] Local dry runs reuse the CI run key at server/src/main/kotlin/de/hoennig/werkrevisor/server/UsageStore.kt:38, hint, as a line comment

  2. [medium] Migration adds local as nullable integer without a default at server/src/main/kotlin/de/hoennig/werkrevisor/server/UsageStore.kt:52, hint, as a line comment

  3. [low] Truthiness precedence makes a hidden row depend on PSEUDO_REPOS at server/src/main/resources/static/werkrevisor-dashboard.js:227-229, hint, as a line comment

Classifier

8 of 8 units passed all questions (1 PR document(s)).
1 answer ignored because of a confidence below [classifier] min_confidence.

Usage: model `openrouter/anthropic/claude-sonnet-5.5`, LLM done, tokens counted before the call 69006, calls 1, tokens in 67900 / out 764 (reasoning included in out), duration 16.7 s, cost 0.1434 USD (reported), classifier `jev-1.13.0` calls 8, tokens in 6663, cost 0.0003 USD, finding judge `jev-1.13.0` calls 2, tokens in 2521, cost 0.0001 USD, build file judge `jev-1.13.0` calls 1, tokens in 560, cost 0.0000 USD, config: defaults + host + repository (.werkrevisor.toml at base f585223).
Reviewed head `754ee60c44517f32dac0b4d868c423a7a970e1c5` against base `f5852232e0b7cd9959c922c9ef081d90c029daf3`, werkrevisor 0.19.0.
<!-- werkrevisor:754ee60c44517f32dac0b4d868c423a7a970e1c5 --> <!-- werkrevisor-verdict:YELLOW --> ## 🟡 werkrevisor: YELLOW / HUMAN_REVIEW Change kind: `mixed`. ### Reasons - **YELLOW** 1 changed file was given to the AI only as diff, not in full, so it could not check it against the rest of its file (each larger than [review] max_full_file_chars = 40000): werkrevisor/cli.py - **hint** 1 build change(s) of low risk according to Jev: server/build.gradle.kts (weakens checks 0.02, risk 0.00) - **hint** 3 finding(s) of low severity or rated minor by Jev: server/src/main/kotlin/de/hoennig/werkrevisor/server/UsageStore.kt:38, server/src/main/kotlin/de/hoennig/werkrevisor/server/UsageStore.kt:52, server/src/main/resources/static/werkrevisor-dashboard.js:227-229 - **hint** model recommends merge with caution ### Findings 1. **[medium] Local dry runs reuse the CI run key** at `server/src/main/kotlin/de/hoennig/werkrevisor/server/UsageStore.kt:38`, hint, as a line comment 2. **[medium] Migration adds `local` as nullable integer without a default** at `server/src/main/kotlin/de/hoennig/werkrevisor/server/UsageStore.kt:52`, hint, as a line comment 3. **[low] Truthiness precedence makes a hidden row depend on `PSEUDO_REPOS`** at `server/src/main/resources/static/werkrevisor-dashboard.js:227-229`, hint, as a line comment ### Classifier 8 of 8 units passed all questions (1 PR document(s)). 1 answer ignored because of a confidence below [classifier] min_confidence. <sub> Usage: model `openrouter/anthropic/claude-sonnet-5.5`, LLM done, tokens counted before the call 69006, calls 1, tokens in 67900 / out 764 (reasoning included in out), duration 16.7 s, cost 0.1434 USD (reported), classifier `jev-1.13.0` calls 8, tokens in 6663, cost 0.0003 USD, finding judge `jev-1.13.0` calls 2, tokens in 2521, cost 0.0001 USD, build file judge `jev-1.13.0` calls 1, tokens in 560, cost 0.0000 USD, config: defaults + host + repository (.werkrevisor.toml at base f585223).<br> Reviewed head `754ee60c44517f32dac0b4d868c423a7a970e1c5` against base `f5852232e0b7cd9959c922c9ef081d90c029daf3`, werkrevisor 0.19.0. </sub>
ai-reviewer left a comment
Collaborator

werkrevisor: YELLOW / HUMAN_REVIEW for 754ee60c44517f32dac0b4d868c423a7a970e1c5.
The result comment of werkrevisor holds the details.

werkrevisor: YELLOW / HUMAN_REVIEW for `754ee60c44517f32dac0b4d868c423a7a970e1c5`. The result comment of werkrevisor holds the details. <!-- werkrevisor-review:754ee60c44517f32dac0b4d868c423a7a970e1c5 -->
@@ -33,1 +35,4 @@
// Without the unknown LLM part, as the sums count it.
val countedCostUsd get() = if (costKnown) totalCostUsd else jevCostUsd
val runKey get() = "$repo#$pr@${headSha ?: ""}@$timestamp"
Collaborator

[medium] Local dry runs reuse the CI run key (werkrevisor)

hint; Jev: real 0.36, severity 2.0 of 3

runKey is built from repo, pr, head_sha and timestamp, and the new local flag is not part of it. A dry run and a CI run of the same PR commit differ only in the timestamp, so a collision is unlikely, but insert or ignore would drop whichever record arrives second if the timestamps are equal. The risk is small. Adding local to the key would remove it.

**[medium] Local dry runs reuse the CI run key** (werkrevisor) hint; Jev: real 0.36, severity 2.0 of 3 `runKey` is built from repo, pr, head_sha and timestamp, and the new `local` flag is not part of it. A dry run and a CI run of the same PR commit differ only in the timestamp, so a collision is unlikely, but `insert or ignore` would drop whichever record arrives second if the timestamps are equal. The risk is small. Adding `local` to the key would remove it.
@@ -45,3 +50,3 @@
)
private val ADDED_COLUMNS = setOf("llm_input_tokens", "llm_output_tokens", "jev_input_tokens", "repo_private")
private val ADDED_COLUMNS = setOf("llm_input_tokens", "llm_output_tokens", "jev_input_tokens", "repo_private", "local")
Collaborator

[medium] Migration adds local as nullable integer without a default (werkrevisor)

hint; Jev: real 0.62, severity 2.0 of 3

Rows written before this PR get NULL in local. rs.getBoolean returns false for NULL, so this is safe today. However, ADDED_COLUMNS creates every column as integer with no default, so the schema does not state the meaning of old rows. Missing test: the migration test a database of an earlier version gets the token columns does not check that local reads as false for old rows.

**[medium] Migration adds `local` as nullable integer without a default** (werkrevisor) hint; Jev: real 0.62, severity 2.0 of 3 Rows written before this PR get NULL in `local`. `rs.getBoolean` returns false for NULL, so this is safe today. However, `ADDED_COLUMNS` creates every column as `integer` with no default, so the schema does not state the meaning of old rows. Missing test: the migration test `a database of an earlier version gets the token columns` does not check that `local` reads as false for old rows.
@@ -222,3 +225,3 @@
{},
// A private repository keeps its row, so that the rows add up to the total, but not its name.
g.hidden ? el("td", { class: "key hidden" }, "private repository") : el("td", { class: "key" }, name(g.key)),
PSEUDO_REPOS[g.kind] || g.hidden
Collaborator

[low] Truthiness precedence makes a hidden row depend on PSEUDO_REPOS (werkrevisor)

hint

PSEUDO_REPOS[g.kind] || g.hidden ? A : B works as intended, but the kind lookup is also applied to the verdict table, where g.kind is always repository. The code is correct, but the shared groupTable now carries repository-specific logic. This is a maintainability note only.

**[low] Truthiness precedence makes a hidden row depend on `PSEUDO_REPOS`** (werkrevisor) hint `PSEUDO_REPOS[g.kind] || g.hidden ? A : B` works as intended, but the `kind` lookup is also applied to the verdict table, where `g.kind` is always `repository`. The code is correct, but the shared `groupTable` now carries repository-specific logic. This is a maintainability note only.
mi approved these changes 2026-10-06 13:42:58 +02:00
ai-reviewer merged commit e95f148df8 into main 2026-10-06 13:42:59 +02:00
ai-reviewer deleted branch claude-code/pseudo-repositories 2026-10-06 13:42:59 +02:00
Sign in to join this conversation.
No Reviewers
No labels
3 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: mi/werkrevisor#28