Repository navigation
feat: retitle chat settings and add a Usage tab - #1298
Conversation
…abricated resets)
Parity re-score scored settings at 0.30/9: the right pane was literally
titled "WebUI Settings" (stock Open WebUI branding) and there was no
consumption or credit surface anywhere in Settings.
Renames the General tab's "WebUI Settings" header to "Chat Preferences",
and adds a dedicated Usage tab clustered next to Account (mirroring the
Claude Desktop reference's General/Account/Usage grouping), showing
credit balance and today's usage.
Usage.svelte reuses vendor/open-webui/src/lib/hive/credits.ts end to end
(fetch, format, low/empty state) rather than re-deriving any of it, so
this tab and the composer credit banner can never disagree about what a
balance means. formatUsdFromCredits carries the same honesty invariant as
apps/web-console/lib/format/model-pricing.ts: a real balance, zero
included, always renders as a dollar figure, never as the bare integer a
prior defect once showed a customer ("9,789,478,244 remaining").
Deliberately does not replicate the reference's session/weekly quota bars
with reset timers: Hive bills prepaid credits with no reset window
(D-046, D-031), so a countdown here would be fabricated data on a screen
whose job is telling the truth about money.
Traced the 'tools' (Integrations, direct OpenAPI tool server + Open
Terminal registration) settings tab: it has no entry in the allSettings
array that drives the tab rail, so its button/content branches are
unreachable. Initially filed that as an open decision (issue #1258), then
corrected on the same issue after reading Dockerfile.open-webui's own
comment: the descriptor's absence from vendored source is the documented,
intentional fix for #771 (direct tool servers bypass Hive's gateway
metering, billing and sanitization; every tenant OWNER holds the OWUI
admin role per #748, so the feature-gate branch never actually gated
anyone), with Caddyfile.owui already blocking the server-side half (#770).
No open design question remains; #1258 is retitled to a low-priority
"delete the now-dead template branches" tidiness item.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Text log backing the screenshots posted to this PR via scripts/post-pr-visual-proof.sh, per D-042 and npm run lint:proof-tokens (which scans only docs/proof/). Documents the sign-in path used (a throwaway local signup, not the shared QA fixture), and the pre-existing environment blocker (dead Supabase Cloud project reference in the shared .env) that limited the Usage tab capture to its honest no-data fallback state rather than a populated balance. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
Warning Review limit reachedNext included review available in 33 minutes. View limit detailsLimit details: You’ve used the included review currently available. You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Review configuration: ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (11)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Visual proofGeneral tab retitled to 'Chat Preferences' (was literal 'WebUI Settings'); new Usage tab clustered next to Account, showing the honest no-data fallback since the local verification stack's shared .env points at a deleted Supabase project (issue #1297). |
Adversarial review (pipeline mode)CodeRabbit CLI: SKIPPED. Plain adversarial pass (my own re-read of the diff against the actual PR description,
No findings. I could not run the two agent-dispatched streams ( |
… scratch tree Repo policy lints (tenant + audit) failed CI: settings-usage-tab.test.ts reads General.svelte and Usage.svelte as text fixtures (same pattern as the existing settings-declutter guard), but scripts/test-owui-hive-frontend.sh only mirrors an explicit allowlist of component files into its scratch tree for speed (avoiding a full frontend npm install), and neither file was on that list. ENOENT on both, 7/208 tests failed. Verified locally by reproducing the script's own mirror step and running vitest against the resulting tree with the real node_modules (host npm network access in this sandbox is unreliable for the script's own docker invocation, confirmed separately as a pre-existing sandbox constraint, not a regression from this fix). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Independent review, stage 6. Verdict: NO MERGE.Read the pushed diff at The headlineI mutated the PR head and re-ran the repo's own gate. Three mutations at once:
Exit 0. Byte for byte the verification the PR body reports. A component that does not parse, with its two money numbers transposed and its tab dead, is indistinguishable from this PR under every check that runs before merge. Root cause is scope, not effort. FindingsBlocking:
Should fix before merge:
Worth fixing:
Checked and clearWorth recording, because these were the risks this surface carried going in and the PR handles them correctly.
Visual proofRequired, since this changes a live UI surface, and satisfied for only half the change. The General retitle is genuinely proven. The Usage tab capture shows "Usage isn't available on this deployment.", which The environment blocker (#1297, dead Supabase Cloud pointers) is real and does not prevent this. A Playwright Review streams
What would flip this to MERGEFindings 1, 2 and 3 are one change in practice: move The feature itself is the right feature, the reuse of |
Correction: the CodeRabbit stream did runMy review summary above marked CodeRabbit as SKIPPED after three rate-limited attempts. A fourth attempt, made a few minutes later, went through. Correcting the record rather than leaving a wrong stream status standing. CodeRabbit CLI: RAN, all six changed files reviewed, zero findings. Attempt history, for the next agent who hits this: attempt 1 failed on an invalid flag ( This does not move the verdict. Zero findings from a diff reviewer is the expected result for findings 1 through 3, which are not visible in the diff text at all: they are properties of which files the CI compile guard covers and of what the assertions fail to pin, both of which need the repo's gate to actually be run and mutated. Findings 4 through 8 it simply did not raise; the Antigravity stream independently raised 4 and 5, so they are not artefacts of a single reviewer. The verdict stands at NO MERGE on findings 1, 2 and 3. |
Independent review mutated this branch three ways at once, a Svelte parse error in the Usage component, the two money figures transposed, and the rail button click handler emptied, and the repo gate still reported 16 files, 208 tests, 13 of 13 components compiled, exit 0. Nothing in this repository could tell a working version of the component from a broken one. Root cause was scope. scripts/test-owui-hive-frontend.sh compiles lib/hive only, and the component had been added under lib/components, where the script treats copied files as text fixtures. The image build that would have caught the parse error runs after merge. The component now lives at lib/hive/SettingsUsage.svelte, where the compile guard already looks and where every other Hive authored component lives, and SettingsModal imports it the way Chat.svelte imports CreditsBanner. The gate grew a real render capability: it installs the vite svelte plugin at the lockfile pinned version and writes a vitest config, so a test can import a component and assert what it renders. Server side rendering, so no jsdom has to be added to the vendored lockfile and the same test runs identically in the image build's in place run. Mutation results after the change, each run through make test-owui-frontend: parse error in SettingsUsage.svelte RED, CompileError, exit 2 two money figures transposed RED, 3 failed assertions, exit 2 rail button click handler emptied RED, 1 failed assertion, exit 2 unmutated tree GREEN, 221 tests, 14 of 14 compiled Also fixed, from the same review: Failed refresh no longer wipes a good balance or advances the last updated stamp. That policy moved into credits.ts as refreshCreditSnapshot so it is executable in a test rather than only readable in a diff, with four cases covering it. Both figures are tenant scope, so both labels now say so. The schema has no per user allowance at all, see the deliberately TENANT balance note in apps/control-plane/internal/ledger/chat_balance.go, so the old bare "Used today" printed the whole organization's spend under a personal label. The Usage tab is hidden where the deployment has no credits surface. Enterprise deployments never wire the chat container's credits proxy and it fails closed with a 404; silent absence is that posture's documented behavior, and a tab permanently stuck on a not available sentence inverted it. The rename drops a string that was translated in bn-BD, so the new key and every new money label are added to en-US and translated in bn-BD, the first market. Remaining locales fall back to English, as every other untranslated key in this fork already does. General tab search keywords carry the new title as well as the old one.
…m it Code scanning flagged the single pass tag stripping regular expression in the new render helper as incomplete multi character sanitization. Nothing here sanitizes anything, the input is a string this same test just rendered, but the pattern was also unnecessary: the span holds a formatted currency string with no nested elements. Slicing between the span boundaries and comparing the result whole is stronger for this test's purpose. A tag or comment appearing inside the value is a real change in what the slot renders, and now fails the comparison instead of being quietly removed from it.
The first capture on this branch showed the tab in its no-data fallback, which is not the behaviour the PR claims. This one renders the populated state against a container built from this branch, with the single credits response fulfilled by Playwright rather than a database, and adds the enterprise case where the endpoint answers its documented 404 and the tab is absent from the rail entirely.
Visual proofUsage tab populated, the state the first capture missed. Organization credit balance 12.50 dollars and organization usage today 0.34 dollars, rendered by a container built from this branch with Playwright fulfilling the one credits response. Third image is the same build with that endpoint answering its documented 404, where the Usage entry is absent from the rail entirely. Log: docs/proof/chat-settings-usage-tab-2026-08-29/capture.log.md |
Second review round, from CodeRabbit CLI and Antigravity on the fixed diff. The settings modal stays mounted for the whole session and probed credits on every open, so two opens in quick succession could land out of order and an older answer could overwrite a newer one. One probe is in flight at a time now. The probe's answer is also kept rather than discarded. It travels to the Usage panel as its starting snapshot, so opening the tab shows the balance the modal already fetched, stamped with the time that fetch happened, instead of firing a second request for the same figure and rendering a spinner over data the modal is holding. The panel takes one `initial` snapshot prop in place of the previous balance and loading pair, and still fetches for itself when handed nothing. The probe goes through `refreshCreditSnapshot` for the same reason the panel does: a failed re-probe keeps the last known good balance and its original timestamp rather than blanking a figure already on screen. Also from Antigravity: the settings keywords test sliced between two `indexOf` results without checking the second. A missing end marker returns -1, and `slice(start, -1)` would have quietly widened the assertion to most of the file, letting any other tab's descriptor satisfy it. Both boundaries are asserted now. Its other finding, that the container payload lacks `set -e` and so swallows a vitest failure, is a false positive: `set -eu` is the first thing in that payload, and the three mutation runs below exit 2 on assertion failures alone. Mutation re-run after these changes, through `make test-owui-frontend`: parse error in SettingsUsage.svelte RED, CompileError at 100:56, exit 2 two money figures transposed RED, 3 failed assertions, exit 2 rail button click handler emptied RED, 1 failed assertion, exit 2 unmutated tree GREEN, 221 tests, 14 of 14 compiled
The panel now renders from the snapshot the settings modal already fetched rather than from its own mount request, so the capture was retaken against that head instead of reused from the previous one.
Visual proofRecaptured against 338b699, the head that answers the second review round, where the settings modal hands its probe balance to the panel. Usage tab populated: organization credit balance 12.50 dollars, organization usage today 0.34 dollars, top up link, last updated stamp. Second image is the retitled General tab with Usage in the rail. Third is the same build with the credits endpoint answering its documented 404, where the Usage entry is absent entirely. Log: docs/proof/chat-settings-usage-tab-2026-08-29/capture.log.md |
Review streams re-run on the fixed diffAll eight review threads plus the code scanning thread are answered and resolved. Streams re-run against the head that carries the fixes. CodeRabbit CLI, round one (
CodeRabbit CLI, round two (after those fixes): ran, one finding, minor, rebutted. It asks that the Antigravity ( Landed: the settings keywords test sliced between two False positive: it reported that the container payload in It found nothing to change in the money surface, the enterprise gating, the refresh policy, the localisation, or in whether the new tests can fail for the defects they name. Plain adversarial pass: covered by the independent review this round answers, plus the mutation runs, which are the part that actually established the original findings. |
…#1364) ## What this changes Repo-local agent tooling only. No product code, no workflows, no runtime behavior. Linked to no issue. ### 1. Four dead skills deleted `.claude/skills/debug-issue.md`, `explore-codebase.md`, `refactor-safely.md` and `review-changes.md` all instruct the agent to call a `code-review-graph` MCP server: `get_minimal_context`, `semantic_search_nodes`, `query_graph`, `get_flow`, `list_flows`, `detect_changes`, `get_impact_radius`, `get_affected_flows`, `get_architecture_overview`, `list_communities`, `find_large_functions`, `refactor_tool`, `apply_refactor_tool`. That server does not exist here. Verified in this worktree before deleting: - No `.mcp.json` at the repository root, and `find . -name .mcp.json` returns nothing anywhere in the tree. - No `graphify-out/` directory in the checkout. - Outside those four files, the string `code-review-graph` appears only in `.gitignore` and a historical note in `.wolf/cerebrum.md`. - The tool names themselves (`get_minimal_context`, `semantic_search_nodes`, `query_graph`, `get_impact_radius`) appear in those four files and nowhere else. An agent invoking one of these is told to call tools that are absent, and the likely failure is improvisation rather than a clean error. Their shared "at most 5 tool calls, at most 800 output tokens" budget is meaningless without the graph it was written for. **`review-changes` is deleted rather than rewritten**, and that was a judgment call worth stating. Rewriting it around `git diff` and `gh pr diff` leaves a file whose remaining content is a pointer to `prove-test-load-bearing.md` and `pr-ci-status.md`, both of which already carry front matter descriptions that route agents to themselves, plus a restatement of the review sequence that `.claude/rules/orchestrator.md` stage 6 already owns and that the global `adversarial-pr-review` skill defines in full. A third copy of that sequence is a third thing to keep in sync, and the two skills it would point at are already discoverable. The two genuinely repo-specific lessons that a rewritten `review-changes` would have carried are folded into `prove-test-load-bearing.md` instead, where the surrounding material is about exactly that. ### 2. Patterns added **Assert on the wire, not on the struct** (`prove-test-load-bearing.md`). For anything crossing an HTTP or SSE boundary, assert on serialized bytes: `httptest.ResponseRecorder.Body`, the SSE frame text, or a decoded `map[string]any`. A struct assertion is blind to a missing `json:"..."` tag, a custom `MarshalJSON`, an `omitempty` erasing a legitimate zero, and any downstream rewrite. Names this repository's three body-rewriting layers, since a struct assertion upstream of any of them cannot see what actually goes out: - `injectMemoryBlock`, `apps/edge-api/internal/chat/memory.go` - the Anthropic request translator, `apps/edge-api/internal/anthropic/translate_request.go` - `buildMessagesFromInput`, `apps/edge-api/internal/inference/responses.go` Worked example is issue #1329 / PR #1334: `StreamUsage` carried `omitempty` on every field, so `message_start` serialized as `"usage":{}` with no required member at all. The struct was correct; the serialization was not. `apps/edge-api/internal/anthropic/usage_wire_test.go` is the guard that can see it, and its own header states the same lesson. **The gate's scope is not the gate's name** (`prove-test-load-bearing.md`). A gate can be green because it never examined the thing. Two shapes, both from real merges: - A scope narrower than its name. `scripts/test-owui-hive-frontend.sh:175` runs `node owui-hive-svelte-compile-check.mjs lib/hive`, so coverage stops at that one directory. Three simultaneous mutations including a hard parse error left the suite reporting `16 passed / 208 passed / 13/13 components compiled`, exit 0 (PR #1298). Every count was true; none of them counted the broken file. - A gate nothing ever runs. `.claude/hooks/hooks.selfcheck.js` had real cases and no caller, which is how a secrets scanner blind to every MultiEdit survived (issues #1333, #1339). PR #1337 wired it into `ci.yml:705`. The check to actually run: name the file you changed, read the gate's invocation rather than its title, find the path or glob argument, and confirm your file is inside it. Negative control offered: break the file on purpose and rerun the gate. **A CONFLICTING PR runs no CI at all while looking green** (`pr-ci-status.md`, new cause 0, ahead of the existing three because it invalidates the evidence they are diagnosed from). Read `mergeable` before `mergeStateStatus`. `mergeable: CONFLICTING` means GitHub cannot build `refs/pull/N/merge`, so no `pull_request` workflow run is created at all, so `statusCheckRollup` is empty or stale and the page reads as "no problems found" rather than "not evaluated". Observed on PR #1336: while CONFLICTING it showed only CodeQL, GitGuardian and CodeRabbit, which scans as green at a glance; the full suite ran only after a rebase. Notes `.wolf/buglog.jsonl` as the recurring cause on this repo, since GitHub's server-side merge ignores `merge=union` (issue #873). The waiting-for-CI section gains one line: an empty `statusCheckRollup` is ambiguous between "not started" and "cannot start", so read `mergeable` first. **`mergeStateStatus: UNKNOWN` means retry, not fail** (`pr-ci-status.md`, new section ahead of the BLOCKED material). UNKNOWN means GitHub has not finished computing the merge commit, and it appears right after a push, a base update, or a force-push. Poll again after a few seconds. Treating it as failure produced two false NOT-MERGED reports in one session, on PRs that had in fact merged. ### 3. Two corrections - `memory-tools.md` listed claude-mem as a live option with an `mcp__plugin_claude-mem_mcp-search__*` detection hint and a `mem-search` instruction. claude-mem was retired 2026-06-12 and survives only as a read-only sqlite archive at `~/.claude-mem/claude-mem.db`. The row now says so and tells the agent not to look for those tools. `memory-layers.md` line 71 carried the same stale `mem-search` pointer and is corrected the same way. - `worktree-compose-stack.md` gains one paragraph: `scripts/set-compose-project-name.sh:103-107` writes `deploy/docker/.env` unconditionally but the repository-root `.env` only if that file already exists, so the script has to be re-run with `--check` after an `.env` is created or copied, not only once at worktree creation. A worktree namespaced before its `.env` was copied in carries the namespace on one file and the default `hive` project name on the other, which is a container collision waiting to happen. ### 4. New skill: `owui-fork-edits.md` Nothing in `.claude/skills/` encoded the Open WebUI patch discipline, which is expensive to rediscover. Covers: - The chat image builds only the frontend from `vendor/open-webui` and replaces `/app/build`; the backend comes from a pinned upstream image, so a backend edit under the vendored tree is inert and produces no error. - A version assertion in the final stage fails the build when the vendored tree and the pinned backend disagree. - Backend changes go through `deploy/docker/owui-patches/`, and every patch asserts its own effect: an anchor that does not match exactly once prints what it expected and exits 1, and Python splices are `ast.parse`d before writing. - `Caddyfile.owui` is a third layer that can 404 a route independently of both others. - `dump_bundle_excerpts.py` plus `pinned-bundle-excerpts.json` is how the literal bundle assertions stay honest, since PR CI never builds the image. It also retires one stale claim that several patch comments still assert in their justifying prose: "every tenant OWNER holds the Open WebUI admin role" is no longer true. `owui-patches/tenant_role_from_db.py` lines 17 to 30 revoked that mapping, and OWUI `admin` now requires an ACTIVE `owner` row in `public.account_memberships` on an account with `is_platform_admin = true`. A tenant OWNER is an ordinary OWUI `user`. The patches remain correct defence; only the prose is stale. ### 5. `CLAUDE.md` The paragraph enumerating project-level skills is replaced with a pointer to the directory. That list had gone stale in both directions: it named four skills that had been dead for months, and omitted six that existed (`memory-layers`, `pr-ci-status`, `pr-visual-proof`, `prove-test-load-bearing`, `verify-deploy-happened`, `worktree-compose-stack`). ## Verification - Absence of the MCP server confirmed by direct search in this worktree before deleting anything, as listed above. - Every factual claim added was read out of the file it cites: `scripts/set-compose-project-name.sh`, `deploy/docker/owui-patches/tenant_role_from_db.py`, `dump_bundle_excerpts.py`, `apply_credits_patch.py`, `deploy/docker/Dockerfile.open-webui`, `deploy/docker/Caddyfile.owui`, `apps/edge-api/internal/anthropic/types.go`, `usage_wire_test.go`, `scripts/owui-hive-svelte-compile-check.mjs`, `scripts/test-owui-hive-frontend.sh`, `.github/workflows/ci.yml`. - `node .claude/hooks/hooks.selfcheck.js`: 61/61 passed. - Every `.wolf/decisions.md` id cited (D-036, D-040, D-044, D-052) exists and is live; none of the revoked or retired entries are cited. ## Test plan - [ ] CI green. `.claude/*` is on the inert-path allowlist in `ci.yml`, so the required checks report green without their heavy steps; `CLAUDE.md` is not, so the full suite runs on that file. - [ ] `node .claude/hooks/hooks.selfcheck.js` still passes. - [ ] No product code, workflow, or runtime behavior touched. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01WyEwUxZCArdn1ZUDkTvuQ1 --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
## Summary This is the batched buglog follow-up for the pull requests merged to `main` on 2026-08-29. Its diff is `.wolf/buglog.jsonl` and nothing else. Per `.claude/rules/openwolf.md`, every fixed bug, error, failed test or failed build must be logged, but the line may never be appended on a fix branch. `merge=union` in `.gitattributes` resolves concurrent appends locally and is ignored by GitHub's server side merge, so two branches that both appended land in hard conflict there. An unmergeable pull request gets no `refs/pull/N/merge`, no `pull_request` run and therefore zero checks, and the required status gate then blocks the merge for a reason the page never states (issue #873). Each fix accordingly carried its entry in its own pull request body, and this pull request copies them onto `main` in one batch, which the protocol explicitly prefers over one pull request per entry. ## Scope examined Fifty nine pull requests merged to `main` on 2026-08-29. Forty eight of them carried at least one entry, for eighty two entries in total. Thirty two of those were already on `main` and are skipped, leaving fifty appended here from thirty four pull requests. The largest block of skips comes from #1342, the equivalent batch for the 2026-08-28 merges, which merged earlier the same day and already landed thirty six entries covering #1257, #1268, #1276, #1277, #1287, #1292, #1293, #1294, #1296, #1301, #1303, #1305, #1313, #1335 and #1337. ## What landed Fifty entries appended, one JSON object per line, append only. The 232 pre-existing lines are byte identical to `origin/main` (verified by hashing the first 232 lines of the result against the base file). Every line in the resulting file parses as JSON and carries `error_message`, `root_cause`, `fix` and `tags`. | Source | Entries | |---|---| | #1083 | 2 | | #1277 | 1 | | #1278 | 1 | | #1298 | 1 | | #1334 | 1 | | #1336 | 3 | | #1343 | 1 | | #1346 | 1 | | #1351 | 1 | | #1365 | 2 | | #1368 | 1 | | #1369 | 1 | | #1371 | 3 | | #1375 | 3 | | #1376 | 1 | | #1378 | 1 | | #1379 | 2 | | #1388 | 5 | | #1389 | 3 | | #1390 | 2 | | #1393 | 1 | | #1394 | 1 | | #1410 | 1 | | #1417 | 1 | | #1421 | 1 | | #1423 | 1 | | #1424 | 1 | | #1426 | 1 | | #1429 | 1 | | #1431 | 1 | | #1433 | 1 | | #1434 | 1 | | #1436 | 1 | | #1439 | 1 | Entries are copied verbatim from their source pull request bodies. Nothing was rewritten, no field was invented, and no field was added. No JSON needed repair: all eighty two extracted entries parsed on the first attempt and all four required fields were present on every one. ## Merged pull requests that carried no entry Eleven of the fifty nine. Recorded here because the gap is itself the useful signal. | Pull request | Title | Assessment | |---|---|---| | #1013 | chore(deps): bump the go-minor-patch group across 1 directory with 4 updates | Dependabot bump, no defect fixed, no entry expected | | #1015 | chore(deps): bump the go-minor-patch group across 1 directory with 6 updates | Dependabot bump, no entry expected | | #1016 | chore(deps): bump golang from 1.26-alpine to 1.27-alpine in /deploy/docker | Dependabot bump, no entry expected | | #1218 | chore(deps): bump postcss from 8.5.19 to 8.5.26 in /apps/desktop | Dependabot bump, no entry expected | | #1219 | chore(deps): bump golang.org/x/crypto from 0.41.0 to 0.52.0 in /apps/control-plane | Dependabot bump, no entry expected | | #1342 | chore: batch buglog entries for the 2026-08-28 merges | The previous batch pull request itself, correctly carries no entry of its own | | #1364 | chore: remove four dead skills and record the patterns that cost time | Protocol gap. The body records patterns that cost time, which is the shape of a buglog entry, but none was written as one | | #1383 | test: retire stale expected-failure markers, restore the ones that are true (#1381, #1382, #1324) | Protocol gap. Stale `it.fails` markers reading as red is a real defect that was fixed here and should have carried an entry | | #1384 | docs: correct D-047, hive-auto reverted to variable pricing (D-059) | Decision ledger correction, arguably a documentation defect, no entry written | | #1387 | chore(deps): bump next from 15.5.23 to 16.3.3 in /apps/agent-console | Dependabot bump, no entry expected | | #1398 | docs: rescue the 2026-08-25 parity captures and add the 2026-08-29 QA matrix evidence | Documentation and evidence rescue, no entry written | Six of the eleven are Dependabot bumps and one is the previous batch, so the genuine protocol gaps are #1364, #1383, #1384 and #1398. Of those, #1383 is the one worth a follow-up: it fixed a real defect class (a stale expected-failure marker reads as a red "Expect test to fail" and gets dismissed as pre-existing) and left no record. ## Entries skipped as already present Thirty two. Thirty of them matched an entry already on `main` on `error_message`, `id` or `fix`. Two more from #1278 are semantic duplicates that an exact match would have missed, and were skipped after reading the landed entries they duplicate: - #1278's `streaming content_block_start omits text field` entry is covered by the consolidated `bug-2026-08-28-anthropic-sdk-wire-conformance` entry landed from #1296, whose root cause names the same `omitempty` on `StreamContentBlock.Text`. - #1278's `GET /v1/models leaked an upstream provider name` entry is covered by `BUG-1284`, landed from #1300, which names the same `public.model_aliases.summary` publication path. #1278's third entry, on `top_k` forwarding producing a 400, is not covered anywhere on `main` and is appended here. #1342 recorded #1278 as fully "merged into #1296", which was accurate for two of its three entries. ## Note on entry quality One appended entry is thin: #1277's parity re-score record carries `error_message` of `n/a` and a root cause of "console had no privacy/data-policy surface at all". It is a parity gap record rather than a defect record. It is included exactly as written rather than embellished, per the protocol's preference for the author's own words. ## Test plan - [x] Branch cut fresh from `origin/main`, diff is `.wolf/buglog.jsonl` and nothing else - [x] First 232 lines byte identical to the base file (md5 match) - [x] All 282 resulting lines parse as JSON and carry `error_message`, `root_cause`, `fix` and `tags` - [x] No `.wolf/` telemetry (`anatomy.md`, `memory.md`, `token-ledger.json`, `hooks/_session.json`, `buglog.json`) in the commit - [ ] The six required checks report green via the inert path allowlist in `.github/workflows/ci.yml` --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>








Summary
A parity re-score of Hive's chat surface against Claude Desktop scored settings at 0.30 credit (criterion weight 9). Two concrete findings: the General tab's section header was the literal upstream string "WebUI Settings" (stock Open WebUI branding), and there was no consumption/credit surface anywhere in Settings.
vendor/open-webui/src/lib/hive/credits.ts, itself a faithful port ofapps/web-console/lib/format/model-pricing.ts). A real balance, zero included, always renders as a dollar figure, never as the bare integer a prior defect once showed a customer directly ("9,789,478,244 remaining")..wolf/decisions.md), so a countdown here would be fabricated data on a screen whose whole job is telling the truth about money.Scope discipline
Did not touch
apps/web-console(parallel work in flight there). Did not do a full audit/removal pass over every remaining stock-OWUI toggle inInterface.svelte/Audio.svelte/DataControls.svelte(traced enough to confirm these are functional, backend-agnostic UI preferences, consistent with the prior P0 settings-declutter wave already having removed the genuinely nonfunctional items).A finding along the way, investigated and corrected in place
Traced the
tools(Integrations: direct OpenAPI tool server + Open Terminal registration) settings tab: it has no entry inSettingsModal.svelte'sallSettingsarray, so its rail button and content-pane branches are unreachable. Filed that as issue #1258 with an initial framing that treated it as an open decision (restore vs. delete) — then corrected it on the same issue after readingDockerfile.open-webui's own comment: the descriptor's absence from vendored source is the documented, intentional fix for issue #771 (direct tool servers bypass Hive's gateway metering, billing and sanitization; every tenant OWNER holds the OWUI admin role per #748, so the feature-gate branch never actually gated anyone), withCaddyfile.owuialready blocking the server-side half (#770). No open design question remains; #1258 is now a low-priority "delete the dead template branches" tidiness item.Review round two, and why the first green was not evidence
An independent review mutated this branch three ways at once, a Svelte parse error in the Usage component, the two money figures transposed, and the rail button click handler emptied, and the repo gate still reported 16 files, 208 tests, 13 of 13 components compiled, exit 0. Nothing in this repository could tell a working version of the component from a broken one, because
scripts/test-owui-hive-frontend.shcompileslib/hiveonly and the component had been added underlib/components, where the script treats copied files as text fixtures.What changed:
vendor/open-webui/src/lib/hive/SettingsUsage.svelte, where the compile guard already looks and where every other Hive authored component lives.svelte/server, so no jsdom has to be added to the vendored lockfile and the identical test runs in the image build's in place run.credits.tsasrefreshCreditSnapshot, executable in a test rather than only readable in a diff.Organization credit balanceandOrganization usage today. The figures are tenant scope, per the deliberately TENANT balance note inapps/control-plane/internal/ledger/chat_balance.go, and a bare "Used today" printed the whole organization's spend under a personal label.deploy/docker/owui-patches/hive_credits.pydocuments. The modal's availability probe hands its balance straight to the panel, so the tab does not fetch the same figure twice.en-USand translated inbn-BD, the first market, with two tests holding it. General tab search keywords carry the new title as well as the old one.Verification
Mutation results, each run through
make test-owui-frontendon the current head:{$i18n.t('Usage'}in the componentCompileError: SettingsUsage.svelte:100:56 Unexpected token, exit 2The component count moving from 13 to 14 is the direct evidence that this file is now inside the compile set.
npm run test:frontend -- --runagainst the vendorednode_modulesreported 16 files and 221 tests passed, so the render assertions work in both the scratch tree and the tree the deploy builds from.deploy/docker/Dockerfile.open-webui, container run locally, and the populated Usage tab captured:Organization credit balance $12.50,Organization usage today $0.34, top up link, last updated stamp. The one credits response is fulfilled by Playwright, so no database is needed; issue shared .env's SUPABASE_URL/SUPABASE_DB_URL point at a deleted Supabase Cloud project, blocking every local agent stack #1297 does not block this after all. A third capture shows the same build with that endpoint answering its documented 404 and the Usage entry absent from the rail.docs/proof/chat-settings-usage-tab-2026-08-29/capture.log.md.gemini-3.1-pro-highran and returned two, one valid and fixed (an unboundedslicein the keywords test), one a false positive (set -euis already the first thing in the container payload, which the mutation runs above demonstrate empirically).Buglog entry
To be appended to
.wolf/buglog.jsonlonmainin a separate buglog-only pull request once this merges.{"date":"2026-08-29","title":"Pre-merge frontend gate compiled lib/hive only, so a Hive component added under lib/components was compiled and rendered by nothing","error_message":"make test-owui-frontend reported 16 files, 208 tests, 13/13 components compiled, exit 0 on a tree carrying a Svelte parse error, two transposed money figures and an inert settings tab","root_cause":"scripts/test-owui-hive-frontend.sh copies upstream components into its scratch tree as text fixtures and runs the svelte compile pass over lib/hive only, so a Hive authored component placed under lib/components/chat/Settings was read as text and never compiled, and no test rendered it; the image build that would have caught the parse error runs after merge in deploy-demo-box.yml","fix":"moved the component to vendor/open-webui/src/lib/hive/SettingsUsage.svelte where the compile guard already looks, taught the gate to install the lockfile pinned vite svelte plugin and write a vitest config so tests can import and server side render components, and re-ran the three mutations to confirm each one turns the suite red","tags":["ci","test-gate","open-webui","svelte","frontend","money-surface"]}Test plan
make test-owui-frontendon the unmutated tree, 221 tests, 14 of 14 components compilednpm run test:frontend -- --runin place, inside the image build, 221 tests🤖 Generated with Claude Code