Skip to content

fix: hide the non-chat aliases on the path the chat picker actually reads (#792) - #814

Merged
sakibsadmanshajib merged 5 commits into
mainfrom
fix/model-picker-access-control-792
Aug 17, 2026
Merged

sakibsadmanshajib merged 5 commits into
mainfrom
fix/model-picker-access-control-792

Conversation

@sakibsadmanshajib

@sakibsadmanshajib sakibsadmanshajib commented Aug 9, 2026 •

Copy link
Copy Markdown
Owner

Fixes #792. Supersedes the mechanism in #776, which is left in place but is not what fixes this.

The diagnosis, confirmed against the pinned image

#776 hid hive-embedding-default, hive-stt and hive-tts by writing Open WebUI's per-model access_control. It was reviewed, tested, merged and deployed, and it changed nothing. Two independent reasons, both read out of ghcr.io/open-webui/open-webui:v0.10.2@sha256:9fcea9c… rather than assumed:

  1. deploy/docker/docker-compose.yml:738 sets BYPASS_MODEL_ACCESS_CONTROL: "true". env.py:749 turns that into a module constant, and the picker's listing path, main.py:842 in the @app.get('/api/models') handler, calls get_filtered_models, which begins if (user.role == 'user' or ...) and not BYPASS_MODEL_ACCESS_CONTROL: and otherwise return models unchanged (utils/models.py:418-472). The flag switches the filter off for every role, so the access_control values fix: hide embedding/stt/tts aliases from the OWUI chat picker (#772) #776 writes are never read.
  2. Even with that flag off, get_filtered_models exempts administrators whenever BYPASS_ADMIN_ACCESS_CONTROL is set, and that defaults to true (config.py:2029), while the #457 tenant-role patch promotes every tenant owner to an Open WebUI administrator. Every human on the demo box is an admin.

So the mechanism could not fire on either count. Note that every test shipped with #776 still passed, because they all asserted that the correct values were written and none asserted that anything was read.

What actually depends on the bypass, measured

The tempting fix is to drop the flag. #792 flags document RAG and text-to-speech as the risk. That turned out to be wrong in both directions, and the measurement is what decided this PR's design.

An isolated harness (the pinned image, a pgvector container, and a stub gateway serving exactly the six catalog aliases and answering chat, embeddings, audio/speech and audio/transcriptions), with Open WebUI's environment mirroring the open-webui service block, run against two personas: an Open WebUI admin (what a tenant owner actually is) and an Open WebUI user.

admin persona member persona
Bypass on (as deployed) picker lists all 6, chat 200 picker lists all 6, chat 200
Bypass removed picker still lists all 6, chat 200 picker empty, chat 400 "Model not found"

Document RAG upload, ingest and query, TTS and STT all returned 200 for both personas in both configurations. None of them consults Open WebUI's model registry: routers/audio.py contains no access-control call at all, and the RAG embedder issues a direct HTTP request to RAG_OPENAI_API_BASE_URL.

So the bypass does not protect RAG or TTS. It protects chat for non-admin members, and removing it would not have hidden a single alias from the people who use the demo. Full runs in docs/proof/issue-792/probe-*.json.

The fix

Filter the listing the picker reads, and nothing else.

A build-time splice into main.py's /api/models handler, the same posture as this Dockerfile's other Open WebUI patches. It runs on the response: request.app.state.MODELS is untouched, so chat, RAG embeddings and text-to-speech still resolve every alias. GET /v1/models on the API origin is not touched at all, there are no Go changes in this PR, and that endpoint stays an OpenAI-contract surface that support-matrix.json marks supported and that direct API clients depend on.

Two things are deliberate because of how #776 failed:

  • The inserted call is unconditional, and assert_unconditional in the patch fails the build if a future edit puts it behind a flag, a role check or an access-control branch. There is no conditional available here that this deployment does not already disable.
  • The transform lives in a patch() function rather than inline, so the guard can run the real thing against a checked-in verbatim excerpt of the pinned image's own handler (pinned-main-excerpts.json). PR CI never builds this image, which is exactly why that excerpt is committed, following the precedent dump_bundle_excerpts.py already sets.

The hidden set is never hardcoded. It is HIVE_PICKER_HIDDEN_MODEL_IDS (compose owns it) unioned with whatever RAG_EMBEDDING_MODEL, AUDIO_TTS_MODEL and AUDIO_STT_MODEL name, so changing the admin-selected embedding alias does not need a second edit (D-001). Unset variables contribute nothing, so a deployment that sets none of them keeps upstream behaviour.

Rejected

  • Dropping BYPASS_MODEL_ACCESS_CONTROL. Measured above: breaks chat for every member, hides nothing from admins.
  • Anything access-control shaped, including repairing fix: hide embedding/stt/tts aliases from the OWUI chat picker (#772) #776. Inert by construction on this deployment.
  • Filtering /v1/models in edge-api by shim identity. owui_unwrap.go keeps hasShimAuthorization unexported precisely so no route branches on "is this the shim key", and handleModels documents that there is no exception for it. Both would have had to be reversed.
  • Filtering /v1/models for everyone. Violates the OpenAI contract; upstream OpenAI lists embedding and audio ids too.

The guard

scripts/test_owui_model_picker_filter.py, wired into make test-scripts, which the required repo-policy-lints check runs on every non-docs change.

It is built to fail the way #776 would have failed. It asserts the filter reaches the image and lands on the response path between upstream's own filtering and the return, rather than asserting a value was written, and it asserts the coupling directly: while compose sets the bypass, a picker filter that does not depend on access control must be present and must run in the image.

Red, against the pre-fix image with the bypass on, which is the deployed world:

OWUI chat model picker filter regression (1 failure(s)):
  run_live: the chat picker still lists ['hive-embedding-default', 'hive-stt', 'hive-tts'] (issue #792). The picker filter is not on the response path, or something is gating it.
exit=1

Green, patched image, bypass still on, same harness, same command:

live: gateway serves 6 models including all 3 non-chat aliases; picker lists 3 and none of them
OWUI chat model picker filter: 10 checks passed
exit=0

The static half that CI runs goes red the same way with the Dockerfile's RUN line neutered and compose untouched, naming both the missing invocation and the bypass coupling. Transcripts in docs/proof/issue-792/README.md.

Live proof

Both halves, captured against a running stack, in one signed-in session.

Picker before, signed in as the owner persona. All six, including the three that cannot serve a completion:

picker before, all six aliases

Picker after, same persona, same harness, patched image. Three chat aliases:

picker after, three chat aliases

The gateway's own list in that same session, post-fix, still carrying all six:

gateway list still returns six

And /api/models, the listing the picker reads, post-fix:

api models listing after the fix

Probe C confirms the rest of the surface is unaffected with the fix in place and the bypass left on: chat 200, RAG ingest completed, RAG query returning a hit, TTS 200 and STT 200, for both personas.

Test plan

  • make test-scripts green, including the new guard
  • New guard proved red against the pre-fix image and green against the patched one, same harness
  • New guard proved red statically with the Dockerfile RUN line neutered
  • Image builds; every patch assertion in Dockerfile.open-webui passes
  • Picker shows only the three chat aliases, admin and member personas
  • Gateway model list still returns all six in the same session
  • Chat, document RAG ingest and query, TTS and STT all still work post-fix
  • Confirmed on the demo box after deploy, which this PR does not perform

Notes for the reviewer

The Open WebUI AUDIO_* settings are wired in the harness even though docker-compose.yml does not set them today. #792 named text-to-speech as a risk, and a risk that is not configured cannot be measured. That harness wiring is not part of this diff.

#776's control-plane machinery is left untouched. It is inert on this deployment but harmless, and it becomes live if the bypass is ever turned off, which is a decision for whoever makes it. The guard makes that coupling explicit rather than silent.

Rebased onto main, 2026-08-17

This PR sat open since 2026-08-09. A lot landed on main in that window,
including Phase 20 provider-catalog waves and pricing corrections, so this
branch was merged forward (4e39de40) and re-verified against current code
rather than assumed still correct.

Checked, not assumed:

  • The pinned image digest is unchanged (ghcr.io/open-webui/open-webui:v0.10.2@sha256:9fcea9c…).
  • public.model_aliases has not grown a new non-chat alias and none of the
    three (hive-embedding-default, hive-stt, hive-tts) were renamed;
    confirmed against every migration that touches the table, most recently
    20260801_13_alias_price_unit.sql.
  • scripts/test_owui_model_picker_filter.py still passes statically (10/10)
    against the checked-in pinned-main-excerpts.json.
  • docker-compose.yml's HIVE_PICKER_HIDDEN_MODEL_IDS default and
    RAG_EMBEDDING_MODEL/OWUI_RAG_EMBEDDING_ALIAS wiring are unchanged and
    still name the same three aliases.

One cleanup from the merge itself: .wolf/buglog.jsonl's merge=union
driver kept this branch's own append after merging main forward. Branch
appends to that file are never allowed regardless of the merge driver
(.claude/rules/openwolf.md); dropped it back to main's content in a
separate commit and moved the entry to Buglog entry below.

Fresh A/B proof, same method as PR #909

The demo box still runs main, so nothing captured against it can show this
fix. Two Dockerfile.open-webui images, same pinned digest, differing only
in owui-patches/, run standalone against a stub gateway serving the real
six-alias catalog shape. Full method and logs:
docs/proof/pr-814-rebase-verification-2026-08-17/README.md.

Built from main (no patch) — all six aliases in the dropdown:

picker built from main, six aliases

Built from this branch — three chat aliases:

picker built from this branch, three aliases

DOM read backing each screenshot (which of the six known ids actually
rendered in the opened dropdown), not just the image:

main:   ["hive-auto","hive-default","hive-fast","hive-embedding-default","hive-stt","hive-tts"]
branch: ["hive-auto","hive-default","hive-fast"]

Is filtering the picker the right fix, or should these aliases not be in the chat-facing catalog at all?

Asked directly, and the honest answer has two parts, because a design pass
run in parallel on this same question reached a real finding that this PR's
own "Rejected" section above already anticipated and rejected once.

The finding, verified against current code and correct as stated:
public.model_aliases carries no modality/is_chat_model column,
apps/control-plane/internal/catalog/repository.go's alias-listing queries
(ListPublicAliases, the tenant-visibility query, GetAlias,
ListAllAliases) never join provider_capabilities, and
apps/edge-api/cmd/server/main.go's handleModels (~line 774) serializes
snapshot.Models verbatim. So yes: GET /v1/models on the API origin lists
hive-embedding-default, hive-stt and hive-tts with nothing marking them
as non-chat, for every caller, chat-scoped or not.

Where the conclusion drawn from that finding doesn't hold: the proposal
was to filter /v1/models itself so it "returns only chat-capable models
for a chat-scoped request." This PR's own Rejected section already
considered and rejected the unscoped version of that
("Filtering /v1/models for everyone. Violates the OpenAI contract; upstream
OpenAI lists embedding and audio ids too.") for a reason that's still true:
a real OpenAI /v1/models response is undifferentiated too, and a direct API
client that wants to call POST /v1/embeddings or POST /v1/audio/speech
with a Hive alias needs to discover it via GET /v1/models first, the same
way it would against upstream OpenAI. Stripping the three aliases from the
endpoint unconditionally would break that discovery path for every non-chat
SDK integrator to fix a problem that, for them, does not exist: nobody
calling /v1/embeddings is confused by seeing hive-embedding-default in
the model list.

So: keep #814's picker filter. Do not expand this PR to touch /v1/models.
The client-side fix stays the answer to the owner's actual complaint (Open
WebUI's chat picker specifically), and it is not "defense in depth" for a
server fix that doesn't exist — until something reconfigures Open WebUI to
consume a genuinely chat-scoped listing, this patch is the only thing making
the picker correct.

There is a real, narrower question worth designing separately: a
chat-scoped variant of the listing, for a caller that opts in to "only
models I can send a chat completion to" (which Open WebUI's picker could
then consume server-side instead of client-side). That needs its own
signaling mechanism (query param, header, or a distinct endpoint) so the
unparameterized GET /v1/models keeps its current, contract-correct shape.
No migration is needed to build it either way: the capability data already
exists twice over and is unused by the listing endpoint today —
apps/control-plane/internal/catalog/http.go's tested isNonChatModality
over capability_badges (currently wired only to the inert, bypassed #776
OWUI access_control sync), and provider_capabilities.supports_chat_completions
/ supports_embeddings / supports_tts / supports_stt, already joined
per-route in listRouteSnapshots for routing decisions but never surfaced to
handleModels. Filed as #931 rather than folded into this PR, since it's a
genuine design question (is there real demand for it beyond this one picker?)
and, if built, its own reviewed diff.

Buglog entry

Carried here per branch policy (never appended to .wolf/buglog.jsonl on a
feature branch). To be appended to main in a separate buglog-only PR once
this merges:

{"id":"bug-msmbcjgc-8012bd","timestamp":"2026-08-09T21:27:12.251Z","related_bugs":[],"occurrences":1,"last_seen":"2026-08-09T21:27:12.251Z","error_message":"Open WebUI chat model picker still listed hive-embedding-default, hive-stt and hive-tts after PR #776 merged and deployed (issue #792)","root_cause":"#776 hid them by writing Open WebUI per-model access_control, but deploy/docker/docker-compose.yml sets BYPASS_MODEL_ACCESS_CONTROL true, which makes main.py skip get_filtered_models for every role in the pinned v0.10.2 image. Even with that flag off, get_filtered_models exempts admins whenever BYPASS_ADMIN_ACCESS_CONTROL is set, and it defaults to true while this deployment promotes every tenant owner to an Open WebUI admin. The mechanism could never fire, and every test shipped with it asserted that values were written rather than read.","fix":"filter the /api/models response instead, via a build-time patch (deploy/docker/owui-patches/apply_model_picker_patch.py plus hive_model_picker.py). Unconditional, env-driven, applied after upstream own filtering and before the return, leaving request.app.state.MODELS untouched so chat, RAG embeddings and TTS still resolve every alias. Measured on a booted container: removing the bypass instead gives members an empty picker and HTTP 400 Model not found on chat, while leaving RAG and TTS unaffected, so the bypass protects chat and not the named risks. Guard: scripts/test_owui_model_picker_filter.py, with a --live mode that fails when the picker still lists the aliases.","tags":["open-webui","model-picker","access-control","inert-fix","issue-792","issue-776","docker-compose"]}

🤖 Generated with Claude Code

…icker actually reads (#792)

PR #776 hid `hive-embedding-default`, `hive-stt` and `hive-tts` by writing Open
WebUI's per-model `access_control`. It merged, deployed, and changed nothing.
`deploy/docker/docker-compose.yml` sets `BYPASS_MODEL_ACCESS_CONTROL: "true"`,
and in the pinned v0.10.2 image that makes `main.py` skip `get_filtered_models`
on `/api/models` for every role, so the values #776 writes are never read. Even
with that flag off, `get_filtered_models` exempts administrators whenever
`BYPASS_ADMIN_ACCESS_CONTROL` is set, and it defaults to true
(`config.py:2029`) while the tenant-role patch promotes every tenant owner to an
Open WebUI administrator. The mechanism could not fire on either count.

Measured on a booted v0.10.2 container rather than reasoned about, because
removing the bypass was the obvious alternative and it is the wrong one. With
the bypass off, an administrator still saw all six aliases and chatted fine,
while a member saw an empty picker and got HTTP 400 "Model not found" on every
chat request. Document RAG ingest and query, text-to-speech and speech-to-text
were unaffected for both personas, in both directions of the flag: none of them
consults Open WebUI's model registry. So the risks the issue named do not depend
on the bypass, what depends on it is chat for non-admin members, and turning it
off would not have hidden anything from the people who use the demo anyway.

The fix filters the `/api/models` response, which is the listing the picker
reads and the only thing that listing feeds. `request.app.state.MODELS` is
untouched, so every invocation path still resolves every alias, and
`GET /v1/models` on the API origin is not touched at all: no Go code changes
here, and that endpoint remains an OpenAI-contract surface direct API clients
depend on.

Mechanically this is a build-time splice, the same posture as this Dockerfile's
other Open WebUI patches, with two differences that exist because of how #776
failed. The inserted call is asserted to be unconditional, so no flag, role or
access-control branch can gate it; and the transform lives in a `patch()`
function so `scripts/test_owui_model_picker_filter.py` can run the real thing
against a checked-in verbatim excerpt of the pinned image's own handler. PR CI
never builds this image, which is why that excerpt is committed.

The hidden set comes from the environment, never from a hardcoded list: compose
owns `HIVE_PICKER_HIDDEN_MODEL_IDS`, and the module additionally hides whatever
`RAG_EMBEDDING_MODEL`, `AUDIO_TTS_MODEL` and `AUDIO_STT_MODEL` name, so changing
the admin-selected embedding alias does not require a second edit (D-001).

The guard is built to fail the way #776 would have failed. It asserts the filter
reaches the image and runs on the response, not that a value was written, and
its `--live` mode asserts both halves against a running stack: the gateway list
must still carry all three aliases while the picker's list carries none of them
and is not empty. Proof of red and green, the before and after screenshots, and
the full probe runs are in `docs/proof/issue-792/`.

Refs #776
@cursor

cursor Bot commented Aug 9, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@coderabbitai

coderabbitai Bot commented Aug 9, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

@sakibsadmanshajib, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 20 minutes

Limit details: You’ve used all 1 included review currently available under your plan.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 26c812bf-2edc-4906-b18e-e99ed21eb2fb

📥 Commits

Reviewing files that changed from the base of the PR and between 7b63d97 and fde760a.

⛔ Files ignored due to path filters (8)
  • docs/proof/issue-792/01-before-picker-owner.png is excluded by !**/*.png
  • docs/proof/issue-792/02-after-picker-owner.png is excluded by !**/*.png
  • docs/proof/issue-792/03-after-picker-listing-endpoint.png is excluded by !**/*.png
  • docs/proof/issue-792/04-after-gateway-list-unfiltered.png is excluded by !**/*.png
  • docs/proof/pr-814-rebase-verification-2026-08-17/picker-branch.log is excluded by !**/*.log
  • docs/proof/pr-814-rebase-verification-2026-08-17/picker-branch.png is excluded by !**/*.png
  • docs/proof/pr-814-rebase-verification-2026-08-17/picker-main.log is excluded by !**/*.log
  • docs/proof/pr-814-rebase-verification-2026-08-17/picker-main.png is excluded by !**/*.png
📒 Files selected for processing (13)
  • .env.example
  • Makefile
  • deploy/docker/Dockerfile.open-webui
  • deploy/docker/docker-compose.yml
  • deploy/docker/owui-patches/apply_model_picker_patch.py
  • deploy/docker/owui-patches/hive_model_picker.py
  • deploy/docker/owui-patches/pinned-main-excerpts.json
  • docs/proof/issue-792/README.md
  • docs/proof/issue-792/probe-a-before-fix.json
  • docs/proof/issue-792/probe-b-bypass-removed.json
  • docs/proof/issue-792/probe-c-after-fix.json
  • docs/proof/pr-814-rebase-verification-2026-08-17/README.md
  • scripts/test_owui_model_picker_filter.py

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Buglog entries never land on a feature branch (openwolf.md, D-025); the
merge=union driver kept the branch's own append after merging main, so
drop it explicitly. The entry itself is carried in the PR body under
Buglog entry.
Two Dockerfile.open-webui images (main vs this branch), same pinned
digest, differing only in owui-patches/, run standalone against a stub
gateway serving the real six-alias catalog shape. Confirms the fix
still applies after the Phase 20 catalog/routing changes that landed
on main since this PR opened: main lists all six aliases in the chat
picker, this branch lists only the three chat ones. Same method PR
#909 used for its user-menu proof.
@sakibsadmanshajib

Copy link
Copy Markdown
Owner Author

Rebase verification + server-side question, re-confirmed

Head after rebase: fde760a4. Checks all green (18/18, including Web E2E on
retry), zero unresolved review threads, mergeStateStatus: CLEAN.

The three locations, verified against this branch's current tree

  1. public.model_aliases (supabase/migrations/20260331_01_model_catalog.sql)
    has no modality/is_chat_model column. Only capability_badges jsonb.
  2. apps/control-plane/internal/catalog/repository.go's four alias-listing
    queries (ListPublicAliases, the tenant-visibility query, GetAlias,
    ListAllAliases, lines 67/115/217/334) select from model_aliases alone,
    no join. The one query in the file that does join provider_capabilities
    (listRouteSnapshots, line 444) builds route snapshots for routing
    decisions, not the alias list /v1/models serves.
  3. apps/edge-api/cmd/server/main.go's handleModels (line 774-777)
    serializes snapshot.Models verbatim into the /v1/models response, for
    both the JWT-session and API-key branches.

All three confirmed correct as stated.

Keep or drop the client-side filter: keep it

This PR's own "Rejected" section already considered and rejected the
unscoped version of a server-side fix ("Filtering /v1/models for
everyone. Violates the OpenAI contract; upstream OpenAI lists embedding and
audio ids too") — a real OpenAI /v1/models response is undifferentiated
the same way, and a direct API client calling POST /v1/embeddings or
POST /v1/audio/speech needs to discover the alias via GET /v1/models
first. Stripping the three aliases from that endpoint unconditionally would
break discovery for every non-chat integrator to fix a problem that, for
them, doesn't exist.

So: no server-side change lands in this PR. The Dockerfile.open-webui client
patch stays the only fix, not "defense in depth" for a server change that
doesn't exist. Full reasoning and the two-part answer (facts right,
conclusion needed correcting) are in the PR body's own "Is filtering the
picker the right fix" section, added this pass.

No migration needed if a chat-scoped variant is ever built

Filed as #931, not bundled here. The capability data already exists twice
over with no schema change required: capability_badges feeds a tested,
working isNonChatModality in apps/control-plane/internal/catalog/http.go
(currently wired only to the inert #776 OWUI access_control sync), and
provider_capabilities.supports_chat_completions/supports_embeddings/
supports_tts/supports_stt are already joined per-route in
listRouteSnapshots for routing, just never surfaced to handleModels.
Ordering, if it's picked up: (1) design the chat-scoped signaling mechanism,
its own reviewed diff, no migration; (2) only if a real is_chat_model
column is still wanted over deriving it, a migration, its own diff; (3)
retire this PR's client patch only once Open WebUI is reconfigured to
consume the new listing, not before.

Files touched by this pass (only)

.wolf/buglog.jsonl (one-line revert, dropping this branch's own append
per policy) and docs/proof/pr-814-rebase-verification-2026-08-17/ (new,
4 files). Nothing in the sidebar, user menu, or hive_ui_surfaces.py.

Visual proof, A/B against main, same method as PR #909

Two Dockerfile.open-webui images, same pinned digest
(ghcr.io/open-webui/open-webui:v0.10.2@sha256:9fcea9c…), differing only in
owui-patches/, run standalone (WEBUI_AUTH=false) against a stub gateway
serving the real six-alias catalog shape. Full method:
docs/proof/pr-814-rebase-verification-2026-08-17/README.md.

Built from main (unpatched) — all six aliases in the dropdown:

picker built from main, six aliases

Built from this branch — three chat aliases:

picker built from this branch, three aliases

DOM read backing each screenshot:

main:   ["hive-auto","hive-default","hive-fast","hive-embedding-default","hive-stt","hive-tts"]
branch: ["hive-auto","hive-default","hive-fast"]

@sakibsadmanshajib
sakibsadmanshajib merged commit 7ababeb into main Aug 17, 2026
18 checks passed
@github-actions
github-actions Bot deleted the fix/model-picker-access-control-792 branch August 17, 2026 09:23
sakibsadmanshajib added a commit that referenced this pull request Sep 2, 2026
## Summary

Reconciles the backlog created by the branch-append restriction in issue
#873: every fixed bug, error, failed test, or failed build must be
logged in `.wolf/buglog.jsonl`, but never appended directly on a feature
branch, since GitHub's server-side merge ignores the `merge=union`
driver and two branches that both appended land in hard conflict. The
route is to carry the entry in the fix PR's body and append it here
afterward, in a dedicated buglog-only PR.

This PR is that reconciliation, swept properly rather than trusting a
short known list:

- Searched all merged PRs whose body contains a "Buglog entry" heading
(287 PRs matched via GitHub code search).
- Extracted the JSON line following each heading (multiple headings per
PR body handled correctly, e.g. PR #814 and PR #1203 each carry two
matches, one a prose mention and one the real entry).
- Deduplicated against the 314 entries already on `main`, both by `id`
and by exact `error_message` text, plus deduplicated within this batch
itself.
- Result: **197 new entries from 167 source PRs**, spanning PR #787
through PR #1734.
- Validated every extracted line has the four required fields
(`error_message`, `root_cause`, `fix`, `tags`). All 297 raw extractions
had them; zero were rejected as incomplete.
- Five entries carried `tags` as a comma-separated string instead of an
array (inconsistent with the rest of the file's schema). Normalized to
an array by splitting on comma, content unchanged, nothing invented.
- The five false-positive "Buglog entry" mentions that were prose
references rather than real headings (PRs #1116, #1303 first match,
#1438 first match, #814 first match, #1203 first match) were correctly
skipped, either because no JSON followed or because the real entry was
found at a later heading in the same body.

## Diff scope

`.wolf/buglog.jsonl` only, 197 insertions, 0 deletions. No existing line
touched (verified byte-identical against the first 314 lines
pre-append).

## Test plan

- [x] Every one of the 511 resulting lines parses as valid single-line
JSON.
- [x] `git show --stat` on the pushed commit shows exactly one file
changed.
- [x] First 314 lines diffed identical to `origin/main`'s current file.
- [x] This is on the inert-path allowlist in `.github/workflows/ci.yml`,
so the six required checks should report green without running their
heavy steps.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Chat model picker still lists the embedding, STT and TTS aliases: #776's access_control mechanism is disabled by BYPASS_MODEL_ACCESS_CONTROL

1 participant