Files
LocalAI/scripts/addons/suites.json
T
mudler-agentandEttore Di Giacinto 4899d28e8a feat(chats): server-side chats with steering, sub-agents and compaction (#12918)
* Find the Sandbox guest image in the executable, not its build info

The Sandbox smoke checked that the packaged executable carries the
guest image by looking for -X main.guestImage in go version -m. The
package is built with -trimpath, and with -trimpath Go leaves -ldflags
out of the build info, so the check failed on every gvisor run,
although the image was linked in.

Look for the reference in the executable instead: the value of
SANDBOX_GUEST_IMAGE when it is set, any digest reference otherwise.
package.sh had the same check for an executable built elsewhere; it
now looks for its own reference the same way.

Assisted-by: Claude:claude-opus-5-5

* Answer a network card the limit refuses with one precise reason

A card that waited while the administrator's limit went down was
refused on the first click with 400, and every later click was a bare
409, so a stale card looked like a conflict loop. A refused card now
answers 400 egress_above_ceiling every time, the same answer sent twice
is one answer (204), and another answer to an answered card is 409
already_answered. The chat view marks a card the limit cannot admit
with above_ceiling.

When the limit is off, or below the chat's preset, the note of the turn
and the block line of the proxy now say that the server's setting
blocks the network and no approval changes it, so the model reports it
instead of waiting or retrying.

Assisted-by: Claude:claude-sonnet-5-5

* Explain a blocked Sandbox network instead of offering dead buttons

A card the limit cannot admit shows why network access is off or
limited, and who can change it, with a link to Settings > Tools >
Sandbox network for administrators. The buttons of a card disable while
an answer is sent, and a failed answer reads the card again. The
Network row says why its choices are capped. Settings opens a group
from ?group=. Strings are translated in all nine locales and the chat
and add-on docs describe the new behaviour.

Assisted-by: Claude:claude-sonnet-5-5

* Add an always-allowed hosts list to the Sandbox network

The extra registries setting only widens the package registries, so a
one-off host needs the approval card in every chat. The new admin
setting chats_egress_allowed_hosts lists exact hosts (optionally
host:port to pin a port) that a chat reaches whenever its effective
preset is registries or all.

The list sits in the same decision as the presets: the ceiling still
caps it, the ports setting still applies, and a private, loopback,
link-local or metadata address still needs the private switch and an
administrator's rule or answer. Each use is audited with the reason
allowed_host. Hosts are validated like the extra registries (lower
case, punycode, no scheme, path or pattern, at most 64) and an IP
literal is refused unless the private switch is on.

get_chat_egress and the chat egress view return the list; no MCP tool
writes it, as for the extra registries.

Assisted-by: Claude:claude-sonnet-5-5

* Let users delete from the Trash for good

A delete only set a tombstone, so the Trash grew without end and
nothing could free the space of a deleted file.

The workspace stores gain a Purger: it erases the deleted nodes of
some change sets, or of a whole folder, with their journal rows, the
change sets that nothing is left in, and the blobs that no row refers
to. Both stores implement it and pass the same contract specs. A blob
is removed after a grace period, and only if it is still unused then,
so an upload of the same bytes in flight keeps them.

DELETE /api/chats/files/trash empties the user's Trash and
DELETE /api/chats/files/trash/{rev} deletes one entry. Both are scoped
to the caller's home. The Trash listing now gives files, folders and
bytes per entry and for the whole Trash. The file tools of a chat
cannot reach any of this.

Assisted-by: Claude:claude-sonnet-5-5

* Add Empty Trash and Delete permanently to the Files page

The Trash tab shows what it holds, with an Empty Trash button that is
off while the Trash is empty and a Delete permanently button on each
item. Both ask in the page first and say how many files and folders and
how much space they remove. Texts are translated in all nine locales.

Assisted-by: Claude:claude-sonnet-5-5

* Fall back to Brave Search and Bing when DuckDuckGo asks for a captcha

DuckDuckGo answers some servers with HTTP 202 and a bot check (the
"anomaly" page) instead of results. The parser read that page as "no
results it could read", so web_search failed for every query.

The keyless search is now a chain: DuckDuckGo, then the result page of
Brave Search, then the result page of Bing. Each page has its own
tolerant parser (title, URL, snippet; Bing's /ck/a links and DDG's uddg
links are unwrapped) with saved fixtures.

A bot check is a typed error (ErrChallenged), and a 403 or 429 is
ErrBlocked. Both wrap ErrProvider. A Fallback with a cool-down skips a
challenged or blocked provider for a few minutes, so each search does
not wait for it first; when every provider is cooling down, all are
asked again. Fallback.SearchAttempts and TestEach report what each
provider did (ok, no_results, challenged, blocked, timeout, error,
skipped).

The error a model reads now lists what was tried and what each provider
did, then where an administrator fixes it.

safehttp keeps the status code of an answer (Response.StatusCode) and
of a refusal (StatusError, still ErrStatus for errors.Is).

Assisted-by: Claude:claude-opus-5-5

* Use the keyless search chain in the chats and test each provider

The built-in web_search now searches with DuckDuckGo, Brave Search and
Bing in turn when no SearXNG instance is set. A new runtime setting,
chats_web_search_providers, sets the order (searxng, duckduckgo,
brave_html, bing_html) and leaves a provider out. Empty keeps the old
choice: SearXNG alone when an instance is set, so its queries do not
reach the public engines unless the administrator lists them.

POST /api/chats/admin/web/test asks every provider of the order and
returns what each did in "providers" (ok, no_results, challenged,
blocked, timeout or error, with the reason), next to the first answer.
Settings > Tools has a Test search on the web_search row that shows it,
and the provider list is checked on the page and by the server.

The cool-down of a challenged provider is kept per frontend, like the
cache and the limits; web.md says why.

Docs: web.md (providers, chain, bot checks, privacy, how to fix it with
SearXNG or the Web add-on) and runtime-settings.md. Strings in the
nine locales. Swagger regenerated.

Assisted-by: Claude:claude-opus-5-5

* Try the mirror library alone in the reinstall recovery spec

The spec adds a second library with the same URL and expects an
install from it to keep the retained data apart. Since two enabled
libraries that list one add-on are a conflict, the reinstall from the
original library then failed with library_conflict, and the install
from the mirror failed for that reason instead of the trusted identity.

Switch the original library off while the mirror is tried, check that
the mirror is refused for its identity and not for a conflict, then
switch the mirror off and the original on for the reinstall.

Assisted-by: Claude:claude-opus-5-5

* Pause a chat turn at the step limit and offer Continue

A chat turn ran at most 10 rounds of tool calls, the default of the
harness, because nothing set a limit. A multi-step task (read some
files, run commands, write a result) stopped half way, and the person
saw an answer that looked final.

The limit is now the runtime setting chats_max_iterations (1 to 500,
default 40, Settings > Tools); a model's agent.max_iterations still
wins. When the tool loop reaches it, the harness sends a paused event
with the limit, and the turn ends with last_turn "paused". A paused
turn counts as finished: waiting messages start the next turn and a
sub-agent reports back. The status line says "Paused, after 40 steps"
and has a Continue button, which sends a message that asks the model
to go on.

A claim that found no waiting message released the chat as "done",
which hid a pause. It now keeps the status the chat had.

Assisted-by: Claude:claude-opus-5-5

* Edit the always-allowed Sandbox hosts in Settings > Tools

Add a list editor for chats_egress_allowed_hosts next to the extra
package registries: the hosts are tags with a remove button, an input
adds one on Enter, comma or Add (a pasted list adds them all), and the
reason an entry is refused shows under the input, with the count out
of 64. The same checks stop Apply on a bad entry, and the server still
has the last word.

The chat's Network panel lists the hosts read only and the row says
how many an administrator always allows while the chat's network is on.
The help text of both settings now says how they differ. Strings are
translated in all nine locales.

Assisted-by: Claude:claude-sonnet-5-5

* Document the always-allowed Sandbox hosts

Describe chats_egress_allowed_hosts in the runtime settings page, the
network section of the add-ons page (including the allowed_host audit
reason and how the list differs from extra registries) and the chats
page.

Assisted-by: Claude:claude-sonnet-5-5

* Let a chat edit, pause and delete the person's triggers

A chat could propose a trigger and list them, but not change one: the
Triggers page and the API could. list_triggers now gives each trigger a
stable ref (not its id) and shows the prompt of one trigger only when
asked. update_trigger and delete_trigger store a change record in the
trigger table: an edit or a delete waits for Apply or Delete on a card,
a pause or a resume applies at once with a receipt. An applied change
can be undone for a day; a delete restores the trigger with its id.

Change records are rows in the database, so every frontend shows and
answers the same card. The new routes under /api/chats/triggers/changes
serve the card and are gated by the triggers feature.

Assisted-by: Claude:claude-opus-5-5

* Show the trigger changes a chat asks for as cards

An edit lists each changed field before and after with Apply and
Dismiss, a delete shows the trigger and its last run with Delete and
Keep, and an applied change is a receipt with Undo. The cards sit below
the message text like the proposal card, and read their state from the
server so a reload shows the same answer.

Assisted-by: Claude:claude-opus-5-5

* Add a Test search button to the web tools settings

POST /api/chats/admin/web/test existed, but no page called it and the
docs showed only curl. The web_search row of Settings > Tools now has
a Test search button. It runs one search with the applied settings and
shows the provider with its first results, or the error a chat would
read.

Assisted-by: Claude:claude-opus-5-5

* Describe undo per tool call in the chats docs

The docs said the checkpoint line of a turn carries the change set of
the turn. A turn checkpoint is taken only by a chat with a VM sandbox,
which the service never sets up, so that rev is always 0. What ships
is one change set per file tool call, with a files_change card on its
tool line. The docs now say so and how to undo a whole turn.

Grouping a turn's changes into one change set in the file store is
left for later: it touches the file store's revisions and the undo of
shared folders.

Assisted-by: Claude:claude-opus-5-5

* Mount the skill folders read-only for the built-in bash

The built-in pdf skill ships scripts, but the commands saw only the
home and the shared folders, so the model could read the scripts and
not run them. The built-in bash now mounts the three skill layers
read-only, at the names the file tools already use: shared-skills,
shared-builtin-skills and shared-addon-skills. A shared folder named
skills moves to "shared-skills 2", so the two never collide.

A read-only mount with subfolders made every command report its
folders as changes the mount refused, because the host backend lists
every folder of its work tree. A folder alone is no change: both
stores now refuse only files, whiteouts and opaque folders there.

The Sandbox add-on mounts only the home; the docs say to copy a
script there first.

Assisted-by: Claude:claude-opus-5-5

* Find the add-on that runs commands by what it shadows

The chats knew the add-on that runs commands from a per-process cache,
filled with the Sandbox's own tool name the first time a chat listed
its tools. Another add-on that replaces bash did not count, so skills
that need commands showed as unavailable. The admin network view read
the same cache: after a restart it said no Sandbox serves until
someone chatted, each frontend of a cluster could answer differently,
and a removed add-on stayed listed.

The tool that runs commands is now the one that shadows bash, as the
spec asks. sandboxRunTool and the cache are gone. The stand-in of an
add-on that cannot work carries the built-in tools it replaces, and
the admin view asks the add-on host which add-on serves bash now: the
pinned one or the oldest running install, and none when the pinned one
is stopped.

Assisted-by: Claude:claude-opus-5-5

* Show international host names in punycode in the network checks

The card-spoofing defence of the sandbox network asks for host names
in their ASCII form, but CheckHost passed Unicode names through. A
look-alike name reached the consent card as text that reads like the
real site.

CheckHost now converts an international name with the IDNA lookup
profile and refuses one with no valid ASCII form. The conversion runs
before the address checks, so full-width digits that spell a loopback
address are refused as loopback.

Assisted-by: Claude:claude-opus-5-5

* Keep the seeded Studio and Talk pins until the add-ons are installed

The upgrade pins Studio and Talk for existing accounts, but both are
add-ons that an administrator installs later. The sweep marked a pin
whose add-on is not installed as missing and deleted it after 30
days, so an administrator who installed Studio late found the seeded
pins gone.

The sweep now records the first time a seeded add-on is present, in
the table of seed runs or the pins file. A seeded pin keeps no clock
until then, and a mark that an older sweep set is cleared. After the
first install the pin follows the retention rule as before.

Assisted-by: Claude:claude-opus-5-5

* Fix two small labels of the Skills and Backends pages

On the Skills page, the skill of an add-on that is not chosen said
"Replaced by <add-on>", the label of a built-in skill that an add-on
serves. It now says "Not active: <add-on> provides it", as the add-on
skills spec asks.

On the Backends page, Clear filters on an empty Installed search left
the library filter set, so the list stayed empty. It now clears the
library filter too.

Assisted-by: Claude:claude-opus-5-5

* Tell the model when no network card can appear

Each turn told the model that a blocked host asks the user. No card
appears when the ceiling is off or no wider than the chat's preset, in
an unattended run or in a sub-agent, so the model waited for an answer
that could not come.

The line now says that a blocked host is refused and nothing asks the
user in those cases, so the model names the host it needs in its
answer.

Assisted-by: Claude:claude-opus-5-5

* Translate six Backends and preview labels in every locale

check, reinstallBackend, deleteBackend and filterLabel of the Backends
page and the label and failed text of the file preview showed in
English in the eight other locales. They now have translations, and
the i18n baseline goes down to match.

Also fix a comment of the home composer that still named the removed
Canvas chip.

Assisted-by: Claude:claude-opus-5-5

* List the admin routes that have no assistant tool, with the reason

The admin oversight routes of saved agents, triggers and connectors
had no MCP tool and no recorded reason, and the other deliberate skips
lived only in code comments. coverage_test.go now keeps them in
adminRoutesWithoutTool with a reason each, and a spec checks that no
route there is also wrapped by a tool. The contributor checklist names
the map.

The tool catalog of the assistant docs said it matched the real one
but missed most tools added since. It now lists every tool, read-only
and mutating, and the actions that stay in the web interface.

Assisted-by: Claude:claude-opus-5-5

* Close the doc and registry gaps of the chats and add-ons

- /api/agent/* answers 404 with the chats_off reason when the chats
  are off, as /api/chats/* and /api/workspace/* do.
- The add-ons docs get an upgrade section: Studio and Talk are
  add-ons, nothing is preinstalled, and users need the addons feature,
  which the upgrade does not grant. It says how an administrator
  installs them (also from a private library) and grants the feature,
  and carries a paragraph for the release notes.
- The migration page no longer lists fork, edit, the chat settings and
  the token counters as removed.
- Runtime settings document chats_vision_model,
  chats_transcription_model and the skill keys of
  chats_tool_providers.
- The docs show POST /api/chats/files/folders,
  GET /api/chats/files/history and the allow route of a connector
  sender.
- The in-tree specs get amendments where the shipped design differs.
- A route test of the tagged suite still set the removed Runs field.

Assisted-by: Claude:claude-opus-5-5

* Look for the kit empty state in the backends regression spec

The Backends page now draws the shared EmptyState of the kit
(ui-empty), not the old dk-empty block, so the regression spec of the
gallery suite found no empty state after a search with no match.
Check the kit's no-results form and its title.

Assisted-by: Claude:claude-opus-5-5

* Ignore a features request that outlives its page in the add-on stubs

stubAddonRoutes answers /api/features by fetching the real flags and
turning add-ons on. A spec that ends while the page polls, like the
one that checks that a viewer without the feature never reads the
list, left that fetch in flight, and Playwright failed the spec with
"route.fetch: Target page, context or browser has been closed" after
its checks had passed. Abort the request when the fetch fails because
the page is gone.

Assisted-by: Claude:claude-opus-5-5

* Bring the gallery-ui case inventory up to date

The suite lists the node unit cases of addons.test.mjs and the
Playwright specs of addons-gallery.spec.js. The inventory missed the
unit cases added since it was written, and one spec was renamed when
the legacy switch came in ("hub: the Add-ons tab appears only for an
account that holds the feature" is now "hub: under the legacy switch
the Add-ons tab appears ..."). The list comes from a local run of
both parts against the UI test server.

Assisted-by: Claude:claude-opus-5-5

* Read spreadsheets, documents and slides in read_document

read_document said "file.xlsx has no text layer; it may be a scan" for
workbooks that some Python libraries write. Their workbook gives the
sheet as an absolute part name (/xl/worksheets/sheet1.xml) and the
cells as inline strings. The text extractor of the harness joined
"xl/" with that name, found no sheet, and returned no text; the tool
then took any empty result for a scanned PDF.

The new package core/services/studio/extract has one entry point,
Extract(ctx, name, data), that returns the text and the structure it
read, for read_document now and for a file indexer later. Office files
go through the files preview reader, which resolves both kinds of part
names and reads inline strings:

- a workbook comes sheet by sheet, rows as tab-separated lines, up to
  2000 rows and 50 columns a sheet, with a note for a cut sheet;
- a Word document gives headings, list items, paragraphs and tables;
- a presentation gives each slide with its title, text and notes.

PDF and EPUB keep the harness extractor. Only a PDF with no text is
reported as a probable scan; an empty Office file is reported as empty.
The preview reader now keeps a Word table as one block with its rows,
and the preview pane draws it as a table.

Assisted-by: Claude:claude-opus-5-5

* Add the missing explorer, library and tools translations

Eight locales had no explorer.json, library.json or tools.json. The
browser asks the server for every namespace of the language it shows,
so an Italian page that used the library answered 404 for
/locales/it/library.json on every load and fell back to English.

The 24 files now exist, translated, with every key of English. The
locale gate counted a missing file as missing keys, which the baseline
allowed. It now fails on a missing namespace file whatever the
baseline says, and the baseline is 24 entries shorter.

Assisted-by: Claude:claude-opus-5-5

* Back off while the add-on service is unavailable

A page that followed an add-on upgrade read the operation every two
seconds, up to 300 times. While the add-on service restarted, each read
waited for its timeout and answered 503, so the log of one session had
48 failed dispatches in a row, and the page only showed the upgrade as
running. The Sandbox state of a chat's Tools menu read once and, on a
503, said nothing more.

The reads of an operation now back off while the service does not
answer: 2, 4, 8, then up to 30 seconds. The upgrade entry says that it
waits for the add-on service and when it checks again, in Activity and
in the details, which also get a Check now button. The Tools menu says
that the Sandbox is starting and reads its state again with the same
back-off, kept for the page, so opening another chat does not ask
again before the wait is over.

Assisted-by: Claude:claude-opus-5-5

* Start a chat with its switches and list them before it exists

The composer of a new chat could not show the Tools and Skills menus,
because the lists and the switches belong to a chat. A chat started
from Home therefore always began with every tool and skill on.

- POST /api/chats takes switches: the add-ons, MCP servers and
  connectors, built-in groups and skills that are off, and the opt-in
  groups that are on. They are checked as the PUT endpoints check them
  and stored with the new record, so the chat never exists without
  them; a bad entry refuses the request and creates nothing. The SQL
  store now writes these lists on create too.
- GET /api/chats/draft/tools and /api/chats/draft/addons list what a
  chat on a model, with a saved agent, could use, every switch in its
  default state. They refuse what create refuses: an unknown or
  forbidden model, an agent without the agents feature, another
  user's agent.

Document both in the chats page and regenerate the swagger.

Assisted-by: Claude:claude-opus-5-5

* Give Home the composer of the chat page

Home drew a smaller message box than the chat page: no files, no
agent, no Tools or Skills menus, no paste to attach, no rich model
list, and its text was lost on a reload. A chat started there could
not be set up before its first message.

Move the composer wiring out of the chat page into one place that
both pages use:

- useChatComposer holds the draft (text and files), the model and the
  saved agent of a new chat, the chat models, the switches and what
  attaching and pasting do.
- ChatComposer draws the model list (fit, vision, memory bar), the
  agent picker, the Tools and Skills menus, the attach buttons,
  dictation, the add-on slot and the vision notice over HomeComposer.
- useChatSwitches has a draft mode: before the chat exists it lists
  from the draft endpoints, a switch changes only the screen, and the
  choices go with the create request. They outlive a change of model
  or agent.

Home now creates the chat with the model, the agent and the drafted
switches, sends the first message with its files and opens the chat.
When the message cannot go, the new chat is removed and the text and
files stay on Home. Its text is kept in the browser across a reload.
Home also gets the shortcuts row, the notices of the chat page and the
line that says whether the model is loaded. Its own slash actions,
widgets, examples and first-run steps stay.

The empty chat page gets the same draft menus. On a phone the chips
of both wrap to a second row, and the Tools and agent menus open as a
sheet from the bottom, as the skills picker does.

Assisted-by: Claude:claude-opus-5-5

* Move add-on settings to the add-on's own page

The settings.sections slot drew every add-on's settings at the end of the
global Settings page, and the Sandbox and Web sections were unstyled: the
add-on UIs used class names the host does not define (btn, btn-primary)
and bare inputs, the SDK offered no form primitives, its muted token
named a property that does not exist, and the slot root was an
inline-flex span that laid a form out in a row.

An add-on's settings sections now render on the Settings tab of its
details on the Add-ons page (/app/addons?detail=<id>&view=settings),
narrowed to that add-on, for administrators only. An add-on page gets a
host Settings link to that tab. The Settings page no longer draws the
slot: an Add-ons group, shown when an add-on has settings, lists those
add-ons with a link each. The old #ad-section-<addon>-<id> anchor
redirects to the tab once the apps list is read. Server settings of an
add-on's feature stay on the Settings page; the tab shows them under
"Server settings for this add-on", with a read-only summary of the
Sandbox network and links to ?group=tools#settings-egress and
#settings-builtin-tools.

The SDK gets a settings kit in sdk.ui (Section, Field, Select,
TextInput, Switch, Choice, StatusChip, Callout, List/ListRow, Code,
Actions, Table, ExternalLink), drawn with host classes and tokens, and
more theme tokens. The Sandbox and Web sections are rebuilt with it:
backend rows with a status chip and the raw reason collapsed in a code
block, a backend choice with one line per option, and the AppArmor and
user-namespace hint (with a docs link) only for the gVisor
"exit status 128 ... cannot read client sync file" failure.

The Settings page showed "Changed, default 30, Reset" next to a 0 for the
audit retention, and the same for the Sandbox network limit, preset and
ports: the server stores 0 or an empty value for a setting never set.
Those fields now read that value as their default, and the retention
input has its unit and bounds.

Assisted-by: Claude:claude-opus-5-5

* Adapt the add-on runtime specs to the new navigation

Three specs of the esm-ui suite still assumed the old shell:

- the Add-ons tab that lists the pages add-ons declare is part of the
  legacy layout, so the navigation spec found no hub subnav; it now
  sets the legacy switch on the server's flags for that page;
- the sidebar has no "Chat" link any more, so the unsaved-edits spec
  could not leave the page; it leaves through Home in the primary
  navigation;
- the shell keeps a notification stream open, so the network never
  goes idle and the spec for a member without the feature waited out
  its timeout; it waits for the server's switches, the account and
  the shell instead.

Assisted-by: Claude:claude-opus-5-5

* Name the legacy Add-ons tab unit case as the esm unit tests do

The esm-ui inventory listed "unit: registry: the Add-ons tab lists
page links only when the registry has usable add-ons", but the unit
test is named "the legacy Add-ons tab lists ...", so the suite could
never match its inventory. Use the name the test prints.

Assisted-by: Claude:claude-opus-5-5

* Say on the Collections page when the embedding model is missing

At startup the server opened a collection and its first embedding call
got 404 from POST /embeddings. The collections embed through this
server's own API with collections_embedding_model, the default
granite-embedding-107m-multilingual, and that model was not installed.
Nothing told the user: uploads and searches just failed.

GET /api/collections now also returns embedding_model and
embedding_model_installed (a loaded configuration of that name, or a
model file of that name). When it is missing, the Collections page
says "No embedding model installed", names the model, and gives an
administrator a button that opens the Models page with a search for
it.

Assisted-by: Claude:claude-opus-5-5

* Report modified times and the upload limit in folder listings

The Files page could not sort by date or show when a file changed: a
folder listing had no time. It also learned the upload limit only after
it had sent the whole file. The default server body limit is 15 MB,
lower than the 256 MiB a workspace file may have, so a large upload
failed late and without a clear reason.

Each listed entry now has "modified", the time of the change set of
its revision. Both workspace stores fill it in List: the JSON store
from its in-memory change sets, the database store with one query per
batch of revisions. The listing also has "max_file_size", the smaller
of the workspace limit and the server body limit, so a client can
refuse a larger file before it sends any byte.

The store contract suite checks the new time against the history, and
the route tests check both fields.

Assisted-by: Claude:claude-opus-5-5

* Add a sortable file list with thumbnails for the Files page

The building blocks of the new file browser, used by the page in a
later change:

- fileBrowser.js: the kind of an entry from its extension, the order
  (folders first, natural and case-insensitive names, then size,
  modified time or type), the filter of a folder, dates in words with
  the full date for a tooltip, the Shift range, the arrow moves of a
  list and of a grid, type-to-find, names that do not clash, why a
  name cannot be used, the name of a pasted screenshot and the view
  settings read back from storage.
- FileList: a grid with sortable column headers or a grid of tiles
  with image thumbnails, a check box per row, a row menu, inline
  rename with the reason a name is refused, rows that can be dragged
  onto folders, and the keyboard: arrows, Shift, Space, Enter, F2,
  Delete, Ctrl+A, Escape, Backspace and typing a name.
- MoveDialog: a folder picker that walks the tree and refuses a move
  into the moving folder itself.
- ActionMenu can open at a point with no trigger (a right click), and
  its trigger can take another icon and class (a split button).
- fileSize also writes gigabytes.

Assisted-by: Claude:claude-opus-5-5

* Add an upload queue with progress, cancel and retry

An upload of the Files page was one fetch per file in a loop: nothing
showed while it ran, one failure stopped the rest, and leaving the
page lost it.

- uploadQueue.js keeps every upload outside React: queued, sending
  with the bytes sent and a smoothed rate, done, failed with a reason
  and whether Try again can help, or canceled. Two files go at once.
  It lives for the whole app, so opening another folder or page does
  not stop an upload.
- filesApi.uploadWithProgress sends the same PUT with XMLHttpRequest,
  which reports upload progress and can be aborted. The server already
  streams the body into the store; nothing changes there.
- useUploads reads the queue and asks before the tab closes while a
  file is on its way.
- UploadTray shows the queue at the bottom of the page: the total and
  the time left, each file with its progress, speed and time left,
  Cancel, Try again with the reason, and a done state that fades out.
  A live region tells a screen reader when uploads start, fail and
  end.
- ConflictDialog asks what to do when an upload has the name of a file
  in the folder: replace it, keep both, or skip it.
- dropFiles.js reads dropped folders with their paths.

Assisted-by: Claude:claude-opus-5-5

* Rebuild the Files page as a file browser

The Files page was a list of links: the store's byte order, the same
icon for every file, three icon buttons on every row, no progress on
an upload, no selection, and on a phone a preview that opened below
the whole list.

Browsing: a breadcrumb that folds a deep path, sortable columns (name,
modified, type, size) with folders first, a list or a grid of
thumbnails, both kept per user in the browser, a filter of the open
folder with a search of every file on Enter, type icons, human sizes,
dates in words with the full date on hover, and Back and Forward
between folders.

Uploads go through the upload queue and its tray: the Upload button
or its folder menu, drops of files and folders anywhere on the page or
onto a folder row or crumb, and paste. A clash asks to replace, keep
both or skip; a file over the server limit is refused before it is
sent.

Selection and actions: click, Ctrl and Shift, check boxes, a selection
bar (Download, Move to, Move to Trash; at the bottom of the screen on
a phone), a row menu and a right click, inline rename and new
folder or file, drag to move, the keyboard, and a toast with Undo for
a delete, a move and a rename.

States: a skeleton on the first load, an error with Try again, empty
states that say how files get here, and a no-match state. The preview
uses the side pane: docked on a wide screen, a sheet on a phone, with
the same actions as the row menu. Trash, History and the Managed by
LocalAI group stay as they were.

Every new string is in the nine languages. The page uses design
tokens only (seven raw font sizes fewer). The specs cover sorting,
the filter, the views, selection and bulk actions, the keyboard, the
menu, rename checks, drag to move, drops, paste, clashes, the size
limit, upload progress, cancel and retry against the real server, and
the error states.

Assisted-by: Claude:claude-opus-5-5

* Fix two specs that fail on the integration branch

The Describe spec of the egress package checked that the no-card line
does not contain "asks the user", but that line says "nothing asks the
user". It now checks for the sentence that promises a card.

The context meter spec gave the chat a 4k context window. The tool
schemas of the chat now take 3k of it, so the turn stopped before the
model request. The spec uses a 16k window.

Assisted-by: Claude:claude-opus-5-5

* Translate the always-allowed hosts note of the chat network row

The three egress keys of the always-allowed hosts were only in English,
so the locale check failed for every chats namespace. The workspace
namespaces now miss two keys fewer, so their baseline goes down too.

Assisted-by: Claude:claude-opus-5-5

* Bring the contracts and host-slots case inventories up to date

The contracts suite has eight new specs for the check of a tool that
shadows a built-in. The host-slots suite runs the unit case of the file
preview slot, which the inventory did not list.

Assisted-by: Claude:claude-opus-5-5

* Add the design of the file text index

The search of the chats' files reads only small UTF-8 text files, so a
PDF or an Office file is found by name only. The design extracts the
text when a file is written, keeps it in LocalAI's own store keyed by
node and hash, checks access at query time and runs one indexer per
cluster under an advisory lock.

Assisted-by: Claude:claude-opus-5-5

* Give extracted documents their pages, sheets and slides

Extract now says where each page, sheet and slide starts in the text,
so a search hit can name its page or sheet. A PDF page starts with a
"## Page N" line, as sheets and slides already start with a heading.
A PDF also stops at a page limit (200 by default) and at the text
limit, which it ignored before, and a panic of the reader is an error.

The test fixtures move to extracttest, with a real text PDF and a
workbook with shared strings, so other packages can build the same
documents.

Assisted-by: Claude:claude-opus-5-5

* Add a store for the text of workspace documents

textindex keeps one entry per workspace node: the text read from a
PDF or Office file, the hash it was read from, its pages or sheets and
its status (pending, ready, failed, skipped), plus the cursor of the
indexer in the workspace journal.

The GORM store keeps a lower-cased copy of the text, so SQL and the
Go matcher agree on every script, and searches it with FTS5 and the
trigram tokenizer on SQLite or a pg_trgm index on PostgreSQL. Without
them it scans the column. The JSON store keeps the metadata in memory
and each text in its own file, and scans the texts. One contract
suite runs on JSON, SQLite and PostgreSQL.

Assisted-by: Claude:claude-opus-5-5

* Index the text of new and changed workspace documents

The indexer tails the workspace journal from a cursor kept in the text
store. A write of a PDF, Word, Excel or PowerPoint file marks it
pending (the same hash only follows the path), a delete removes the
entry and a move rewrites the paths below a folder. Then it reads the
pending files two at a time, with a timeout, a size cap, a page cap and
a text cap, and stores ready, failed or skipped. A panic of the reader
fails the file, not the pass. The same content is read once.

The first pass starts at revision 0, which indexes the files that were
there before, in bounded steps that resume from the cursor. Enqueue
marks an upload pending at once and Forget drops the entries of nodes a
purge erased. In a cluster each pass runs under a new advisory lock,
so one frontend reads.

Assisted-by: Claude:claude-opus-5-5

* Search and read the text of documents in the chats' files

search_files and GET /api/chats/files/search now also search the text
index: after the name and text-file hits come lines of PDF, Word, Excel
and PowerPoint files, as path (page 3, line 40): text, with the sheet or
slide where a document has them. Each entry is shown only when the
caller may read its file now and the file still has the content the
text came from. Documents keep up to a third of the hits. When files
below the path are still pending, the answer says so instead of
"Nothing found.", and the REST result has indexing.

read_file returns the text of a PDF or Office file with the usual offset
and limit, from the index when it matches the file and read on the
spot otherwise. An upload and a write of a chat tool queue the file at
once, and emptying the Trash drops the entries of the purged files.

Assisted-by: Claude:claude-opus-5-5

* Start the file text index with the files and add its settings

With files on, the server opens the text store next to the workspace
index (the auth database, or a folder under the data path) and starts
the indexer. A chat worker searches the index but runs no indexer.

chats_index_files (default on) switches the reading off and
chats_index_max_text_bytes (2 MiB by default, 64 KiB to 16 MiB) caps
the text kept for one document. Both apply at the next pass, and both
are rows of Settings > Tools.

Assisted-by: Claude:claude-opus-5-5

* Show the page, sheet or slide of a document hit on the Files page

Search all files now lists hits inside PDF and Office files with their
page, sheet or slide instead of a line number of the extracted text,
and says how many documents are still being indexed. The strings are
in all nine locales.

Assisted-by: Claude:claude-opus-5-5

* Test finding an uploaded PDF by its words through the routes

The PDF has a generated name and is uploaded with the REST upload. The
search route first reports it as being indexed, then finds it on its
page after a pass of the indexer, and so does the search_files tool of
a chat. Another user finds nothing.

Assisted-by: Claude:claude-opus-5-5

* Document the search inside documents

The chats page says what the index reads, where the text is kept, who
finds it, which search engine each database uses, the two settings,
the backfill and the single-runner mode in a cluster, and how
search_files and read_file answer for documents. The API instructions
and the PDF skill say the same in short.

Assisted-by: Claude:claude-opus-5-5

* Test the indexer on the JSON workspace store

A server without a database keeps the workspace and the text in JSON
files. The indexer follows the uploads, a folder move and a delete in
that journal as it does in the database one.

Assisted-by: Claude:claude-opus-5-5

* Read all of a long document with read_file

The index keeps the first chats_index_max_text_bytes of a document, so
read_file used to stop where the index stopped. It now uses the index
only when it holds the whole text, and reads the document again (up to
16 MiB of text) when the index cut it.

Assisted-by: Claude:claude-opus-5-5

* Start bash in the user's home

The Sandbox's bash and the built-in bash started in /workspace, the
folder that holds the mounts, so a model that ran a script by a
relative path failed and a file it saved there was lost. A call now
starts in /workspace/home, the folder of the user's files: a relative
path is the same file the file tools see. The tool descriptions and
the commands block of every turn say where a call starts and that
only what is saved there is kept. The built-in bash says that the
/workspace paths do not exist on the host and that a shared folder is
next to the home.

Assisted-by: Claude:claude-opus-5-5

* Name files in tool results by the path the model uses

write_file, edit_file and search_files named a file of the home by its
path in the home ("/scripts/build.py") while the model had written
/workspace/home/scripts/build.py, and a model took the two spellings
for two files. The results now give the path the model uses, and
move_file says where it moved the file to. The cards and the change
notes keep the path in the home.

Assisted-by: Claude:claude-opus-5-5

* Name the paths a command's commit did not save

The result of a bash call ended with "N file(s) changed in your files
meanwhile; the sandbox's version was kept as a copy" for every path the
commit refused, also for a file written outside the user's files,
where no copy is kept. It now has one line a path, with the path as
the guest sees it, the reason, and the path of the copy when the store
kept one, so the model and the user can act on it. The host returns
the paths and the copy to the Sandbox add-on relative to the user's
files, as its mounts are.

Assisted-by: Claude:claude-opus-5-5

* Show the files a command saved under its step

A document that a script wrote with bash reached the user's files, but
the chat showed nothing: only the file tools put a file on their step,
and the Sandbox committed for no chat, so the chat's file list, the
chips under the answer and the preview pane never saw the file.

The host now commits a Sandbox call for the chat that ran it (the
action resource of the request names the chat). After each bash call,
of the Sandbox or of this machine, the chat reads the change sets of
the chat that the call made from the shared store and puts the files
on the step's card, next to the card that says who served the call
(session.SetToolFiles; files with path, change set and op on the
card's new files field). The step lists them as chips that open the
preview pane, the chat's clients are told that its files changed, and
the files reach the file list, so the answer gets its chips and the
pane opens on the newest one, as for write_file.

Assisted-by: Claude:claude-opus-5-5

* Keep JSON out of the answer of a trigger run

The workspace skill told the model to put the widget data shape and a
source marker in a trigger prompt. Some proposals then asked the run to
print that JSON, and every run ended its chat with a stray line of it.

The skill now says source and note live inside the data file and are
never the answer, and that a prompt must not ask for JSON. The runner
appends one closing instruction to the first message of every trigger
run: finish with one short plain sentence. The propose_trigger and
update_trigger descriptions say the prompt must stand alone and must
not ask for JSON. Connector chats are talks with people and do not get
the line.

Assisted-by: Claude:claude-sonnet-5-5

* Read the images of a page as base64 for its frame

The bridge of a page reads UTF-8 text only, so the UI could not put a
png or a jpg of the page's folder into the page. A read of the page
file routes with encoding=base64 now returns an image as base64 with
its media type. Only the extensions of an image are read this way
(png, jpg, gif, webp, avif, bmp, ico, svg); any other file is 415, so
this is no way to read an arbitrary binary file. The path checks, the
1 MiB limit, the viewer's rights and, for a shared page, the consent
check are the same as for a text read.

Assisted-by: Claude:claude-opus-5-5

* Let a page use the files next to it

A page runs from a srcdoc with no network, so fetch('news.json'),
<script src="app.js">, <link rel="stylesheet" href="style.css">,
<img src="logo.png"> and import './x.js' all failed without a word.
Models that split a page into files, or load its data with fetch,
made pages that showed nothing.

Before the frame loads, the UI now reads the files that the page names
with relative URLs, with the same calls as the bridge, and puts them in:
classic scripts in place (deferred ones at the end of the body), style
sheets as <style> with their @import and url(), images as data: URLs,
and ES modules as blob: URLs behind an import map, so cycles and
import() work. A page with modules gets blob: in script-src; no other
part of the policy changes. Inside the frame, fetch and XMLHttpRequest
read relative URLs with files.read and answer with a real Response (200,
404 for a missing file, 413, 415); any other URL rejects with "network
is off in pages; put the data in a file next to the page".

Every path is resolved inside the page's folder: .., %2e%2e, absolute
paths, backslashes and protocol-relative URLs are refused, and the
query and the fragment are dropped. The files go in only after a shared
page is allowed, with the viewer's rights. The files that go in are at
most 4 MiB, images 2 MiB; a script or style sheet that does not load
shows a notice in the page. A change of one of these files reloads the
page, as a change of index.html does.

The skills, the docs and the shared pages fixture say and test the same.

Assisted-by: Claude:claude-opus-5-5

* Return tool descriptions from an MCP connector test

A connection test listed only the tool names. A person who adds a
server cannot tell from a name such as "query" what the tool does or
whether to keep the connector on.

The test response now also has tool_details: each tool with the
description its server gives, in the order of tools. tools is
unchanged, so existing clients keep working.

Assisted-by: Claude:claude-opus-5-5

* Add jq, ripgrep, sqlite3 and archive tools to the Sandbox guest

The guest user cannot install packages and apt is blocked by the proxy,
so any tool the model needs has to be in the image. Add jq, ripgrep,
sqlite3, zip, unzip, file and tree to the final stage.

A new check-tools.sh runs in the existing build step and fails the build
when one of these programs, Poppler, git or curl is missing or does not
start.

The list is one constant, GuestTools, in the shared sandbox package. The
Commands block of the prompt of an isolated chat names it. The tool
description (capped at 400 characters, already full) and the turn note
(cut at 400 characters) have no room for it. Tests keep the Dockerfile,
the check script and the Sandbox documentation in line with the constant.

Assisted-by: Claude:claude-sonnet-5-5

* Keep the helper files of a chat in its work folder

A chat asked for a Word document left a 19 KB build script at the top of
the user's home, next to the user's own files. Chats like it leave
scripts, intermediate data, logs and drafts at the top level or in
folders such as scripts/, and nothing tells them apart from what the
user asked for.

Each chat now has a work folder, Chats/<chat folder>/work/ in the
user's home, next to its attachments. The chat takes the name of its
folder at its first turn (checked against the folders and the other
recent chats of the user, so two chats with one title get two names)
and makes the folder only when it is used: before a bash command runs,
or when a file is saved there. The prompt of every turn names the
folder and says what goes in it: scripts, helper code, intermediate
data, logs and drafts go there; the deliverable goes where the user
said or at the top of the home; no new top-level folders for scripts;
a run-once command needs no file. A sub-agent is told its parent's
folder. The descriptions of bash (the Sandbox's, within its 400
characters, and the built-in one) and of write_file end with one short
hint, and the built-in office, apps and workspace skills say the same
in one line.

The steering is soft. When write_file, move_file or a command leaves a
helper file outside the work folder, the result gets one line that
suggests moving it, at most once a turn of a chat.

One function (workspace/workfiles) decides the kind of a file:
working for anything in a chat's work folder, or for a script, a log
or a temporary file by its extension or a folder named scripts, tmp or
scratch; deliverable for everything else, and always for pages, the
LocalAI folder, the shared folders and the files the user attached.
The chat's file list (kind), the files of a command's card
(files[].kind) and the card of a file tool (file_kind) carry it, so the
interface only renders it.

The runtime setting chats_work_folder (on by default) turns the
steering off.

Assisted-by: Claude:claude-opus-5-5

* Stop telling the model that the Sandbox has npm

The guest image has no Node, so the network hints named a tool that
does not exist.

Assisted-by: Claude:claude-sonnet-5-5

* Update the Sandbox description test after dropping npm

Assisted-by: Claude:claude-sonnet-5-5

* Open the links of a page after the person confirms them

A page runs in a frame without allow-popups or top navigation, so a
click on <a href="https://..."> did nothing, and a link to #id loaded
LocalAI's own address in the frame, since a srcdoc resolves it against
the parent. A news page had only dead links.

The bridge of the frame now takes the clicks on links (also with a
modifier, the middle button or Enter) and window.open(), and sends
link.open(url) to the host. The host lets through only an http or https
address without a user name or password, at most 2048 characters;
javascript:, data:, file:, blob:, //host and links to other files of
the page are refused with a message in the console. A bar above the
page shows the site in large type, the whole address, and Open and
Cancel. A host in punycode also says how it reads, since it may imitate
another site. Open is a click in the app, so the new tab is not blocked
and opens with noopener and noreferrer. A page asks at most 5 links at
once, then one every 3 seconds. A link to #id scrolls the page.

The sandbox, the policy of the frame and the consent of shared pages do
not change; a shared page asks the same way.

Assisted-by: Claude:claude-opus-5-5

* Let the items of a Home widget link

A list widget showed each item as plain text, so a digest of articles
or a list of pages could not take the person anywhere. An item now has
an optional url. An http or https address without a user name opens in
a new tab with noopener and noreferrer, and its tooltip names the site;
a path of the app (/app/pages, /app/chats, /app/files and the other
screens a person reads) opens inside LocalAI. The label is the link,
with a focus ring, an underline on hover and focus, and an icon for an
address outside the app.

The widget-data schema checks the url, and the server adds an error in
words that names the item and the rule, so a trigger run that writes a
bad link learns why. The skill and the docs show the field.

Assisted-by: Claude:claude-opus-5-5

* Attach any file in a chat with one button

The chat had three attach buttons (image, audio, file) that all add to
the same list, and the file button's dialog filtered on */*, which
some file dialogs read as a type filter that greys out archives such as
.zip. A chat now shows one Attach file button whose dialog has no type
filter. Composers without anyFile keep the three buttons.

Assisted-by: Claude:claude-opus-5-5

* Accept both Node behaviours for a broken punycode label in the link test

Node 22 refuses the address, Node 24 parses it. Both mean the page never
opens it unwarned.

Assisted-by: Claude:claude-sonnet-5-5

* Show a chat's working files apart from what it made

The Files pane, the steps and the preview treated a helper script like
the document the user asked for: a 19 KB build script was listed next
to the document, got a chip under the answer, and the preview opened on
whichever file was newest.

The interface now renders the kind the server puts on each file. The
pane lists what the chat made first and folds the working files into
one quiet heading under the rest, "Working files · 2", with a line that
says what they are; opening it shows their rows, which preview like any
file. A working file opened from a step unfolds the group. The preview
that opens by itself after a turn picks the newest file that is not a
working file, and the chips under the answer name only those files. A
step that saved working files lists them as one line, "Also saved 2
working files", that opens to their chips, and the file of a write_file
step that is a working file is a quieter chip. The files the user
attached are unchanged.

Assisted-by: Claude:claude-opus-5-5

* Add a search field and a segmented filter to the UI kit

The Agents views each drew their own toolbar: a search box capped at
320 px on the agents list, round chip filters on the triggers history,
and a bare checkbox on the tasks page. Add-ons already had the look the
product wants (a search that fills the row and a segmented tray), but
only as add-on classes.

SearchField and Segmented are that toolbar as two small primitives with
ui-* classes and token values only. Segmented buttons carry their id in
data-filter, so specs can press them. The README shows how to use them.

Assisted-by: Claude:claude-opus-5-5

* Draw an agent task run as a history row with its output

The jobs of an agent task were table rows that opened to bare <pre>
blocks: no copy, parameters printed as k=v, the traces in a raw
<details>, and "by manual" in the server's words.

RunItem is one run of a history list: a toggle, the state chip, what it
was and what happened, when and for how long, small actions, and the
details that open under it. OutputBlock draws an answer or an error in
mono with a Copy button. JobRow and JobDetail use them for a job: the
values it ran with as labelled chips, the answer or error, the steps,
the webhook outcome and a link to the chat that holds the run. Times
show as words with the full date as a tooltip.

The agent task helpers gain the pure rules the page needs: the jobs of
a task, the run filters (waiting and running count as in progress), the
on/off filter and search of the task list, the field errors of a save,
how a job started, and the API call that runs a task by name.

Assisted-by: Claude:claude-opus-5-5

* Create, edit and run agent tasks in a side sheet

The task form opened as bare fields above the list, with a checkbox for
On and a Save button that was only disabled when a field was missing.
Run with parameters was a second inline form in the same place.

TaskSheet is a side sheet with three labelled groups (about, who runs
it, what it does), help under each field, the parameters the prompt
asks for as chips while you type, and an On switch. Save checks the
required fields, says next to each one what is missing, and moves the
focus to the first. RunSheet asks for each value the prompt names and
shows the prompt as the task will receive it.

Assisted-by: Claude:claude-opus-5-5

* Show the details of an agent task in a pane with tabs

A task had no details view: its prompt, its runs and the way to run it
over the API were only in the lede of the page.

TaskPane is the kit's side pane with three tabs. Overview shows who
runs the task, the values it asks for, the prompt and a curl call that
runs it by name, with Copy. Runs lists its jobs. Settings holds the On
switch, the webhook count and Delete. Run and Edit stay in the footer.
The tabs move with the arrow keys, Home and End.

Assisted-by: Claude:claude-opus-5-5

* Rebuild the agent tasks page from the shared list pieces

The tasks page looked unstyled next to Add-ons and the agents list: two
raw tables under uppercase eyebrows, a bare checkbox for All users,
forms that opened above the list, three text buttons on every row, and
on a phone a table that broke names one syllable per line.

The page now uses the same pieces as the polished pages. The header has
one line and New task. A toolbar holds the search, an All/On/Off filter
and, for an administrator, an All users switch. Each task is an agent
row: a tile, the name, two lines of description, who runs it and what
it asks for, the last run's state and time with the run strip, an On
switch, Run and a menu. A task with no parameters runs at once. The
name opens the details pane; New task, Edit and Run open the sheets.
The run history is grouped by day, with a state filter, a task filter
and Show more. A job is deleted after an in-page question. With no
tasks the page explains what one is, with an example; a failed load
shows the error with Try again. On a phone the controls grow to 44 px
and the filters scroll sideways.

New strings, and the task strings that existed only in English, are in
all nine locales; the strings the page no longer uses are gone. A new
stubbed spec covers the list, filters, sheets, pane and history, and the
real-server spec follows the new controls. The docs describe the page.

Assisted-by: Claude:claude-opus-5-5

* Rebuild the MCP connectors page on the Add-ons patterns

The page read as a form: every connector was a row of raw controls (a
checkbox, a Test button, red Delete text), the add form pushed the list
down, a test result vanished on reload, and the frame was narrower than
the pages next to it in the sidebar.

The page now uses the same blocks as Add-ons and Files:

- Full page width and the shared PageHeader with a one-sentence purpose
  and "Add connector".
- The Add-ons toolbar (search and a state filter with counts) from four
  connectors, and the Add-ons rows: a monogram tile, a state chip
  (Connected, Needs sign-in, Can't connect, Not tested, Off), one line
  with the tools or the reason, a meta line, the kit Switch and a menu.
- Details in the shared SidePane: the switch, the last test, the tools
  with their descriptions and a search, the connection with the query of
  the address hidden, and what is saved.
- Add and edit in the shared SideSheet: kind first, grouped fields with
  inline checks, masked secrets with show and hide, then "Save and
  test", the result with the tools, and Turn on. Escape and Cancel ask
  before they drop typed changes.
- An empty state that says what a connector is for.

The last test of each connector is kept in this browser with a hash of
what it tested, never the address or a secret, so the page shows the
last known state after a reload. Strings are in all nine locales.

Assisted-by: Claude:claude-opus-5-5

* Document the MCP connectors page and its states

The MCP servers section now describes the add sheet (kind, checks,
masked secrets, Save and test, Turn on), the states a connector shows,
where the last test is kept, the search and the filter, and the details
pane. The test example shows tool_details.

Assisted-by: Claude:claude-opus-5-5

* Render a preloaded page without its loading placeholder

A page that was preloaded still showed the route's loading placeholder
when it opened: React.lazy suspends once on its first render even when
the chunk is already in memory, and React keeps a fallback on screen
for at least 300 ms once it shows one. Opening a chat from Home showed
a blank page for that time.

The page loader now remembers the module once it has loaded and hands
it to React.lazy as a thenable that resolves at once, so a preloaded
page renders in the same commit. A preload of a segment now warms
every page registered under it: /app/chats is the chat page, its
connectors and its conversion page, and before only the last one
registered was preloaded.

Assisted-by: Claude:claude-opus-5-5

* Move the composer from Home into the new chat in one gesture

Sending the first message on Home was a hard cut. The page stood still
while the chat was created, then showed a blank placeholder, the empty
"new chat" screen with its composer in the middle, an empty thread
with the composer at the bottom, and only then the message, while the
sidebar folded and moved the whole column. Focus was lost.

Now Send fades the rest of Home and keeps the composer in place while
the message goes. When the send has answered, a view transition moves
the composer to the dock of the chat, lifts the text out of it into
the message, moves the attached files with it and folds the sidebar in
place; the model's indicator comes in after the message has landed and
the empty composer has the focus. The chat page draws the message from
what Home already knows (a small hand-off store: the chat record, the
text and the files, with the local copy of an image for its thumbnail)
and keeps the same row when the server's transcript replaces it, so
nothing is drawn twice or animates again. What is sent to the server
does not change.

A browser without view transitions gets a FLIP slide of the composer
and the message (Web Animations, transform and opacity only). Less
motion gets a short cross-fade, or an instant switch. A send that fails
brings Home back, shakes the composer and keeps the draft; a second
Enter while one send is in flight sends nothing. The draft is cleared
when Home closes, so the box never shows its placeholder on the way.

Focus mode folds the sidebar in a layout effect, so the fold happens in
the frame the conversation appears. One motion token is added,
--dur-glide (360 ms), for a part that travels to its place on the next
page.

Assisted-by: Claude:claude-opus-5-5

* Draw the triggers as rows and their history like the task runs

The triggers page used a table with a switch column next to the agents
card list, folded its list behind Hide, filtered the history with round
chips, and on a phone cut each history row at the right edge.

Each trigger is now an agent row: a clock or folder tile, the name, the
schedule in the server's words, the agent or model and when it runs
next, the last run's state and time with the run strip, an On switch,
Run now and a menu. The week sentence sits under the Run history title.
The history uses the segmented filter and the same run rows and day
headings as the agent tasks, with Show more after 30 runs; an open run
shows its reason with Copy. On a trigger page the prompt comes before
the runs, in the body face, the On switch is the kit switch, and the
runs stop at 10 with Show more.

Assisted-by: Claude:claude-opus-5-5

* Use the shared search and the full width on the agents list

The agents list stopped its search at 320 px and used the content width,
while the Triggers and Tasks views next to it use the full width, so the
title and the view tabs moved when you switched views.

The list now uses SearchField, which fills the toolbar row as on
Add-ons, and the full page width like its sibling views.

Assisted-by: Claude:claude-opus-5-5

* Polish the agent task sheets and pane after a visual review

Screenshots of every state showed a few rough edges:

- The name placeholder looked like a filled-in value next to the error
  "Give the task a name". The name field has no placeholder now, and
  the prompt placeholder starts with "For example:".
- A task run by an agent showed the agent id until the agents were
  read. It says "Agent" until then.
- A run opened in the details pane also opened in the history, and the
  two copies shared an element id. The pane keeps its own open runs and
  ids.
- A failed run in the pane drew its meta line in red; the title carries
  the error colour there now.
- A group title that is not a legend had a double gap under it, and the
  kebab menus were under 44 px on a phone.

Assisted-by: Claude:claude-opus-5-5

* Cover the code files of a shared page in its consent

The consent to a shared page was kept against the hash of index.html
and page.json. The UI also puts the scripts, style sheets and modules
next to the page into it before it runs, so the author could change
app.js after a viewer allowed the page and run new code without asking
again.

The server now finds the same files as the UI's inliner: every script
src, stylesheet link, relative CSS @import and module import of the
folder, followed through the module graph. Their content hashes go into
the hash of the page, and a file the page names that is missing counts
too, so adding it later also asks again. Data files and images stay
out, so saving data does not ask again. The files are listed as
code_files. What a file names is kept per content hash in a small
per-frontend cache, which only saves reads.

Two more checks close the gaps around it. A frame of an older version
that reads a changed file of code gets 409, so a script edited while
the page is open never runs under the old consent. The UI puts no text
file into a shared page that is not in code_files, so if the server and
the UI ever disagree, the file fails to load instead of running outside
the consent. The trust sheet names the files of code when only one of
them changed.

Assisted-by: Claude:claude-opus-5-5

* Let a page be a tile on Home in its compact mode

Home widgets could show a list, a number or the last chats, but not one
of the pages a person or the assistant built. A page can now be a tile.

A page opts in with a widget block in page.json: a size (small, medium
or large, the height of the tile) and an optional short title. A
widget of type page in LocalAI/home.json names the page, and a folder
id for a page of a shared folder. The server takes at most three page
widgets and says why in words, and refuses a name that is not a page
name.

The tile runs the page in the same sandbox and bridge as the full
view. The page reads localai.page.mode ("widget" in a tile, "page"
otherwise) and localai.page.size, and <html> carries data-mode and
data-size, so the page decides how its tile looks instead of being
shrunk. The tile reserves the height of its size, builds its frame only
once it scrolls into view, tells the page through a new visibility
event when it goes out of sight or the tab is hidden, takes the frame
down far off screen, and keeps at most three frames alive. It has a
title bar with Open page and a refresh button, a skeleton while it
loads, Retry on an error, and the link question of the full view. A
page that is gone or has no widget block shows a calm line with a link
to Customise Home; a shared page that the viewer has not allowed shows
Allow this page, which opens the same trust sheet.

Customise Home lists the pages with a widget block, with the size of
their tile. The task board starter has a compact view, the skills tell
the assistant how to put a page on Home, and the docs describe it.

Assisted-by: Claude:claude-opus-5-5

* Give the Files upload its own size limit

The Files page upload was capped by the general --upload-limit (15 MB
by default), although a workspace file can be 256 MiB.

Make 0 the default of --upload-limit, meaning not set. When it is not
set, the general routes keep the 15 MB limit and the Files upload route
skips it, so the workspace file size is its limit. When the operator
sets a value, it applies to the Files upload too, lower or higher (a
file never exceeds the workspace size). The max_file_size of a folder
listing reports the limit in force.

Assisted-by: Claude:claude-sonnet-5-5

* Refuse writes of code files from a page

A page loads its own scripts, modules and styles, so a page that could
overwrite app.js or style.css would run new code on its next load. The
page bridge now writes data files only.

The server refuses a write whose final segment has a code or document
extension (js, mjs, cjs, css, html, htm, svg, xml, xhtml, wasm), is named
index, or is page.json, with 403 and a clear message. The check applies
to the page routes only; the Files page and the assistant's file tools
keep full write access. The judgement lives in pages.IsCodeFile and is
mirrored by isCodeFile in the web host, which refuses early with the
error code forbidden. Both run one table of cases, covering case, double
extensions, trailing dots and spaces, percent-encoding, backslashes and
lookalike dots.

Assisted-by: Claude:claude-sonnet-5-5

* Make the trigger tools a built-in group a chat can switch off

propose_trigger, list_triggers, update_trigger and delete_trigger were
added to every chat a person starts, with no switch. They are now four
entries of the built-in tool registry in one group, triggers, so the
Tools menu, the tools panel, the draft list and the builtins switch
endpoint handle them like the web group. The group is on by default.

A trigger or connector run and a sub-agent still never get them. The
panel lists the group as not usable, with a reason, for those chats,
for a user without the triggers feature, and not at all when the server
runs no triggers. The group has no runtime setting, so the registry
gets an Unlisted flag and Settings > Tools skips it. The panel now
builds every grouped tool to learn whether it is usable, not only the
opt-in ones.

Assisted-by: Claude:claude-sonnet-5-5

* Show the Triggers group in the chat Tools menu

The menu rows come from the groups the server lists, so the row needs
only its label in the nine locales. A Playwright spec covers the row,
its switch request, Select all and Disable all, and the disabled row
with its reason.

Assisted-by: Claude:claude-sonnet-5-5

* Talk about settings, not the files behind them

The settings cards, the shortcuts row, Home and the change notes in a
chat named the files that hold a person's settings: "Defined in
LocalAI/shortcuts.json", "Layout is in LocalAI/home.json", "Saved
LocalAI/persona.json". A person changes their shortcuts or their Home,
not a file, and the Files page still shows the files to whoever looks.

The "Stored in", "Defined in" and "Layout is in" lines are gone; the
history line keeps Versions, Revert and the Invalid badge. The notes
say what changed ("Saved your shortcuts.", "Created the page Task
board."), the errors name the setting or the widget instead of a path,
and the Source view says "The settings as text" instead of JSON and
schema. A failed save now says what happened in one plain sentence and
keeps the server's own words under a collapsed Details. The drafts that
"Edit with the assistant" puts in the composer no longer carry the
path; the built-in workspace skill already maps shortcuts and Home to
their files.

All nine locales are translated; only the changed keys moved, and four
keys that nothing reads any more are removed.

Assisted-by: Claude:claude-opus-5-5

* Drop internal names from the skills, add-ons and tasks copy

Other pages used words that only make sense to someone who knows how
LocalAI is built:

- Skills said "a folder with a SKILL.md" and "the file workspace". It
  now says what a skill is for, and that skills need Files.
- The add-on notes blamed "the owner", the internal name of the server
  that runs add-ons. They now say what happened to the action, or that
  the add-on service is not available; a private library names a
  credential "an administrator configured on this server".
- The Tasks header listed an API route, and the first-run wizard spoke
  of a "host bash fallback". The memory line of Settings no longer
  mentions "the resources endpoint".

All locales that have these keys are translated. The skill delete
dialog, the unused skills intro and the Tasks header exist only in
English and change only there.

Assisted-by: Claude:claude-opus-5-5

* Fail the unit tests when UI copy names implementation details

A new test reads every string of every locale and fails when one names
a settings or data file (.json, .yaml, LocalAI/), an API route or HTTP
method, a setting key (chats_*), an environment variable, a format
word (JSON, YAML, schema) or a path shown as code. Plain words such as
"schema" and "endpoint" are checked in English only, since other
languages use them for other things.

Operator pages may still name the model configuration, the metrics
route or a startup setting that the docs name. Those keys are listed in
ui-copy-allowlist.json, each with the audience and the reason. The list
only shrinks: an entry whose string no longer needs it, or whose key is
gone, fails too.

Assisted-by: Claude:claude-opus-5-5

* Name the triggers group in the chat tools routes

The routes that list and switch the built-in groups of a chat said only
"a name such as web". They now name all three: web, triggers and
saved_agents, with the tools of each.

Assisted-by: Claude:claude-opus-5-5

* Make the built-in skills answer in plain words

The skills told the model to report file names, folders and formats
after a change. Add one rule near the top of localai-workspace and
localai-apps: do the work with files, but say what changed, and name a
file only when the user did or asks. Replace the example replies that
carried paths, keep every path that says where to write, and pin the
rule with a test.

Assisted-by: Claude:claude-sonnet-5-5

* Apply the Go 1.26 modernizers to the latest Studio code

go fix suggested slices.Contains, strings.SplitSeq and range-over-int
on lines added since the first pass. ParseSearchProviders had the same
hand-written membership loop, so it uses slices.Contains too. Only
lines that the branch added since then are changed.

Assisted-by: Claude:claude-opus-5-5

* Share the blob wait and the counting of the two workspace purges

The JSON and GORM stores each had the 2-minute default for the blob
grace, the same switch that reads the BlobGrace option, and the same
loop that counts files, folders and bytes per revision. They now call
blob.Grace and PurgeResult.Add, both with specs. The SQL and the
in-memory walk that pick the nodes stay in each store.

Assisted-by: Claude:claude-opus-5-5

* Read the upper layer of a sandbox in one place for both stores

The JSON and GORM workspace stores had the same readUpper, place,
joinRel, depth and sortedKeys, with the same upperSet types. They move
to workspace/internal/upperset, which has its own specs. The commit
algorithm that applies the set to the nodes stays in each store; it
needs a storage interface first.

Assisted-by: Claude:claude-opus-5-5

* Let chat attachments use the 1 GiB message limit

The docs promise 1 GiB for a message with attachments, but the general
body limit (15 MB by default) ran first, because only the Files upload
skipped it. Skip it also for a multipart POST to the messages route
when the operator set no --upload-limit. A JSON message keeps the
general limit, and an explicit --upload-limit still wins. A message
that goes over the 1 GiB limit now gets 413, not 400.

Assisted-by: Claude:claude-opus-5-5

* Name the read_file tool in the skills index header

A weaker model read a built-in skill with the wrong path and then tried
the Sandbox, which cannot see skill folders. The header now says which
tool reads a skill and that the shown path is the one to use, before it
mentions where the user's own skills go.

Assisted-by: Claude:claude-sonnet-5-5

* Tell the model that skill folders are not in the Sandbox

The Commands block of an isolated chat now says that skills are read
with read_file. The Sandbox tool description and the per-turn note are
at their size caps, so the sentence goes in the system prompt.

Assisted-by: Claude:claude-sonnet-5-5

* Point read_document at read_file for text files

read_document reads PDF, Word, Excel, PowerPoint and EPUB files. For a
Markdown or text file it said only that the file is not a document it
can read. The error now names read_file.

Assisted-by: Claude:claude-sonnet-5-5

* Tidy the text index stores and the indexer pool

The two stores wrote the default limits 20 and 100 as numbers in five
places; they are now named constants, so the stores cannot drift. The
JSON store checks a missing file with errors.Is. The indexer starts its
readers with wg.Go and keeps the first error inline, which drops the
cmpErr helper.

Assisted-by: Claude:claude-opus-5-5

* Refuse the server's public address in the Sandbox proxy

web_fetch refuses the addresses of the server: its interfaces,
loopback and the host of the external base URL. The Sandbox proxy runs
in the add-on process and listed only the interfaces of its own
machine. Under "All public sites", an always-allowed host or an Allow
card, a command could reach the LocalAI API through the public name or
address of the server, a NAT address or a proxy in front of it.

The host now keeps one list for both. The application builds it once,
gives it to web_fetch, and sends it as CIDR strings in the new self
field of every egress.check allow. The proxy keeps the last list it
got and refuses it on each dial, besides its own interfaces, also for
an allow it cached. safehttp gets the codec and a join of deny lists,
so both sides read the list the same way.

Assisted-by: Claude:claude-opus-5-5

* Check the TLS server name on every port of the Sandbox proxy

The proxy checked the ClientHello only on CONNECT to port 443. An
always-allowed host pinned to another port, or any port added to
chats_egress_ports, was a raw tunnel: a command could open TLS to
another tenant of the same front through it. The docs said the server
name must still match.

On other ports the proxy still waits for nothing, since the protocol
may be anything and the server may speak first. But when the first
bytes from the guest are a TLS handshake record, it reads the whole
ClientHello and passes it on only when the server name is the CONNECT
host; otherwise it closes the tunnel and audits the reason sni.

Assisted-by: Claude:claude-opus-5-5

* Say what sent each notification

The inbox only knew whether a notification was about a run or needed
attention, so a trigger that was switched off and a connector that was
switched off looked the same. Each notification now carries a source:
trigger, connector or system (the conversion of old data). The list
endpoint returns it, and items stored before have none.

Assisted-by: Claude:claude-opus-5-5

* Say where a skill is when a read of it fails

When read_file, read_document or list_files fail with not found for a
path that names a skill of the chat (a wrong skills folder, or just
<name>/SKILL.md), the error now gives the skill's real path and says to
read it with read_file. The skills come from the chat's own resolver, so
every layer, add-on and per-user switch is respected, and nothing is
looked up unless a read fails.

Assisted-by: Claude:claude-sonnet-5-5

* Keep the last valid Sandbox network lists when a value is bad

The settings endpoint refuses a bad chats_egress_allowed_hosts with the
reason, and the runtime settings file keeps the value in force. A bad
value that reached the configuration another way was dropped with no
log line: the always-allowed hosts and the extra registries became
empty, and a bad port list fell back to 80 and 443, which can widen a
narrower list.

Each of the three lists now keeps the last value that parsed, logs a
bad value once, and uses the default only when the process never saw
a valid one. The parse runs again only when the value changes, not on
every egress.check.

Assisted-by: Claude:claude-opus-5-5

* Use the keyless chain of the built-in search in the Web add-on

The add-on replaces the built-in web_search, but its keyless provider
was DuckDuckGo alone. DuckDuckGo often answers data-center addresses
with a bot check, so installing the add-on without a key made search
worse than the built-in, which falls back to the Brave Search and Bing
result pages.

The keyless entry of the add-on's order (saved name duckduckgo) is now
the built-in chain from pkg/web/search: DuckDuckGo, then the Brave
Search page, then the Bing page, with the same cool-down. The status
tool reports the providers in their cool-down, and the Settings tab
shows them with the reason. Test the providers gives one row for each
page of the chain.

Assisted-by: Claude:claude-opus-5-5

* Fix the GitHub hosts in the Q1 row of the egress design

The Q1 row still listed raw.githubusercontent.com on the registries
list. The owner decision below it and registries.json exclude it,
since it serves any user content, and add
release-assets.githubusercontent.com. The row now says the same.

Assisted-by: Claude:claude-opus-5-5

* Keep one private-address rule for the network cards

A card asked whether its host is a private IP literal by calling
egress.Admits with a made-up ceiling, which re-derived the rule that
egress already has. egress.PrivateLiteral is now exported (with a spec)
and the card uses it. The two String methods of an allowed host write
host:port with net.JoinHostPort, which brackets an IPv6 literal the
same way the hand-written code did.

Assisted-by: Claude:claude-opus-5-5

* Read a unique constraint violation in one place

The jobs and triggers stores had the same isUniqueViolation, and the
saved agents store had the same test inline before it looked for the
name index. They now call dberr.IsUniqueViolation, which has specs for
the SQLite and PostgreSQL error texts. The workspace store keeps its
own stricter match.

Assisted-by: Claude:claude-opus-5-5

* Ask before a Home widget link opens another site

A list widget turned an http or https item into a plain link to a new
tab. Its data file is written by trigger runs and the assistant, which
read web text, so a planted link opened with one click, and only a
tooltip showed the host. A link of a page asks first.

An external item link now opens the confirmation bar of page links in
the widget: the site, the full address, the punycode warning, and Open
or Cancel. A link inside the app still navigates directly. The bar
takes a label, so the widget says that it wants to open the link.

Assisted-by: Claude:claude-opus-5-5

* Prune the audit of the commands run on this machine

The audit of the built-in bash had no retention: the database table
grew without bound in a cluster, with commands of up to 4 KiB each.
The Sandbox network audit had chats_egress_audit_days and a daily
prune under an advisory lock.

Both audits record what the commands of the chats did, so the host
command audit now uses the same retention and is pruned in the same
daily pass: one frontend of a cluster, under the same lock; a
standalone process alone. The GORM and file stores get Prune. No new
setting.

Assisted-by: Claude:claude-opus-5-5

* Save the Studio JSON stores with atomicfile.WriteJSON

Seven stores (agents, connectors, jobs, MCP connections, notifications,
push subscriptions and triggers) encoded their state and then called
atomicfile.Write with the same four lines. atomicfile.WriteJSON does
both and has specs. The load side stays in each store, since the error
messages differ.

Assisted-by: Claude:claude-opus-5-5

* Build the result page walkers of the keyless search on one walk

hasChallenge and firstByClass each had their own recursive walk that
stopped at the first match. They are now predicates passed to
firstElement, which already did that walk. The order of the walk and
the element tested first are the same.

Assisted-by: Claude:claude-opus-5-5

* Expire network cards that a dead frontend left pending

Pending network cards expired only on the turn-end path of the process
that ran the turn. When that frontend died, its cards stayed pending
in the chat record, counted toward the cap of three, and gave the next
turn's connections cards-full blocks. The UI showed them as waiting.

A card now names the turn that asked it. One rule, shared with the
command card in a later change, says whether a card still has a
waiter: its turn holds the chat and its wait has not run out. A card
that fails it reads as expired, takes no place under the cap, and is
expired in the record when the next card is asked, when the next turn
starts, or when the reaper ends the dead turn.

Assisted-by: Claude:claude-opus-5-5

* Reuse ChooseProvider for the expected add-on of a tool

shadowers.expected repeated ChooseProvider line for line: the pinned
add-on when it is installed, else the oldest install. It now calls it.
commandFiles kept an order field and sorted the nodes of a map by it;
it now appends each node to a list when it first sees it, which gives
the same order without the sort.

Assisted-by: Claude:claude-opus-5-5

* Do not print a nil error when a key or entry is missing

Three checks joined "the read failed" and "the read found nothing" in
one branch, so the second case wrote "<nil>" into the message: the
VAPID keys of push notifications, the sealing key of connectors and a
rendered catalog entry. Each case now has its own message. The message
of a failed read does not change.

Assisted-by: Claude:claude-opus-5-5

* Check the close errors and rename the tool variables

golangci-lint failed on the new studio code. Five deferred Close calls
and one Fprintf into a hash dropped their error, and two locals named t
made forbidigo read `t.Run` as a testing call. Discard the errors
explicitly and name the locals tool.

Assisted-by: Claude:claude-opus-5-5

* Make the file text index forget purged files and say its limits

Three gaps of the text index of documents:

- A purge dropped the index entries of what it erased in a goroutine
  that only logged its errors, and the purge had already erased the
  journal rows. A crash or a store error left the text in the database
  for good. Each pass of the indexer now also checks a batch of entries
  (200 every 30 s, round all of them) and deletes those whose node is
  gone, so what a failed Forget leaves is removed.

- A document search stopped at 20000 files or 64 MiB of text without a
  word, and the "still being indexed" count stopped at 50. The search
  now sets Limited (search_files says "results limited", the REST
  answer has "limited", the Files page shows a note), and the count is
  the number of pending entries below the path.

- read_file extracted a long document again for every page, up to 50
  MiB and 60 s each time. The first read keeps the whole text in the
  index store by content hash (a new documents table, or files in the
  JSON store), and the next pages come from it. The text goes away with
  the last entry of that content, on delete and on purge.

Search reads the text without its folded copy, which only the database
needs.

Assisted-by: Claude:claude-opus-5-5

* Stop the PDF reader when the extraction gives up

The PDF and EPUB reader runs in a goroutine, and the call returns after
60 seconds when it is slow. The goroutine went on reading every page,
since its context ended only with the caller's. It now gets a context
that ends when the call returns, so it stops at the next page. What
the call returns does not change.

Assisted-by: Claude:claude-opus-5-5

* Compare the code files of a shared page as the store does

The guard that refuses new code to a frame of an older version compared
the name it reads with the names of the page's code exactly. The
workspace folds case, so an old frame that read Index.html or JS/App.js
got the new code with no 409. Compare names in the store's form
(workspace.FoldName), as the write check already does, and test the
case variants.

Assisted-by: Claude:claude-opus-5-5

* Expire the command card of a turn that is over

The card of the built-in bash was cleared only by a defer in the call
that asked. When that frontend died, the card stayed in the chat
record. The chat hid it only while no turn ran, so the next turn
showed it again, and an answer to it reached no one but still got 204.

The card now names its turn and when it was asked, and follows the
same rule as the network cards: it waits only while that turn holds
the chat and its five minutes have not run out. GET /api/chats/{id}
shows only such a card. The next turn and the reaper clear a card left
behind, and the waiting call clears only its own card, so it never
removes a newer one. An answer to a card with nobody waiting is
410 consent_expired, and the chat shows the card as not answered, with
no buttons. The store gets UpdateHostConsent, an atomic change of the
card.

Assisted-by: Claude:claude-opus-5-5

* Answer a trigger change once across frontends

ApplyChange, UndoChange and DismissChange checked the outcome of the
change record under a mutex of one process, then wrote the store. Two
frontends could both see a pending change and both apply it, or both
undo it.

Add Store.SetOutcome, a conditional update of the outcome (only from
the outcome it names), to the GORM and JSON stores and to the store
suite. The three answers now claim the record with it before they
write, give the outcome back when the change itself fails, and answer
ErrProposalAnswered (409) when another request won. A test runs the
two answers on two frontends at the moment between the read and the
write, for an edit, its undo, and a delete.

Assisted-by: Claude:claude-opus-5-5

* Add the shadowers spec to the tables-tools inventory

The tool adapter gained a spec that lists the add-ons that replace a
built-in in any state. The tables-tools suite runs every spec of that
package, so verify.sh found one case more than the inventory holds.

Assisted-by: Claude:claude-opus-5-5

* Offer Clear filters when the backend Catalog shows nothing

The Installed view had a Clear filters button in its no-results state;
the Catalog view did not, although the spec asks for it in both. Move
the button to one place and show it in the Catalog when a search, a
type filter or a library filter leaves no row. Add Playwright specs for
both views, which the earlier Installed fix lacked.

Assisted-by: Claude:claude-opus-5-5

* Give the chat settings without an assistant tool their reason

chats_max_iterations, chats_work_folder, chats_index_files and
chats_index_max_text_bytes had no MCP tool and no entry in
adminRoutesWithoutTool, and the older chats_saved_agents,
chats_suggestions, chats_vision_model and chats_transcription_model
were unlisted too. Add each with the reason it stays a person's choice
in Settings: they apply to every user's chats, and the step limit is
one a model must not raise for itself.

Assisted-by: Claude:claude-opus-5-5

* Remove the stray allowed-hosts keys from the chats inbox locales

allowedHosts, allowedHostsOff and allowedHostsNote sat twice in eight
locales: under egress, where English has them and the UI reads them,
and again under inbox, where nothing reads them. In de and ko the two
copies had drifted apart. Delete the inbox copies and keep the egress
ones.

Assisted-by: Claude:claude-opus-5-5

* Bring three design specs in line with what shipped

- web tools and shadowing: the status still said phase 2 waits; both
  phases shipped. Note that the Web add-on's keyless entry is now the
  built-in keyless chain.
- Home front door: Home now creates the chat and sends the first
  message itself, with a short-lived hand-off to the chat page, and
  its composer takes attachments. Both were described the old way or
  as out of scope.
- chat footer: the meter bar is 96 px with the tokens left, and a phone
  keeps the bar and the tokens left, not the percentage only.

Assisted-by: Claude:claude-opus-5-5

* Store the command card's answer and read it back every two seconds

The answer to the command card of the built-in bash went only as a
bus message. When the message was lost, the call waited the full five
minutes and ended as not answered, although the person had clicked.
The network card stores its answer first and re-reads the card every
two seconds.

The command card now does the same, through one shared pair of
helpers: listenConsent subscribes before the card is stored, and
waitConsent wakes on the bus message or every two seconds and reads
the record, which holds the truth. The network card uses the same
helpers. HostExecDecide writes the decision to the card atomically
before it sends the message: the same answer twice is 204, the other
answer 409 already_answered, and an answered card is no longer shown
as waiting.

Assisted-by: Claude:claude-opus-5-5

* Load skills by name with a load_skill tool

A weaker model failed to read a skill at the path the index showed. The
chat now has a built-in load_skill tool that takes a skill's name and
returns the instructions of its SKILL.md, without the frontmatter.

The tool reads the same resolved skill set as the index: the nearest
skill of each name, the chat's switches, the add-ons the chat can use
now and the grants of its agent. It reads through the user's rights.
When the skill's folder holds other files, the answer starts with the
base directory and names up to 20 of them for read_file; a chat without
read_file gets the instructions only. A skill that needs commands, in a
chat that cannot run them, is refused with the reason. An unknown name
is an error that gives near names first and then every name the chat
has.

Every chat with at least one skill gets the tool, and a sub-agent gets
it with its parent's tools. It has no switch and Settings > Tools does
not list it.

The index of skills now lists names and descriptions only and tells the
model to call load_skill. The Sandbox sentence and the error for a
wrong skill path now point at load_skill too.

Assisted-by: Claude:claude-opus-5-5

* Tell the built-in skills to load other skills by name

localai-apps told the model to read the localai-workspace skill, and
writing-skills said a description is what the agent sees before it
opens the file. Both now speak of loading a skill with load_skill.
localai-workspace keeps the path of its schemas folder and says to read
it with read_file, since those files are not a skill.

A test checks that no built-in skill sends the model to another skill by
"read" or by the path of its SKILL.md.

Assisted-by: Claude:claude-opus-5-5

* Document load_skill and the skills index

The chats page now says that the prompt lists skills by name and
description, that load_skill returns a skill's instructions and names
the files of its folder, what it refuses and who gets it. It no longer
says the model reads a skill by its path. The add-ons page says how a
chat loads an add-on's skill, and the saved agents page says that the
skills grant limits load_skill too.

Assisted-by: Claude:claude-opus-5-5

* Add the proposal action spec to the tables-acceptance inventory

The spec that an editor cannot confirm a schema change as a write ran in
the suite but was never in the inventory, so the evidence manifest check
failed. CI did not reach that check before, because the burst spec
failed first.

Assisted-by: Claude:claude-opus-5-5

* Give a chat a goal that it works toward by itself

A chat can now hold one goal. While it is active, every turn's prompt
names it, the model gets goal_done and goal_blocked, and when a turn
ends by itself the frontend that ran it starts the next one with
"Continue toward the goal". The person's waiting messages still go
first, and a turn they start does not count as an automatic one.

The goal pauses when the person presses Stop, when a turn fails or is
cut short, and when the automatic turns or the model steps reach their
limits. Resume gives it fresh budgets. A sub-agent, and a chat that a
trigger, a connector, a job or a page started, has no goal and no goal
tools.

The goal lives with the chat record in the store (UpdateGoal on the
JSON and GORM stores, with contract tests and a column migration), so
every frontend reads the same one. The next turn goes through the same
turn claim as any other, so only one frontend continues it; a reaped
turn, or a JSON store that reloads after a crash, leaves the goal
paused instead of continued twice. The transcript keeps goal lines
(set, replaced, continue, paused, resumed, done, blocked, cleared) as
their own role, so an automatic message never reads as typed by the
person.

Assisted-by: Claude:claude-opus-5-5

* Add a store for the loops of the chats

A loop repeats a prompt in one chat, at an interval or when the model
asks for the next run. The new loops package keeps the loops, the
daily budget of runs of each owner, and which chats confirmed a loop
once. JSON and GORM stores share one contract suite. Add checks the
limits per chat and per owner in the same step as the insert, and
TakeRun never hands out the last run of a day twice, also across
frontends.

A user message that a loop sent now carries a loop mark (loop ID, run
number, self-paced or not). Both chat stores keep it. The model reads
a short line before the prompt that says the message repeats by
itself, and, for a self-paced loop, how to ask for the next run.

Assisted-by: Claude:claude-opus-5-5

* Add the file preview slot specs to the host-slots inventory

The file preview slot came with two Go specs in the host-slots package.
verify.sh found them in the run but not in the inventory.

Assisted-by: Claude:claude-opus-5-5

* Check the Settings page and the add-ons with the UI copy guard

The guard read the locale files only. The Settings page keeps its
English labels and descriptions in settingsSchema.js, and several
add-ons carry their own English bundle, so neither was checked.

The guard now also reads the label, description and note of every
setting and the label and hint of every group, and the English
bundles of the add-ons (an en.js module or an English JSON file).
The allow-list takes settings:<key>.<what> and addon:<id>:<key>
entries, each with its reason; the operator ones (the SearXNG JSON
format, the fine-tuning file types, the API route of a voice, the
schema of the Databases add-on) are listed.

What it found in the voice library is fixed in plain words: "model
YAML is not modified" and "Existing model YAML is not changed" now say
that the models' settings are not changed, in the voice add-on, the
Studio add-on and the host locales that have the strings (en, fr,
pt-BR). The two host allow-list entries for them go.

Assisted-by: Claude:claude-opus-5-5

* Add the update digest specs to the updates inventory

Two checker specs pin that an update names its candidate digest and
that a stale cached notice stays readable. The updates suite runs the
whole checker package, so the inventory needs both.

Assisted-by: Claude:claude-opus-5-5

* Draw the Add-ons search and state filter with the kit pieces

The Add-ons page had its own copy of the search box and the segmented
filter (ad-search, ad-seg), the same shapes and styles as the kit's
SearchField and Segmented that the Agents pages use. Use the kit
pieces and drop the copy; the narrow-screen rules now target the kit
classes inside the toolbar. The search keeps its test id.

Assisted-by: Claude:claude-opus-5-5

* Add the limits of a chat goal to the runtime settings

chats_goal_max_turns (1 to 200, default 20) is the most turns a chat
with a goal starts by itself, and chats_goal_max_steps (1 to 10000,
default 400) the most model steps of all the turns of one goal, before
the goal pauses. Both are read when a turn ends, so they apply without
a restart. They sit in Settings > Tools next to the step limit of one
turn, and the settings page documents them.

Assisted-by: Claude:claude-opus-5-5

* Add the goal routes of a chat to the API

GET, PUT and DELETE /api/chats/{id}/goal read, set and clear a chat's
goal, and POST /api/chats/{id}/goal/resume resumes a paused or blocked
one. They belong to the chat's owner like the other chat routes and
take the chats feature. A chat view carries the goal with the limits
that apply now, the transcript gives goal lines with goal_event and
goal_turn, and the event stream has a goal event so that other tabs
read the chat again.

The routes are in the route feature registry, the swagger file and the
chats entry of /api/instructions. They manage the person's own chat,
not the server, so they have no MCP tool, as the other chat routes. The
chats page documents goals, their states and limits, and how several
frontends share them.

Assisted-by: Claude:claude-opus-5-5

* Redesign the notification inbox

The inbox panel was a plain list: every row had the same weight, a
failed run looked like a finished one, the panel ran off the screen on
a phone, and a failed load showed nothing.

The panel now has a header with the unread count, a menu for Clear read
and Clear all, Mark all read, and an All / Unread / Failed filter. Items
are grouped under Today, Yesterday and Earlier. Each item shows what
sent it (trigger, connector or LocalAI) with a tinted icon, the title,
two lines of text or the reason of a failure, and when it happened, with
the exact time on hover. A click marks it read and opens its chat; a
connector that was switched off opens the connectors page. Mark read and
Delete show on hover or focus, and stay in view on a touch screen.

The panel has a loading skeleton, an error with Try again, an empty
state that says what shows up here, and a caught-up state. A new
notification slides in, is highlighted for a few seconds and is
announced once. The badge stops at 99+. Focus moves into the panel when
it opens; the arrow keys, Home, End and Delete work on the items, and
Esc returns focus to the button. On a phone the panel is a sheet over
the bottom of the screen with 44 px targets.

Assisted-by: Claude:claude-opus-5-5

* Explain the reads of the text index and the provider requests to gosec

gosec flagged three new lines. The text index reads files from the
directory the host gave it, with names it listed there. A search
provider sends its request to the endpoint fixed at construction, never
to a URL from a tool call. Mark the lines with the reason.

Assisted-by: Claude:claude-opus-5-5

* Keep the add-on details open when Escape closes a dialog

Escape in the restore dialog of the recovery panel also closed the
details pane around it. The pane handles Escape in React, and the
dialog listens on the document, so the pane ran first and saw no
preventDefault. The pane now registers as a modal layer and closes only
when it is the top layer, as the side panes do.

Assisted-by: Claude:claude-opus-5-5

* Add skill and agent messages, compact and clear to the chats API

A message can now carry a skill of the chat or one of the user's saved
agents. The server checks the name against the chat's resolved skill
set (switches, the agent's grants, shadowing, add-ons) or the saved
agents the chat may call, and refuses an unknown one with a 400 that
lists what the chat has. A skill message gives the model the text of
the skill's SKILL.md before the user's words, for that turn only; an
agent message asks the model to start the agent with spawn_agent. The
transcript keeps the words and the command (Entry.Invoked), not the
instructions. A regenerate or an edit runs the command again. Such a
message does not wait for a running turn: it answers 409.

POST /api/chats/{id}/compact runs the summary the loop makes when the
context fills up, through a new optional session.Compactor that the
loop harness implements with its own history compaction. The compacted
state is saved for the next turn and a "compacted" line with the sizes
goes in the transcript.

POST /api/chats/{id}/clear writes a "cleared" line and drops the saved
state. The model then sees nothing above the line: the rebuilt state
and the transcript summary start after the last such line, so a fork
from above it keeps what the model saw there. Export, import and the
Markdown export carry both lines.

Both calls take the turn claim, so no frontend starts a turn on the
chat meanwhile; messages sent during them start a turn after. No MCP
tool: they act on one chat of the caller and are not admin calls.

Assisted-by: Claude:claude-opus-5-5

* Give each network card spec its own settings

A check that a card spec starts can still wait on its card when the
next spec begins. It read the settings through a closure over a
variable that the next BeforeEach replaced, which the race detector
reported. Each service now reads the settings holder it was built with,
under a lock, and the specs change the settings through it.

Assisted-by: Claude:claude-opus-5-5

* Show the effective audit retention in the settings snapshot

The settings snapshot returned 0 for chats_egress_audit_days while the
setting was unset. Any page that saves the whole snapshot back, such as
the Traces settings strip, then posted 0 and the server rejected it with
"Invalid chats_egress_audit_days", so saving tracing settings failed on a
fresh install.

Report the retention that applies (30 days by default), the same way
chats_max_iterations does.

Assisted-by: Claude:claude-sonnet-5-5

* Run the Sandbox smoke test in a short scratch folder

The smoke test step was reached for the first time and both isolated
backends refused to start: their state folder under the checkout's
cache made the socket paths 126 and 132 bytes, over the 107 a unix
socket allows. Point SANDBOX_SMOKE_WORK at /tmp/sandbox-smoke, which
leaves room for the sockets.

Assisted-by: Claude:claude-opus-5-5

* Use paths from the home folder in the Sandbox command specs

bash now starts in the user's home folder, so the end-to-end specs that
read and wrote home/<name> found nothing. Use names relative to the
home folder, as the Sandbox specs already do.

Assisted-by: Claude:claude-opus-5-5

* Show the goal of a chat on the chat page

A bar above the composer shows the goal with its state: Pause (which
stops the running turn and so pauses the goal) while it works, Resume
when it paused or needs the person, and Clear. A second line says why
it paused, what the model needs, or what it did. The status line shows
"Goal · turn 3 of 20" while the goal is active, and the Continue button
of a paused turn stays away then, since the next turn starts by itself.

The transcript shows the goal lines as quiet rows: set, replaced,
continuing (with its turn), paused with the reason in plain words,
resumed, reached with the summary, blocked and cleared. A goal event,
also from another tab, reads the chat again, and a hidden live region
says each change to a screen reader once.

The strings are in all nine locales. Unit tests cover the helpers and
the thread rows; a Playwright spec covers the bar, the progress, the
lines, Pause, Resume, Clear and the event.

Assisted-by: Claude:claude-opus-5-5

* Run the loops of the chats

The loop host fires the loops that are due. A run sends the prompt to
the chat as a new message only when the chat is idle: a busy chat
skips the run, and an interval loop moves to its next slot instead of
piling missed runs up. A self-paced loop gets two tools while it is
active: schedule_next (clamped to the minimum interval and one day)
and loop_done. A run in which the model calls neither ends the loop
with a note. A loop ends after its run limit, pauses after three
failed runs in a row, and waits for the next UTC day when the owner's
daily budget of runs is used up.

One frontend fires the loops, the holder of a new advisory lock. A run
is claimed in the store first, and the turn claim keeps one turn per
chat, so a short overlap of two leaders starts no run twice. A new
leader finishes the runs the old one watched. Deleting a chat removes
its loops; a due loop whose chat is gone removes itself.

Five runtime settings bound the loops: chats_loop_min_interval,
chats_loop_max_runs, chats_loop_max_per_chat, chats_loop_max_per_user
and chats_loop_daily_runs.

Assisted-by: Claude:claude-opus-5-5

* Add the loops API of the chats

GET, POST and DELETE /api/chats/{id}/loops list, start and stop the
loops of a chat; PUT and DELETE /api/chats/{id}/loops/{loopId} pause,
resume, confirm or stop one. GET /api/chats/{id} carries the loops,
the transcript marks the user lines a loop sent with loop {id, run},
and a loops event tells every open tab that the list changed.

The routes are gated by the chats feature and documented in the
swagger spec and the API instructions. They act on the caller's own
chats only, so they get no assistant tool. The chats page gets a loop
section, with when to use a loop and when a trigger, and the cluster
behaviour; the runtime settings page lists the five loop settings.

Assisted-by: Claude:claude-opus-5-5

* Show the loops of a chat above the message box

Each loop of the open chat shows as one line over the message box,
such as "Loop · every 5 min · run 4 · next at 09:20", with Pause or
Resume and Stop. A loop that paused itself or ended says why; an
ended one has Dismiss. The first loop of a chat shows a card instead:
"Run this every 5 minutes until you stop it?" with Start and Cancel.
The server keeps the pending loop, so a reload shows the card again.

A message that a loop sent carries a small "Loop run 4" label. The
page reads the loops again on the loops event, so every open tab
follows. The answer to /loop list is ready for the slash command. The
strings are in all nine locales.

Assisted-by: Claude:claude-opus-5-5

* Build the chat slash menu on one command registry

The slash commands of Home and of a chat now come from one registry,
src/utils/slashCommands.js. A command has a kind (navigate, insert or
server), the surfaces that offer it, a needs check and, optionally, an
argument provider: args(query, ctx) returns the items the menu lists
when the box holds "/cmd <query>". Every existing command and test id
stays; the registry adds:

- one command per skill of the chat or the draft (/review), marked
  built-in, add-on, shared or yours, and /skill <name>, which also
  reaches a skill named like a command;
- /agent <name> <task>, which lists the saved agents, or offers to turn
  them on for the chat when they are off;
- /model and /models with a model name, which switch at once;
- /compact and /clear, which show their progress in the status line
  and leave a marker in the thread; the context meter drops;
- /attach and /attach clear, /help (a card that lists the commands)
  and /about (a card with the model, its state, the tools, skills,
  where commands run and the context size).

Tab completes a command or an argument, Enter runs it, and the first
row whose name starts with what was typed is selected first. A message
typed as a skill or agent command is sent with its marker, not as text;
the transcript shows the words and a chip. Home offers the same set
without the commands that need a thread.

The words are in all nine locales. The registry has unit tests, and a
Playwright spec covers the menu, the completion, the marker, the chip,
compact, clear and the cards with the routes stubbed. The docs page
gains a slash commands section.

Assisted-by: Claude:claude-opus-5-5

* Add the /goal command to the chat

/goal shows a card with the goal, its state, the automatic turns and
steps it used out of the limits, and when it was set. /goal <text>
sets a new goal at once, replacing the one the chat had without a
question, and the goal bar says what it replaced. /goal clear and
/goal resume act on the goal; typing "/goal " lists resume and clear
for the goal the chat has. None of these is sent as a message. In a
new chat, /goal <text> creates the chat first.

The command sits in the Context group of the shared command registry,
on the chat surface only, and not in a chat that a trigger or another
run started. A skill named goal is reached through /skill. Unit tests
cover the parser and the menu items; the Playwright spec covers the
card, setting, replacing, resuming and clearing from the box.

Assisted-by: Claude:claude-opus-5-5

* Add /loop to the chat

/loop [interval] <prompt> starts a loop in the chat; /loop list shows
the loops of the chat with the code that /loop stop takes, and
/loop stop [id] stops one or all. The command is in the slash
registry: after "/loop " the menu offers list and stop, and after
"stop " the loops of the chat.

A loop prompt that invokes a skill (/review the diff, or
/skill review the diff) runs as the person's skill command would: the
model gets the skill's text, and the transcript shows the words, the
skill's chip and the loop label. The server checks the skill when the
loop starts and at each run; any other command is refused with the
reason.

Assisted-by: Claude:claude-opus-5-5

* List the loop settings on the Settings page

The five limits of the loops of the chats show under Tools with the
other chat settings: the shortest interval, the runs per loop, the
loops per chat and per user, and the loop runs per day. All apply at
once.

Assisted-by: Claude:claude-opus-5-5

* Clear a sent Home draft when the page goes away too

Home clears the draft of a sent message when it closes, so the text
stays visible while the composer moves into the new chat. While the
chat page still loads, a reload or a closed tab could come first, and
the sent text came back on Home. Leaving the page now clears it too.

Assisted-by: Claude:claude-opus-5-5

* Check the close error of a previewed file

golangci-lint (errcheck) flagged the deferred Close of the file the
preview endpoint reads. Discard its error explicitly, as the other
studio file handlers do.

Assisted-by: Claude:claude-opus-5-5

* Explain the document read of the text index to gosec

gosec reported the read of a stored document text as a file inclusion
through a variable. The path is the configured index directory joined
with a hash that documentPath refuses when it holds a path separator
or a dot, so it cannot leave the documents folder.

Assisted-by: Claude:claude-opus-5-5

* Build the darwin/arm64 add-on packages on macos-15

GitHub retires the macos-14 runner image on 2026-11-02 and runs
scheduled brownouts until then: every darwin/arm64 package job failed
at once with the brownout notice. macos-15 is the Apple Silicon image
that replaces it.

Assisted-by: Claude:claude-opus-5-5

* Expect the chat's own load_skill tool in the agent prompt spec

The spec that keeps the agent engine's text out of the prompt also
required that no load_skill tool or mention reach the model. Chats now
offer their own load_skill tool and the skills index tells the model to
call it, so the spec failed. Keep the checks on the engine's own skill
and command text, and check that the chat's tool is offered.

Assisted-by: Claude:claude-opus-5-5

* Read the user's scripted tool call in the mock model

The chat prompt now names the chat's work folder, and the folder name
comes from the chat title, which holds a cut copy of the user message.
The mock model read the first ADDON_TOOL_CALL marker, the cut one in the
system prompt, and called the tool with broken arguments over and over.
Read the last marker, the one of the user message.

Assisted-by: Claude:claude-opus-5-5

* Keep the phone targets of the inbox at 44 pixels in every build

On a phone the inbox close button and the item actions must be 44
pixels wide. Their rule had the same weight as the kit's .dk-btn
min-width, so the order of the stylesheets decided. The single-chunk
coverage build puts the kit later and the close button shrank to 28
pixels. Scope both rules to their container so they win in any order.

Assisted-by: Claude:claude-opus-5-5

* Let the about-you spec accept the sidebar's own seen date

When the user has pages, the sidebar writes the date of its New label
under seen.new in user.json. In the whole suite other specs make pages
first, so the saved record held that date as well and the exact
comparison failed. Check that the uploaded seen record is kept.

Assisted-by: Claude:claude-opus-5-5

* Give the typed-while-working chat spec time for two turns

The spec waits up to 30 seconds for each step, but two turns of the
mock model with its tool steps take about 28 seconds on their own, so
the default 30 second test limit cut it under load. Set its limit to
90 seconds.

Assisted-by: Claude:claude-opus-5-5

* Scope the foundation spec's state query to the sheet header

The details pane now repeats the observed state under Health, so a
role query for "State: Off" inside the add-on sheet matched two
elements and failed in strict mode. The administrator-manages spec,
and the two specs after it, did not run.

Query the chip in the header (.ad-pane__meta), which is the state the
administrator sees next to the add-on's name, through one helper used
for all three assertions.

Assisted-by: Claude:claude-sonnet-5-5

* Wait for the page to read each apps answer in the registry polling spec

The spec moved the page clock as soon as the stand-in saw a request.
The registry sets its next timer only after it reads the answer, so on
a slow runner the clock could pass the due time of a timer that did not
exist yet, and the next read never came. With the CPU throttled ten
times, the old spec failed in 3 of 3 runs.

The spec now counts the answers the page has read and lets queued work
finish before it moves the clock. It pauses the clock before it leaves
the page, and it tries the pause again when a slow machine passed the
target time. The assertions do not change: one read at once, one read
per interval and no faster, and no read after the disable.

Assisted-by: Claude:claude-opus-5-5

* Close the egress test listener only after it accepts

The dial helper of the egress proxy specs closed its listener when it
returned, while the goroutine that accepts the connection could still
be waiting to run. On a loaded runner the listener sometimes closed
first. The kernel then reset the connection that was still in the
accept queue, the spec's write consumed the reset error, which the
spec ignores, and the next read saw EOF. The spec failed with
"unexpected EOF" before the proxy got the request.

Wait for Accept to return before the listener closes, then start the
proxy handler on the accepted connection.

Assisted-by: Claude:claude-opus-5-5

* Run host commands in a shell that reads no startup file

The host backend promises a fixed environment, but bash -lc reads
/etc/profile and the user's dotfiles. On macOS path_helper rewrote PATH
there, so the command did not get the fixed PATH. Turn the login shell
into 'bash --noprofile --norc -c' in the host backend only, and make the
test assert the exact fixed PATH.

Assisted-by: Claude:claude-sonnet-5-5

* Answer the command card in the platform turns and 400 a bad answer

The tool-list spec of the platform suite timed out: without accounts
the one person is an administrator, so the chat has the built-in bash
in ask mode. The tool list is sorted and bash is first, and the mock
model calls the first tool, so every turn waited five minutes for a
yes on the command card. The turn helper now refuses each card it
sees, as a person who clicks deny, and the turn goes on to its step
limit. bash stays in the checked list.

An administrator who posts a consent with no card id or an unknown
decision got 403 "only an administrator can allow commands". That is
a bad request, not a refusal: it now answers 400, as the swagger
already says, and the route check for administrators passes.

Assisted-by: Claude:claude-opus-5-5

* Let a chat switch off its shell, file, media, collection and sub-agent tools

The Tools menu of a chat switched only three groups of built-in tools:
web, saved_agents and triggers. A person could not keep a chat away
from the shell, the files, the helper models, the collections or the
sub-agents.

Add five groups to the registry of built-in tools, all on until the
chat switches them off:

- shell: bash, whoever serves it. The Sandbox add-on's bash and the
  built-in bash on this machine both go, and the add-on list reports
  commands switched_off. The row stays listed when nothing can run
  commands, not usable, with the reason.
- files: the file tools and read_document.
- media: describe_image and transcribe_audio.
- collections: list_collections and search_collection, usable only
  for a user with the collections feature.
- subagents: spawn_agent. list_agents and /agent follow it.

The registry gets two flags. External marks a tool that its own code
builds for the turn (with the wrappers it needs); the registry lists it
in its group and Hidden tells the builder what the chat switched off.
Covers makes a group's switch also hide the add-on tool that replaces
the built-in one. PUT .../builtins, the panel, the draft list and the
fallbacks use the existing group code.

A sub-agent follows the switches of its parent chat. The turn prompt
is built from the final tool list: no file tool names, no skill
writing hint, no work folder and no rules pointer when the chat cannot
use files, no describe_image when the helper is off, and a commands
block that says the person switched commands off.

Assisted-by: Claude:claude-opus-5-5

* Queue the edited chat message after the first step starts

The spec queued its message as soon as the chat showed a busy state.
The turn is busy before its first model request starts, and that
request takes every message that waits. With the chat's tools and
skills, the first request now starts a few hundred milliseconds after
the turn, so the message went with it, and the edit got 409 "already
delivered" (5 of 6 local runs).

Wait until the answer streams, as the Stop spec does: the request is
running then, and the queued message waits for the next step.

Assisted-by: Claude:claude-opus-5-5

* Give the reload chat spec a turn that outlasts the reload

The spec reloaded the page during a 3 second turn and expected the
page to show the turn still running. A reload of the coverage build
on a busy runner takes 4 to 5 seconds (measured with a 6x CPU
throttle), so the turn had ended before the page could show it. With
the 30 second turn the page always showed it running, so the resumed
state works and only the window was short.

Add MOCK_LONG_STREAM_MEDIUM to the mock model, a turn of about 10
seconds, and use it in the spec with a 60 second limit.

Assisted-by: Claude:claude-opus-5-5

* Wait for the chat page after the Home hand-off in the specs

Send on Home changes the address inside a view transition, and the
chat page mounts about 35 ms later. Specs that waited only for the
address acted on Home in between:

- The title spec pressed Ctrl+K at once, because the server names a
  chat after its first message as it arrives, so the title poll ends
  at once too. The key reached the page before the chat page listened,
  and the menu did not open (3 of 3 presses at 0 ms failed, all at
  300 ms and later passed).
- The Back spec went back before the chat page was drawn. Home was
  never closed, so its draft of the sent message stayed in the box.

startChat now waits for the chat page, the title spec for the title
in the chat header, and the Back spec for the chat page before Back.

Assisted-by: Claude:claude-opus-5-5

* Accept a resolved user.json conflict in the quiet page specs

The sidebar notes in the seen record of user.json the first day it
labels Pages as new, and saves it from the version it read. All specs
share the test server's one user, so tabs of other workers save the
same record at the same time: one gets 409 and useSeen reads the file
again and saves once more. Three tabs that open /app/files at once
give 200, 409, 200. The quiet check of the shell pages counted the
409 as a problem.

Ignore a 409 on PUT /api/chats/wellknown/user in that check.

Assisted-by: Claude:claude-opus-5-5

* Check only the spec's own items in the Trash after the reload

After Empty Trash and a reload, the spec expected the whole Trash to
be empty. The Trash belongs to the test server's one user, and specs
of other workers move files to it meanwhile, so CI saw "In the Trash:
3 files, 356 B." after the reload.

The checks right after Empty Trash stay. After the reload, check that
the server's Trash, the Trash tab and Files do not hold the spec's
items, once each list has loaded.

Assisted-by: Claude:claude-opus-5-5

* Show the new tool groups in the chat Tools menu

The Tools menu lists the groups of built-in tools that the server
sends. The five new ones need words and an order, and the shell row
needs to say who runs the commands.

Name the groups in all nine locales (Run commands, Your files, Images
and audio, Collections, Sub-agents) and order the rows by what they
reach: the shell and the files first, the triggers last. The shell row
carries a chip with the provider (Sandbox or This machine) and a line
under it that says the commands run isolated, or a warning when they
run on this machine. When nothing can run commands the row is disabled
with the words of the commands notice. A switched-off sub-agents group
also turns /agent off in the composer.

The specs cover the rows, the off and on requests, the bulk actions,
the provider chip, the disabled reasons, the draft on Home and a real
server round trip.

Assisted-by: Claude:claude-opus-5-5

* Document the groups of built-in tools a chat can switch off

The Tools menu section described only the web, triggers and saved
agents groups. List every group with its tools, say which groups the
server may leave out and why a row can be not usable, how Run commands
covers both providers, what the model is told when a group is off, and
that a sub-agent follows its parent's switches.

Assisted-by: Claude:claude-opus-5-5

* Fix the host command consent spec for the 400 contract

The consent route answers 400 for a body without a card id or with a
decision other than once or deny, whoever asks. The spec still expected
403 for always from an administrator. Cover the malformed answers for
an administrator and a user, each in their own chat, keep another
user's chat at 404, and say it in the chats guide.

Assisted-by: Claude:claude-sonnet-5-5

* Find the web tool group by name in the route spec

The tools panel lists the shell group before the web group, so the
spec that read the first entry compared the wrong group. Look the
group up by name, which does not depend on the registry order.

Assisted-by: Claude:claude-sonnet-5-5

* Give Skills its own sidebar item

Skills work in every chat, but the sidebar filed the page under Agents
and only agent skill chips linked to it. Add a Skills item right after
Memory, show it in the legacy list too, and stop lighting up Agents on
the skills pages.

Assisted-by: Claude:claude-sonnet-5-5

* Add Manage skills to the skills picker and a /skills command

The picker now ends with a Manage skills link, and /skills opens the
Skills page from the composer on Home and in a chat. The picker keeps
the height of its status line, so a refused change does not move the
rows. Words are added in all nine locales.

Assisted-by: Claude:claude-sonnet-5-5

* Say on the Skills page that every chat can use skills

The page subtitle named only agents as users of skills. Say that all
chats use them, translate it, and document where to manage skills: the
sidebar item, the picker link and /skills.

Assisted-by: Claude:claude-sonnet-5-5

* Keep Home on screen while its widgets load their strings

A Home widget reads the pages strings, and i18next loads a namespace
the first time a component asks for it, by suspending. Home had no
Suspense boundary of its own, so the route's boundary hid all of Home
(display: none) and showed the route fallback until the strings came.

A widget shows only after home.json is read, so this happened after
the composer was already drawn. Focus given to the composer in that
window went nowhere, and a key typed then was lost. The slash menu
spec failed in CI this way when another spec had written widgets to
the shared home.json: the box was empty and the body had the focus.
With widgets in home.json the composer was hidden right after it
appeared on 5 of 5 loads, and the spec failed 1 or 2 times in 5.

The examples and the widgets now have their own boundary with no
fallback, so only they wait. A new spec holds the pages strings while
it types in the composer; it fails without the change (the composer
never takes the focus) and passes with it.

Assisted-by: Claude:claude-opus-5-5

* Send the stubbed file change after the Files page read the folder

The change feed spec answered the first stream request with the change
at once. The app shell (the appearance sync) opens the shared stream
when the app starts, before the Files page chunk has loaded, so on a
slow runner the change reached a tab where nobody watched the folder
yet and was dropped. The page then never read the folder again, and
the spec failed on all three CI attempts. A CPU throttle of 8 makes it
fail 3 of 3 times locally.

On a real server the page's own first read would already show such a
change. The stub now holds the change until the page has read the
folder; the page subscribes in the same commit as that read, so the
change arrives with a subscriber in place. The resume check is kept.

Assisted-by: Claude:claude-opus-5-5

* Give the oversized 3D input as a sparse file, not a buffer

The spec built a 32 MiB buffer and passed it to setInputFiles.
Playwright sends a buffer to the browser over the protocol: that step
alone took 5.5 s on an idle machine, and on the loaded CI runner the
test hit the 30 s timeout on all three attempts.

It now writes a sparse file of the same size to the test output folder
and passes its path, which the local browser opens as is. The page
still checks the size before it reads the file, so the toast and the
no-request assertion are unchanged. The step takes milliseconds.

Assisted-by: Claude:claude-opus-5-5

* Check the tool line, not the tool name, in the tool call journey

The spec looked for /list_files/ in the transcript. The user's own
message holds that name, so the check could pass before any tool ran.
Once the model's call streamed, a second element matched, and the
strict locator failed (2 matches on the first attempt, 5 on the
retry).

It now waits for the activity line that the tool run adds ("Listed
/"), which only shows after the tool ran.

Assisted-by: Claude:claude-opus-5-5

* Measure the proposal card and its neighbours in one frame

The layout spec read the boxes of the message text, the card and the
message actions with three boundingBox calls. They are viewport
positions taken in three frames, and the transcript scrolls to its end
while the card fills in. On the phone the actions were read after a
scroll and came out 156 px above the bottom of the card.

The three boxes now come from one page.evaluate, so they are read in
the same frame. The order assertions are unchanged.

Assisted-by: Claude:claude-opus-5-5

* Read the page fixture time when the page is served

The task board fixture of the discovery and Pages specs set its
change time once, when the file loaded. A worker loads it once and
keeps running specs, so a spec that ran two minutes later read
"Changed 2 minutes ago by the assistant" where it expects "just now".

The change time is now a getter, read when the fixture is serialized
into a response.

Assisted-by: Claude:claude-opus-5-5

* Check a background process without /proc in the host test

The alive helper read /proc/<pid>/stat, which macOS does not have, so it
reported every process as dead and the spec failed there with "did not
survive the suspend". Use signal 0 for existence and ps (or /proc where
present) to tell a zombie from a live process.

Assisted-by: Claude:claude-sonnet-5-5

* Keep the composer switch menus at their own height

The base rule of the dropdown menu caps it at 320px and lets it scroll.
The switch menus set their own height with a rule of the same weight in a
lazy sheet, so which one won depended on the order the sheets loaded in.
When the base rule won, the picker showed a few rows, and a click on a row
at the edge of the list scrolled the list by a few pixels.

Double the class on the switch menu rules so they win in any order, and
add a test that loads the base rule last.

Assisted-by: Claude:claude-sonnet-5-5

* Show what applies in the chat Network switch

The Network row highlighted the choice stored with the chat, so a
chat that asked for All public sites under an administrator limit of
Off showed All highlighted although it was disabled and not in effect.

Highlight the effective choice, the lower of the chat's choice and the
limit, which the server already computes. When the chat asks for more
than the limit, say so in one line instead of highlighting it. Add a
line that the limit is set by the administrator, and tell the host
network line that limits need the Sandbox add-on.

Assisted-by: Claude:claude-sonnet-5-5

* Design the host components that add-ons reference

The host UI names the Sandbox and the Web add-ons to place their server
settings, and the chat's Network row links to the global Settings page.
Describe a closed registry of host components that an add-on references
by ID in its manifest, entitled by the existing host operation grants
and tool shadows, so the controls live on the add-on's own page and a
second add-on can reuse them with no host change.

Assisted-by: Claude:claude-opus-5-5

* Let an add-on ask for host controls in its manifest

An add-on had no way to say that a host-owned control belongs on its
page, so the host UI placed those controls by add-on name. Add
ui.controls, a list of IDs from a closed registry of host controls:
network-policy (the network of the commands an add-on runs) and
tool-providers (the rows of the built-in tools it replaces).

The host decides which controls it draws: EntitledControls keeps a
control only when the add-on holds its host operation grant and
replaces its built-in tool. The field is optional, so every existing
manifest stays valid.

Assisted-by: Claude:claude-opus-5-5

* List the host controls an add-on is entitled to

The apps list now carries ui.controls with the host controls the
manifest declares and the host setting entitles the add-on to: the
manager passes each add-on's host operation grants to the list.

GET /api/chats/{id}/egress gains addon, the add-on that runs the chat's
commands when it has the network-policy control, so the chat can draw
its Network row from that add-on and link to its settings. applies and
applies_reason keep their meaning: the policy holds with or without the
control. The model and the 400 error no longer send an administrator to
Settings > Tools for the limit.

Assisted-by: Claude:claude-opus-5-5

* Draw the host controls on the add-on's own page

The host UI placed the Sandbox network and the tool rows by add-on name
(SERVER_SETTINGS), showed a read-only summary on the add-on's Settings
tab, and linked the chat's Network row to the global Settings page.

Add a registry of host controls keyed by the IDs of the contract. The
Settings tab of an add-on draws, below its own sections, the controls
the apps list gives it, in one form with the pending bar of the
Settings page: network-policy reuses the network section and its
setting rows, tool-providers the rows of the built-in tools the add-on
replaces. The chat draws its Network row only when the server names an
add-on with network-policy, and the administrator link opens that
add-on's tab. The row itself is unchanged.

The Settings page keeps the settings of features that exist without an
add-on, points to the add-on where one serves them, and no longer
lists the network settings. Its old address opens the add-on's tab.

Assisted-by: Claude:claude-opus-5-5

* Ask for the host controls in the Sandbox and Web manifests

The Sandbox asks for network-policy and tool-providers, so the network
of its commands and the bash row are drawn on its own Settings tab and
its chats get the Network row. The Web add-on asks for tool-providers
only: it holds no egress grant. The manifest tests check that the
default grants entitle each add-on to what it asks for.

The proxy's refusal now sends the model to the Sandbox Settings tab
instead of Settings > Tools.

Assisted-by: Claude:claude-opus-5-5

* Keep the button of the network pointer row at its size

The row used the wide layout of the tool rows, so its Open settings
button stretched across the page. Use the plain setting row, which
puts the button on the right like the other controls.

Assisted-by: Claude:claude-opus-5-5

* Fix the add-on contract inventory and the apps Swagger fixture

The contracts case inventory missed the six host control specs, so
verify.sh rejected the Ginkgo report. List them.

The Swagger spec test never saw `controls` in the emitted UIView JSON
because its fixture left the omitempty field empty. Set it there.

Assisted-by: Claude:claude-sonnet-5-5

* Add the host controls spec to the apps inventory

The apps suite ran one more spec than scripts/addons/suites.json
listed, so verify.sh rejected the apps report as an inventory
mismatch. List the new spec in the report inventory and in the
suite's aggregate case list. Every other Ginkgo suite was re-run
and matches its inventory.

Assisted-by: Claude:claude-sonnet-5-5

---------

Co-authored-by: Ettore Di Giacinto <mudler@localai.io>
2026-11-01 12:08:23 +01:00

4576 lines
325 KiB
JSON

{
"prerequisites": {
"kind": "shell",
"commands": [
[
"sh",
"scripts/addons/prerequisites_test.sh"
]
],
"cases": [
"missing-go",
"old-go",
"future-go",
"old-node",
"wrong-node",
"wrong-protoc",
"absent-generated",
"empty-name",
"future-suite",
"empty-selection",
"failed-child",
"failed-case-named",
"failed-tail-kept",
"zero-tests",
"skipped-tests",
"exact-tag-pin",
"wrong-tag-sum",
"ginkgo-empty",
"ginkgo-skipped",
"ginkgo-missing",
"ginkgo-failed-spec-named",
"ginkgo-failure-message",
"browser-setup-failure",
"configured-browser-missing",
"configured-browser-setup",
"contracts-empty",
"contracts-skipped",
"gateway-missing-report",
"gateway-skipped-report",
"ui-report-failed",
"ui-report-skipped",
"ui-report-flaky",
"ui-report-empty",
"ui-report-missing",
"leak-ignores-command-line",
"leak-finds-working-directory"
],
"readiness": {
"ginkgo": {
"command": [
"go",
"test",
"-count=1",
"-p",
"2",
"-tags",
"auth",
"<temporary SQLite probe>",
"-ginkgo.json-report=<unique report>"
],
"cases": [
"sqlite transaction"
]
},
"commands": [
[
"sh",
"scripts/addons/prepare.sh",
"--check"
],
[
"tests/e2e-ui/ui-test-server",
"--mock-backend=<absolute mock-backend>",
"--port=<isolated port>"
],
[
"core/http/react-ui/node_modules/.bin/playwright",
"--version"
],
[
"node",
"--input-type=module",
"-e",
"<browser readiness probe>",
"<healthy server URL>"
]
],
"cases": [
"toolchain",
"server health",
"browser"
]
}
},
"contracts": {
"kind": "ginkgo",
"commands": [
[
"go",
"test",
"-count=1",
"-p",
"2",
"-tags",
"auth",
"./pkg/addons/contract",
"-ginkgo.json-report=../../../.cache/addons/logs/contracts.json"
]
],
"cases": [
"accepts independent service tool page and chat capabilities",
"rejects invalid namespace IDs and executable paths",
"rejects add-on IDs that the host serves as a route segment",
"rejects invalid versions ranges and capabilities",
"rejects unknown duplicate trailing and oversized manifest JSON",
"rejects incompatible host API protocol SDK data and platform fixtures",
"validates UI only when declared and rejects inconsistent contributions",
"uses canonical version one wire fixtures",
"rejects incomplete expired or forged authority shapes",
"rejects unknown and oversized wire payloads",
"validates finite defaults overrides and cross field bounds",
"validates preview receipt states and output descriptions",
"accepts the apps surface fields and keeps headless manifests valid",
"rejects unknown and reserved launch modes",
"rejects remote data absolute and traversing icon paths",
"requires the main page to be one of the declared pages",
"bounds localized titles and descriptions and rejects markup",
"requires the existence tool of an addon whose resources are created or deleted",
"reserves the segments of the navigation routes",
"refuses an add-on that needs a newer SDK than the host provides, and says so",
"accepts a range that contains the host SDK",
"accepts a range that spans the host SDK",
"refuses an add-on built for SDK 1 only on a version 2 host",
"keeps the generic message for a range that is malformed",
"accepts a read tool that names no resource",
"keeps a create tool free of the resource argument",
"refuses a read tool that offers the resource without requiring it",
"refuses a write or schema tool without a resource",
"still accepts a read tool that requires its resource",
"still accepts a write or schema tool that requires its resource",
"accepts a pull kind with a declared page",
"accepts drafts and a preview interval within the bounds",
"lets an add-on declare nothing but the connector",
"no kind",
"a bad kind id",
"a repeated kind",
"markup in the title",
"an unknown delivery",
"a page the UI does not declare",
"a preview interval too short",
"a preview interval too long",
"is valid when the add-on says it acts",
"is refused when the add-on does not say it acts",
"leaves the other kinds alone",
"cuts a long name on a character boundary",
"a plain name",
"a path keeps its last element",
"a Windows path",
"control characters and quotes",
"dots only",
"empty",
"a hidden name loses its leading dot",
"a long name keeps its extension",
"is a valid scope for an action request",
"is refused for any other request, and an action request refuses any other scope",
"has a long timeout of its own that is not part of the limits an add-on receives",
"accepts an action tool that names no resource, and refuses one that offers it without requiring it",
"keeps the argument names of identity and approval out of an action tool",
"round-trip",
"unknown field",
"duplicate key",
"trailing",
"not an object",
"empty",
"refuses an oversized body",
"finetune.get",
"quantize.start",
"finetune.a.b",
"empty",
"no dot",
"leading dot",
"uppercase",
"trailing space",
"slash",
"trailing newline",
"hyphen",
"empty verb",
"too long",
"bash is replaceable",
"web_search and web_fetch are replaceable",
"a file tool is not",
"an unknown name is not",
"a page-only tool cannot shadow",
"two tools cannot shadow one name",
"a shadow of bash must be an action tool",
"a shadow of web_fetch must be a read tool",
"a shadow of bash must declare command",
"a shadow keeps the type of a required property",
"a shadow requires no property the built-in does not",
"a shadow names no resource",
"extra optional properties are allowed",
"lists only the shadows that pass the check",
"keeps the file tools off the replaceable list",
"parses skillDefinitions from the manifest",
"accepts the add-on id and names that start with it",
"refuses a bad name, naming it",
"refuses a name declared twice",
"refuses more than 16 skills",
"refuses a plain name that does not start with the add-on id",
"refuses a plain name that is a built-in skill, whatever the add-on id",
"accepts a skill that replaces a replaceable built-in skill by its name",
"refuses shadows that does not repeat the name, or names a skill that may not be replaced",
"keeps the built-in names covered: each is replaceable or protected, never both",
"keeps the replaceable skills and tools apart, so one pin map holds both",
"accepts a read tool without a resource",
"refuses one that works on a resource or is not a read: the page has no resource to name",
"is resourceless like any read without a resource",
"has the same IDs as the registry of the React UI",
"accepts known controls and refuses an unknown or repeated one",
"reads ui.controls from a manifest and refuses an unknown field in it",
"draws the network policy only for an add-on granted egress that runs bash",
"serves a second add-on with the same controls, by its grant and not by its name",
"draws the tool providers for an add-on that replaces any built-in tool"
],
"report": ".cache/addons/logs/contracts.json"
},
"catalog": {
"kind": "ginkgo",
"commands": [
[
"go",
"test",
"-count=1",
"-p",
"2",
"-tags",
"auth",
"./core/services/addons/catalog",
"-ginkgo.json-report=../../../../.cache/addons/logs/catalog.json"
]
],
"cases": [
"fetches private bearer and basic catalogs without OCI credentials",
"blocks redirects without leaking credentials or error details",
"reports refresh failures rather than serving stale success",
"resolves the host platform from a multi platform catalog",
"selects exact configured owner targets and rejects absent or ambiguous targets",
"requires authoritative administration for all source edits",
"persists protected references and removes sources without touching installs",
"invalidates cached releases on explicit source changes",
"rejects secret URLs invalid digests duplicate identities and malformed catalogs",
"refuses a library entry whose add-on ID is a host route segment",
"lists and gets protected source copies including disabled and empty sources after reload",
"requires current authoritative administration and context for source reads",
"serializes source reads with concurrent configuration edits",
"pins channels and restricts package transport to secure or opted in loopback origins",
"surfaces optional UI metadata in search results and resolutions without changing plain entries",
"rejects entries with remote icons, reserved launch modes, markup or overlong display text",
"lists only releases the configured target platform can install",
"keeps the compatibility hint of an entry and refuses a malformed range",
"lists the releases of one add-on for every platform, from the cache, and refuses a failed library",
"names an unavailable credential reference as a credential failure inside the refresh failure",
"reads a YAML list of releases with the documented fields",
"accepts an empty library written as an empty list",
"refuses a JSON index",
"refuses an unknown field, at the top and inside ui",
"refuses a second document, a mapping, an empty body and a duplicate key",
"refuses duplicate identities",
"enforces the release count and the size limit",
"resolves the tag at install and builds the version from the digest",
"refuses a tag that cannot be resolved or a answer that is not a digest",
"keeps a pinned entry as it is and never looks it up",
"refuses an entry that is neither mutable nor pinned, and a mutable one that has a digest",
"refreshes an index with an unknown kind and reports what it skipped",
"lists add-ons by default and backends on request",
"resolves a backend only as a backend",
"refuses entries that mix the fields of the kinds",
"accepts an anchored identity pattern and refuses a loose one",
"has an entry for every enabled platform of every add-on",
"a release tag",
"a release candidate",
"a source build",
"a commit after a tag",
"a bare commit",
"a version that could escape the URL",
"moves a stored official library to the index of the new build",
"leaves an official library the admin pointed at another URL",
"reads an index written before kinds existed, and the entry is an add-on",
"reads a backend entry on a reader that knows backends",
"skips a backend entry on an add-on only reader and says so",
"skips an unknown kind without reading its fields, and keeps the rest",
"skips the reserved model kind in this phase",
"reports the id of a skipped entry, written as id or as the legacy addonId",
"reads a backend entry that still uses the legacy addonId, and refuses one that has both",
"still refuses an unknown field on an entry of a known kind",
"refuses a malformed kind",
"reads every new field and keeps it",
"keeps the reader strict about an unknown field of the backend kind",
"refuses a license, urls, tags, icon, mirrors or capabilities on an add-on",
"refuses a schemaVersion this host does not know",
"is a URL, and the host does not fetch it",
"must be an https URL with a host and no credentials",
"is not the icon of the add-on UI, which stays a path in the package",
"refuses a url that is not http or https",
"refuses too many urls and too many tags",
"refuses a tag or a license with a control character or a length over the bound",
"keeps the order",
"refuses a mirror that is not an oci image, a duplicate, the artifact itself, and too many",
"refuses a malformed capability name or backend name",
"has capabilities and no artifact, digest or platform, and is listed for every platform",
"cannot carry an artifact-only field",
"needs capabilities: an entry with no artifact and none is refused",
"is not a meta backend when it has an artifact",
"keeps its tag, has no digest and is listed",
"is refused with a digest, and an entry with no digest is refused unless it is mutable",
"is accepted on an add-on without a digest, as on a backend",
"is refused on an add-on with a digest, without a digest unless mutable, or on an archive",
"reads an index of more than a thousand entries",
"encodes and decodes an entry with the new fields unchanged",
"reads the legacy addonId as id, and refuses an entry that has both",
"carries the built-in tools an add-on replaces, and refuses one that may not be replaced",
"carries the built-in skills an add-on replaces, and refuses one that may not be replaced",
"carries toolCount and tools from the index to the listing",
"leaves both fields out for an entry without chat tools",
"keeps a count above the listed names when the names are capped",
"refuses a malformed hint",
"lists the first-party add-ons, one entry for each platform, in the library format",
"is a valid, signature-requiring source",
"is added when there is no sources.json and is written to it",
"keeps a sources.json the admin already has",
"does not add the default again after the admin removed it",
"seeds only once per instance",
"refuses an entry two of your sources list, and excludes disabled sources"
],
"report": ".cache/addons/logs/catalog.json"
},
"packages": {
"kind": "ginkgo",
"commands": [
[
"go",
"test",
"-count=1",
"-p",
"2",
"-tags",
"auth",
"./core/services/addons/packages",
"-ginkgo.json-report=../../../../.cache/addons/logs/packages.json"
]
],
"cases": [
"stages verified HTTP bytes and commits immutable receipts without activation",
"rejects untrusted integrity forged releases and digest mismatches",
"rejects traversal links collisions and excessive extraction",
"rejects cancellation disk full and preserves existing packages",
"rejects platform data API SDK and missing asset mismatches",
"pins and verifies real local OCI distribution bytes without a container runtime",
"rejects downloaded digest mismatch redirects cancellation and file count limits",
"accepts optional UI only with real immutable assets and rejects non executable entrypoints",
"does not allow remote verification policy to replace owner trust",
"requires source opt in before any plaintext OCI request",
"bounds compressed OCI PAX expansion before tar parsing",
"bounds compressed OCI GNU expansion before tar parsing",
"counts padding trailing bytes and layers at the exact expanded boundary",
"denies nonloopback plaintext and redirect responses at the transport boundary",
"bounds expanded bytes cumulatively across real OCI layers",
"bounds sparse logical output across files and layers preserving old packages",
"accepts exact sparse output budget and cancels synthesized writes",
"stages real trusted signatures and rejects signed identity digest and trust mismatches offline",
"records the digest of a packaged immutable icon in the receipt and refuses unusable icons",
"installs from the old repository per add-on",
"installs from the shared repository with an id-prefixed tag",
"follows a digest-pinned blob redirect without the registry credential",
"still verifies the digest of the redirected bytes",
"refuses a plaintext redirect to a host name instead of a loopback address",
"installs by a digest resolved at install, and the receipt records it",
"checks the signature against the resolved digest",
"is refused when the tag cannot be resolved or resolves to something that is not the image",
"refuses an entry that has no digest and is not mutable",
"accepts a good skills tree and records every file with its digest",
"reads the skills back for the copy, checked against the receipt",
"refuses a file added after commit",
"has nothing to copy for a package without skills",
"refuses a declared skill without a folder, and a folder that is not declared",
"refuses a skills folder when the manifest declares none",
"refuses a folder without SKILL.md and bad frontmatter",
"refuses links, executable files and special entries",
"refuses scripts and other file types",
"refuses names that are not plain lowercase ASCII",
"refuses text that is not UTF-8 or holds a NUL",
"refuses oversize files, deep paths and too many files",
"is for backend sources only: an add-on install refuses it",
"installs the darwin/amd64 child of an index with four platforms",
"installs the darwin/arm64 child of an index with four platforms",
"installs the linux/amd64 child of an index with four platforms",
"installs the linux/arm64 child of an index with four platforms",
"refuses an index that does not list the host platform",
"refuses a child whose digest differs from the one the index lists",
"still installs a single manifest and refuses a different digest"
],
"report": ".cache/addons/logs/packages.json"
},
"lifecycle": {
"kind": "ginkgo",
"commands": [
[
"go",
"test",
"-count=1",
"-p",
"2",
"-tags",
"auth",
"./core/services/addons",
"-ginkgo.json-report=../../../.cache/addons/logs/lifecycle.json"
]
],
"cases": [
"recovers every durable journal boundary without replaying publication",
"removes abandoned staging without removing published packages on recovery",
"keeps immutable history on successful upgrade and reinstallation",
"excludes competing owners and rejects conflicting durable identities",
"never opens replica roots or elects an absent owner",
"binds duplicate operation IDs to actor and command and serializes conflicts",
"refuses commands and asset reads for an add-on ID the host serves as a route",
"retains generations identity data and grants across uninstall and restart",
"preserves old packages and active generation on manager upgrade failure",
"requires current authoritative administration even for idempotent retries",
"rejects symlinked package roots without touching external staging",
"executes enabled owner intent on startup and stops on disable and close without forwarder execution",
"retries runtime synchronization after canceled disable and generation upgrade",
"binds lifecycle lookup to current admin and original actor without writes or repair",
"cancels status lookup while a lifecycle writer holds the journal lock",
"denies enable and disable for a stale generation without recording anything",
"lists the identifiers of installed addons, disabled ones included",
"refuses to list installed identifiers while recovery is required",
"lists apps by visibility and serves an icon only for a visible app at its generation",
"reports the supervisor state of an app through a crash and a restart",
"reads a flat directory in batches and stops at the entry bound",
"adds up nested files and reports a complete walk as not truncated",
"never follows or counts a symbolic link",
"keeps a result for a short time so polling does not walk again",
"stops at the time bound and reports a truncated size",
"does not keep a result cut short by the caller",
"is what the installed view reports for the data directory",
"resolves a package for the current enabled generation and digest only",
"answers from the current installed manifest only and follows a generation change",
"reports a digest-only change of a moving channel, applies nothing and offers the pinned upgrade",
"refuses a second operation ID for the same transition, in flight or done, and applies it once",
"runs concurrent requests with one operation ID once and gives each the same answer",
"serializes conflicting upgrades by the installed digest and refuses the loser without a record",
"refuses a candidate that is not the one the library resolves now",
"refuses an upgrade to the digest that is already installed",
"rechecks compatibility at execution and refuses an incompatible candidate",
"selects a newer immutable version and treats a rewritten version as an integrity error",
"keeps the last good generation when the candidate cannot be staged",
"never switches the library or channel, and a failed check is never up to date",
"lets an administrator refresh and everyone with the feature read a redacted status",
"shows the pending update in the apps list from the cache only",
"does not accept pins without an update checker or on another action",
"keeps the unpinned typed upgrade of an earlier release working",
"carries the SDK refusal text to the caller of a failed install and keeps the generic error",
"installs an add-on whose SDK range contains the host SDK",
"upgrades an installed add-on through the same path as a manual upgrade",
"does nothing when no newer version is listed",
"refuses a candidate whose package no longer matches its listed digest and replaces nothing",
"refuses a candidate that fails the signature policy of its library and replaces nothing",
"does not upgrade to a release the host cannot run",
"does nothing without an update checker",
"keeps the manual upgrade closed to a caller who is not an administrator",
"copies them at install, upgrade and owner start, and removes them at uninstall",
"never fails the operation when the copy fails",
"fails the install and says the package could not be verified, without installing anything",
"names a release that the library does not list",
"names two libraries that list the same add-on",
"names a library that cannot be read",
"reads the library on demand when the startup refresh has not filled the cache",
"reads the library again when the startup refresh failed",
"writes the owner and storage only, with no address",
"loads a file written in the old format with an address",
"loads when only the address changed",
"refuses a changed owner ID",
"refuses a changed storage ID",
"copies every capability field of the manifest, so a new field cannot be forgotten",
"is offered when the tag moved, pinned to the build the tag names, and upgrades to exactly that build",
"refuses the upgrade when the tag moved again after the check, and installs nothing",
"stamps the first install, keeps the time over an upgrade and stamps it again after an uninstall",
"needs a state root for the owner only",
"starts the enabled add-ons side by side, so the start takes the slowest ones and not the sum"
],
"report": ".cache/addons/logs/lifecycle.json"
},
"runtime": {
"kind": "ginkgo",
"commands": [
[
"go",
"test",
"-count=1",
"-p",
"2",
"-tags",
"auth",
"./core/services/addons/runtime",
"-ginkgo.json-report=../../../../.cache/addons/logs/runtime.json"
]
],
"cases": [
"registers only ready generation bound service headless and UI capabilities",
"rejects forged registration nonloopback and stale incarnation handshakes",
"bounds readiness and handles exit during start and stop",
"withdraws immediately drains boundedly and rejects stale process identities",
"exhausts restart budget without retaining dead registrations",
"does not inherit secrets and exits when the private parent channel closes",
"rejects foreign supervisor handles and numeric PID substitutions",
"resets restart budget only after sustained authenticated health",
"authenticates every request and separates trusted authority from model arguments",
"bounds output streams cancellation deadlines and stop admission",
"tells a 409 conflict of the add-on from an outage",
"rejects nonloopback endpoints and bounds oversized streams and concurrency",
"never reports failed between a launch starting and the restarted process being published",
"reserves a draining slot against concurrent starts",
"waits for a restart launch worker before acknowledging stop",
"exposes a new incarnation client after restart without reviving the old client",
"kills the exact paused child of a killed owner before launching its replacement",
"fails closed on ambiguous launch identities and preserves unrelated reused PIDs",
"retains a canceled restart slot until cleanup completes and rejects duplicate supervisors",
"refuses a missing established ledger and fences failed cleanup publication",
"withdraws and initiates every live slot before a cleanup timeout",
"reports stopped, running, failed, starting and running again across a crash and a restart",
"keeps reporting failed once the restart budget is exhausted",
"creates one private data directory per addon and passes its path in the startup object",
"gives no data directory without a data root and refuses an unsafe root or addon ID",
"gives an add-on that the host setting names a host endpoint of its own",
"gives an add-on that the host setting does not name no host endpoint",
"closes the host endpoint when the incarnation ends",
"an HTTP 400 answer",
"an HTTP 422 answer",
"keeps a bounded, printable reason and nothing else of the body",
"leaves 503, 500 and 404 as outages",
"types a withdrawn client, a full slot table, a bad envelope and a missing schema as not sent",
"keeps a not-sent error an ErrRuntime for callers that do not tell them apart",
"types a refused connection as not sent",
"never types a possibly-sent request as not sent",
"types the add-on's own 'forbidden' answer as a denial of the person, not as an outage",
"keeps a 403 about the envelope itself an outage: it is a host fault, not a permission",
"reaches an add-on that declares actions, as the actor of the envelope, under the act scope",
"never sends a call that is not an act call or has another scope",
"never sends an act call to an add-on that did not declare actions",
"stops an act call when the caller gives up",
"posts the request with the incarnation credential and decodes the answer",
"is not sent to an add-on that declared no connector",
"gives it time to release what it owns before it kills the process",
"kills an add-on that ignores the closing of its startup channel, within the grace period",
"goes to the log line by line with the add-on ID and a cap per line"
],
"report": ".cache/addons/logs/runtime.json"
},
"gateway": {
"kind": "ginkgo",
"commands": [
[
"go",
"test",
"-count=1",
"-p",
"2",
"-tags",
"auth",
"./core/services/addons/gateway",
"-ginkgo.json-report=../../../../.cache/addons/logs/gateway.json"
],
[
"go",
"test",
"-count=1",
"-p",
"2",
"-tags",
"auth",
"./core/http/endpoints/addons",
"-ginkgo.json-report=../../../../.cache/addons/logs/gateway-http.json"
]
],
"cases": [
"serves only declared installed generation assets and rejects traversal",
"fails closed without current identity or resource policy and reports the original ID of an unknown mutation outcome",
"reports an unclassified account check error as unavailable on every path and a wrapped denial as forbidden",
"propagates interrupted progress cancellation through the receiving frontend",
"validates finite relay budgets and prevents disabling polling bounds",
"builds a carrier only from complete pinned identities",
"types an unknown mutation outcome as unavailable without losing its operation",
"rejects untrusted peers wrong audience body expiry replay and revoked credentials",
"alternates pinned frontends and rejects untrusted certificates without local fallback",
"reports the original operation after lost mutation replies without retrying",
"rejects a stream longer than its receiving frontend budget",
"rejects a CA signed peer without a pin on the owner side",
"refuses an owner whose CA signed certificate is not the pinned owner",
"returns the artifact status through the owner from every frontend with one denial for the rest",
"types the owner's refusal and outage of a lookup the same from every frontend",
"writes an attachment header that cannot be broken out of",
"rotates the enforced audience on restart and rejects captured requests",
"never expires the response deadline after the relay returned",
"returns the owner's forbidden status for an invalid kind and for missing policy",
"still reports unavailable when the owner is unable to serve and not forbidden",
"reaches the same decision through both frontends and delivers bytes when allowed",
"keeps aborting when revocation happens after bytes were written",
"bounds progress, asset and file relays by their own limit",
"alternates real owner journal status and terminates coarse progress without submitting again",
"reports an account store outage as unavailable and a refused account as forbidden",
"rejects unknown lifecycle argument fields before touching the owner journal",
"reports a runtime that cannot serve as unavailable through both frontends",
"reports an output that ends before its first byte as unavailable",
"fails closed as unavailable for an unclassified owner error",
"keeps authorization and policy denials forbidden",
"keeps a mutation unknown when the runtime fails after the owner applied it",
"keeps a mutation unknown when the owner reports recovery required for its operation",
"reports a mutation as unknown when the owner cannot serve it at all",
"keeps a mutation unknown on the owner's own frontend and leaves reads and denials alone",
"lets unavailability win when an error wraps both a denial and an unavailable cause",
"does not leak attachment headers into an error when the first read fails",
"treats every action except the known reads as a mutation",
"keeps resolved resources under admission for JSON and attachment bytes",
"closes interrupted output and releases admission on disconnect",
"rechecks revoked credentials during attachment copying",
"adopts read outputs as private artifacts inside admission and replaces a forged resource identity",
"refuses at ingest a file result larger than the relay file bound so nothing unservable is staged",
"denies private relays without host resolution and admission",
"serves declared assets of the current enabled generation by package digest only",
"allows only an exact declared tool name and fails closed otherwise",
"never contacts the add-on for an undeclared tool and still serves a declared one",
"denies a repeated key at any depth however it is spelled",
"denies arguments that are not exactly one object",
"separates a denial from an unavailable declaration source",
"answers 503 and never contacts the add-on when the source is unavailable or the arguments repeat a key",
"is the typed invalid request on the owner for a read, never an outage",
"is the typed invalid request on the owner for a proposal call",
"is the typed invalid request on the owner for a json relay",
"is the same typed answer from a forwarding frontend",
"stores a proposal from an API key and lets only the proposer's browser session confirm it",
"cancels a proposal from the same chain and never lets typed dispatch or relay confirm",
"denies sharing and deletion proposals and an unauthenticated caller",
"serves the local owner's confirmation only from a same-origin fetch of the host page",
"reports a lost reply with the original operation from forwarding frontends and resolves it by receipt",
"lets only the resource owner's browser session abandon an unresolved outcome and then accepts writes",
"lets the owner role list an editor's unresolved proposal and abandon it by the listed digest from every frontend",
"tells an editor of a blocked write only that it is denied",
"returns the applied proposal when the confirmed operation committed",
"answers an owner outage by the owner's state with the same type from every frontend",
"keeps a proposal confirmable by the same ID after the owner could not reach the addon",
"documents the proposal routes and the proposal schema in the Swagger spec",
"serves one owner journal through two real authenticated HTTP frontends and rejects paused keys",
"serves the synthetic owner through the real chain, denies sharing and rejects named callers",
"checks browser CSRF feature and admin access with real stored keys",
"serves a private file result as a safe attachment over real HTTP",
"never renders hostile names or active media types inline",
"answers one 403 for unknown, foreign, incomplete and expired artifacts and requires the feature and a principal",
"denies the download of a disabled addon and serves it again after enable",
"relays the same bytes, headers and denials through two forwarding frontends",
"keeps a file result of a read denied whole without an artifact store",
"serves the local owner's file only in local-owner mode",
"documents the artifact routes and the artifact schema in the Swagger spec",
"rejects anonymous callers and forged forwarding headers",
"gates the feature and then administration for named keys",
"requires same-origin browser requests for cookie mutations",
"registers only the dispatch, relay and proposal mutations",
"reserves every first path segment the host registers under /api/addons",
"gates the artifact routes by authentication and feature",
"gates the proposal routes by feature and refuses a confirmation from a key before the owner is asked",
"rejects anonymous and forged forwarding authority through real authentication",
"lets callers through only when the deployment selected local-owner mode",
"keeps authentication, the feature gate and administration when accounts exist",
"reports an unknown mutation outcome from a forwarding frontend with the original operation",
"documents every field the error responses emit in the Swagger schema",
"reports an unavailable read as plain unavailability",
"reports a denial as forbidden",
"reports an unclassified account check error as unavailable and a definite denial as forbidden",
"reports an unknown mutation outcome from the owner's own frontend with the original operation",
"lists the enabled installed apps for a reader and the disabled ones too for administrators, the same from every frontend",
"lets only administrators start and stop, through the lifecycle manager, and denies a stale generation",
"serves the verified icon through the host route and denies it identically otherwise",
"reports a lost start as an unknown outcome with its original operation and a lost list as unavailable",
"documents the apps routes and every field of the app view in the Swagger spec",
"lists every registered addon route in the feature registry",
"gates the apps routes by authentication, feature and administration",
"serves catalog search, details and the installed management view to administrators only, the same from every frontend",
"refuses every management call of the owner itself for a caller that is not an administrator",
"saves, refreshes and removes a library by reference and leaves installed addons alone",
"upgrades an installed addon through the typed action and keeps its earlier generation",
"reports a lost source change as an unknown outcome and a lost read as unavailable",
"documents the management actions and every emitted field of the installed view",
"serves the declared files of the current package through every frontend with immutable headers",
"lists the same URLs the route serves, and only for an enabled addon",
"denies every other path, digest, addon and credential form with one answer and no immutable caching",
"accepts a same-origin browser session and refuses a cross-site or direct one",
"withdraws the code the moment the addon is disabled, uninstalled or replaced, even for a page that is still open",
"refuses a declared file that is not a regular file of the package",
"documents the asset route and its binary response in the Swagger spec",
"gives the same 403 on the owner and on a forwarding frontend and never contacts the add-on",
"lists the caller's own pending proposals the same from the owner and every forwarding frontend",
"gives every caller with the feature the same status from every frontend, redacted for non-administrators",
"checks only for an administrator's own browser session, and applies nothing",
"upgrades only to the checked candidate, with the same typed refusals from every frontend, and never twice",
"runs two concurrent upgrades from two frontends once: the same ID shares the answer, another ID is a conflict",
"refuses an incompatible candidate and a library that cannot be read, with a typed answer",
"reports a lost upgrade as an unknown outcome with its original operation, and a lost status read or check as plainly unavailable",
"keeps the update actions out of the tools and names every field of the status in the Swagger spec",
"answers an add-on's invalid-request refusal as a typed 400 from the owner and from a forwarding frontend",
"crosses the owner's wire as the same typed error, whatever the frontend",
"does not trust a code the host does not know, and cleans the detail the add-on wrote",
"is a stale view for a caller that only knows ErrStale, and a denial otherwise",
"is a mutation on the carrier: a lost answer is an unknown outcome, never a plain outage",
"runs on the owner for the actor the signature binds, and the typed direct dispatch still refuses it",
"keeps the answer of a call that outlasts the write timeout of the owner server",
"is an unknown outcome when the answer is lost",
"runs the backend-releases check for a pinned frontend without an actor",
"refuses a system call from a peer that is not pinned",
"never lets a system call change anything or ride the user-facing route",
"writes the set with private modes and no CA key",
"loads both roles into carriers and serves a frontend call from the owner",
"gives the owner no signing key and the frontend its own",
"accepts two frontends made from the same set",
"refuses a frontend from another generation",
"reads only the files of the role",
"refuses a key file with group or other access",
"refuses an unknown role",
"refuses to overwrite a file and leaves it unchanged",
"needs an owner host",
"says nothing was sent when the add-on is not running, instead of an unknown outcome",
"runs a declared action tool for the calling user, under the act scope, admitted as an add-on call",
"is not reachable through the typed dispatch of the direct API",
"refuses what is not a declared action tool",
"refuses an add-on that did not declare actions",
"is unavailable when the runtime does not serve action tools, and never runs for an unvalidated user",
"reports an unknown outcome, not a refusal, when the runtime fails after the call began",
"runs a resource-less read tool for the calling user only",
"denies a tool that declares a resource when none is given, and never reaches the add-on",
"denies a resource-less read when the admission cannot admit an add-on, or the tool is undeclared",
"keeps its address stable across starts",
"does not share state between different roots",
"fails clearly when the port is in use",
"rejects an invalid port file",
"rejects a port file with a loose mode",
"rejects a port file that links outside the root",
"is not permitted when the add-on denies the person, on the owner and on a forwarding frontend",
"is an unreachable resource when the policy denies it, on the owner and on a forwarding frontend",
"types the denial of a read like the denial of a write, on the owner and on a forwarding frontend",
"crosses the wire of a resource call typed, so a forwarding frontend answers like the owner",
"keeps any other failure to resolve a resource a plain denial, so nothing more is told",
"Sec-Fetch-Site cross-site is refused even with a Referer on the same host",
"Sec-Fetch-Site same-origin passes",
"Sec-Fetch-Site same-site is refused",
"a request without a session cookie is not guarded",
"no Sec-Fetch-Site and no Origin or Referer is refused",
"no Sec-Fetch-Site with a Referer on the same host passes",
"no Sec-Fetch-Site with a foreign Origin is refused",
"no Sec-Fetch-Site with a foreign Origin is refused even with a Referer on the same host",
"no Sec-Fetch-Site with a foreign Referer is refused",
"no Sec-Fetch-Site with a null Origin is refused",
"no Sec-Fetch-Site with an Origin on the same host passes",
"no Sec-Fetch-Site with the same host on another port is refused",
"matches the host without regard to letter case",
"gives no pins to an account created after the upgrade",
"round-trips pins for the local owner",
"drops IDs the caller cannot see",
"an object",
"numbers",
"not JSON",
"empty",
"null",
"rejects a list over the hard limit",
"does not show Studio and Talk as pins without the add-ons",
"lists add-ons by default, and takes a kind that this host reads",
"is empty because Studio and Talk are packaged add-ons",
"lists every entry without an account database",
"strict same-origin fetch",
"same-origin without destination",
"same-host Referer, no Sec-Fetch headers",
"same-host Origin, no Sec-Fetch headers",
"foreign Referer",
"same host, other port",
"foreign Origin wins over same-host Referer",
"no Origin and no Referer",
"cross-site with same-host Referer",
"same-site with same-host Origin",
"same-host Referer but navigation destination",
"same-host Referer but no-cors mode",
"still refuses a same-host Referer with an API key",
"returns the SDK refusal text, the unverified-package text and the missing-release text to the administrator",
"logs the cause of a failed install and types it for the client",
"logs the reason behind a generic denial and leaves the response unchanged",
"returns the same text through a forwarding frontend",
"names every typed cause of a failed install in the 403 of the dispatch route"
],
"report": ".cache/addons/logs/gateway.json",
"reports": [
{
"path": ".cache/addons/logs/gateway.json",
"cases": [
"serves only declared installed generation assets and rejects traversal",
"fails closed without current identity or resource policy and reports the original ID of an unknown mutation outcome",
"reports an unclassified account check error as unavailable on every path and a wrapped denial as forbidden",
"propagates interrupted progress cancellation through the receiving frontend",
"validates finite relay budgets and prevents disabling polling bounds",
"builds a carrier only from complete pinned identities",
"types an unknown mutation outcome as unavailable without losing its operation",
"rejects untrusted peers wrong audience body expiry replay and revoked credentials",
"alternates pinned frontends and rejects untrusted certificates without local fallback",
"reports the original operation after lost mutation replies without retrying",
"rejects a stream longer than its receiving frontend budget",
"rejects a CA signed peer without a pin on the owner side",
"refuses an owner whose CA signed certificate is not the pinned owner",
"returns the artifact status through the owner from every frontend with one denial for the rest",
"types the owner's refusal and outage of a lookup the same from every frontend",
"writes an attachment header that cannot be broken out of",
"rotates the enforced audience on restart and rejects captured requests",
"never expires the response deadline after the relay returned",
"returns the owner's forbidden status for an invalid kind and for missing policy",
"still reports unavailable when the owner is unable to serve and not forbidden",
"reaches the same decision through both frontends and delivers bytes when allowed",
"keeps aborting when revocation happens after bytes were written",
"bounds progress, asset and file relays by their own limit",
"alternates real owner journal status and terminates coarse progress without submitting again",
"reports an account store outage as unavailable and a refused account as forbidden",
"rejects unknown lifecycle argument fields before touching the owner journal",
"reports a runtime that cannot serve as unavailable through both frontends",
"reports an output that ends before its first byte as unavailable",
"fails closed as unavailable for an unclassified owner error",
"keeps authorization and policy denials forbidden",
"keeps a mutation unknown when the runtime fails after the owner applied it",
"keeps a mutation unknown when the owner reports recovery required for its operation",
"reports a mutation as unknown when the owner cannot serve it at all",
"keeps a mutation unknown on the owner's own frontend and leaves reads and denials alone",
"lets unavailability win when an error wraps both a denial and an unavailable cause",
"does not leak attachment headers into an error when the first read fails",
"treats every action except the known reads as a mutation",
"keeps resolved resources under admission for JSON and attachment bytes",
"closes interrupted output and releases admission on disconnect",
"rechecks revoked credentials during attachment copying",
"adopts read outputs as private artifacts inside admission and replaces a forged resource identity",
"refuses at ingest a file result larger than the relay file bound so nothing unservable is staged",
"denies private relays without host resolution and admission",
"serves declared assets of the current enabled generation by package digest only",
"allows only an exact declared tool name and fails closed otherwise",
"never contacts the add-on for an undeclared tool and still serves a declared one",
"denies a repeated key at any depth however it is spelled",
"denies arguments that are not exactly one object",
"separates a denial from an unavailable declaration source",
"answers 503 and never contacts the add-on when the source is unavailable or the arguments repeat a key",
"is the typed invalid request on the owner for a read, never an outage",
"is the typed invalid request on the owner for a proposal call",
"is the typed invalid request on the owner for a json relay",
"is the same typed answer from a forwarding frontend",
"crosses the owner's wire as the same typed error, whatever the frontend",
"does not trust a code the host does not know, and cleans the detail the add-on wrote",
"is a stale view for a caller that only knows ErrStale, and a denial otherwise",
"is a mutation on the carrier: a lost answer is an unknown outcome, never a plain outage",
"runs on the owner for the actor the signature binds, and the typed direct dispatch still refuses it",
"keeps the answer of a call that outlasts the write timeout of the owner server",
"is an unknown outcome when the answer is lost",
"runs the backend-releases check for a pinned frontend without an actor",
"refuses a system call from a peer that is not pinned",
"never lets a system call change anything or ride the user-facing route",
"writes the set with private modes and no CA key",
"loads both roles into carriers and serves a frontend call from the owner",
"gives the owner no signing key and the frontend its own",
"accepts two frontends made from the same set",
"refuses a frontend from another generation",
"reads only the files of the role",
"refuses a key file with group or other access",
"refuses an unknown role",
"refuses to overwrite a file and leaves it unchanged",
"needs an owner host",
"says nothing was sent when the add-on is not running, instead of an unknown outcome",
"runs a declared action tool for the calling user, under the act scope, admitted as an add-on call",
"is not reachable through the typed dispatch of the direct API",
"refuses what is not a declared action tool",
"refuses an add-on that did not declare actions",
"is unavailable when the runtime does not serve action tools, and never runs for an unvalidated user",
"reports an unknown outcome, not a refusal, when the runtime fails after the call began",
"runs a resource-less read tool for the calling user only",
"denies a tool that declares a resource when none is given, and never reaches the add-on",
"denies a resource-less read when the admission cannot admit an add-on, or the tool is undeclared",
"keeps its address stable across starts",
"does not share state between different roots",
"fails clearly when the port is in use",
"rejects an invalid port file",
"rejects a port file with a loose mode",
"rejects a port file that links outside the root",
"is not permitted when the add-on denies the person, on the owner and on a forwarding frontend",
"is an unreachable resource when the policy denies it, on the owner and on a forwarding frontend",
"types the denial of a read like the denial of a write, on the owner and on a forwarding frontend",
"crosses the wire of a resource call typed, so a forwarding frontend answers like the owner",
"keeps any other failure to resolve a resource a plain denial, so nothing more is told"
]
},
{
"path": ".cache/addons/logs/gateway-http.json",
"cases": [
"stores a proposal from an API key and lets only the proposer's browser session confirm it",
"cancels a proposal from the same chain and never lets typed dispatch or relay confirm",
"denies sharing and deletion proposals and an unauthenticated caller",
"serves the local owner's confirmation only from a same-origin fetch of the host page",
"reports a lost reply with the original operation from forwarding frontends and resolves it by receipt",
"lets only the resource owner's browser session abandon an unresolved outcome and then accepts writes",
"lets the owner role list an editor's unresolved proposal and abandon it by the listed digest from every frontend",
"tells an editor of a blocked write only that it is denied",
"returns the applied proposal when the confirmed operation committed",
"answers an owner outage by the owner's state with the same type from every frontend",
"keeps a proposal confirmable by the same ID after the owner could not reach the addon",
"documents the proposal routes and the proposal schema in the Swagger spec",
"serves one owner journal through two real authenticated HTTP frontends and rejects paused keys",
"serves the synthetic owner through the real chain, denies sharing and rejects named callers",
"checks browser CSRF feature and admin access with real stored keys",
"serves a private file result as a safe attachment over real HTTP",
"never renders hostile names or active media types inline",
"answers one 403 for unknown, foreign, incomplete and expired artifacts and requires the feature and a principal",
"denies the download of a disabled addon and serves it again after enable",
"relays the same bytes, headers and denials through two forwarding frontends",
"keeps a file result of a read denied whole without an artifact store",
"serves the local owner's file only in local-owner mode",
"documents the artifact routes and the artifact schema in the Swagger spec",
"rejects anonymous callers and forged forwarding headers",
"gates the feature and then administration for named keys",
"requires same-origin browser requests for cookie mutations",
"registers only the dispatch, relay and proposal mutations",
"reserves every first path segment the host registers under /api/addons",
"gates the artifact routes by authentication and feature",
"gates the proposal routes by feature and refuses a confirmation from a key before the owner is asked",
"rejects anonymous and forged forwarding authority through real authentication",
"lets callers through only when the deployment selected local-owner mode",
"keeps authentication, the feature gate and administration when accounts exist",
"reports an unknown mutation outcome from a forwarding frontend with the original operation",
"documents every field the error responses emit in the Swagger schema",
"reports an unavailable read as plain unavailability",
"reports a denial as forbidden",
"reports an unclassified account check error as unavailable and a definite denial as forbidden",
"reports an unknown mutation outcome from the owner's own frontend with the original operation",
"lists the enabled installed apps for a reader and the disabled ones too for administrators, the same from every frontend",
"lets only administrators start and stop, through the lifecycle manager, and denies a stale generation",
"serves the verified icon through the host route and denies it identically otherwise",
"reports a lost start as an unknown outcome with its original operation and a lost list as unavailable",
"documents the apps routes and every field of the app view in the Swagger spec",
"lists every registered addon route in the feature registry",
"gates the apps routes by authentication, feature and administration",
"serves catalog search, details and the installed management view to administrators only, the same from every frontend",
"refuses every management call of the owner itself for a caller that is not an administrator",
"saves, refreshes and removes a library by reference and leaves installed addons alone",
"upgrades an installed addon through the typed action and keeps its earlier generation",
"reports a lost source change as an unknown outcome and a lost read as unavailable",
"documents the management actions and every emitted field of the installed view",
"serves the declared files of the current package through every frontend with immutable headers",
"lists the same URLs the route serves, and only for an enabled addon",
"denies every other path, digest, addon and credential form with one answer and no immutable caching",
"accepts a same-origin browser session and refuses a cross-site or direct one",
"withdraws the code the moment the addon is disabled, uninstalled or replaced, even for a page that is still open",
"refuses a declared file that is not a regular file of the package",
"documents the asset route and its binary response in the Swagger spec",
"gives the same 403 on the owner and on a forwarding frontend and never contacts the add-on",
"lists the caller's own pending proposals the same from the owner and every forwarding frontend",
"gives every caller with the feature the same status from every frontend, redacted for non-administrators",
"checks only for an administrator's own browser session, and applies nothing",
"upgrades only to the checked candidate, with the same typed refusals from every frontend, and never twice",
"runs two concurrent upgrades from two frontends once: the same ID shares the answer, another ID is a conflict",
"refuses an incompatible candidate and a library that cannot be read, with a typed answer",
"reports a lost upgrade as an unknown outcome with its original operation, and a lost status read or check as plainly unavailable",
"keeps the update actions out of the tools and names every field of the status in the Swagger spec",
"answers an add-on's invalid-request refusal as a typed 400 from the owner and from a forwarding frontend",
"returns the same text through a forwarding frontend",
"Sec-Fetch-Site cross-site is refused even with a Referer on the same host",
"Sec-Fetch-Site same-origin passes",
"Sec-Fetch-Site same-site is refused",
"a request without a session cookie is not guarded",
"no Sec-Fetch-Site and no Origin or Referer is refused",
"no Sec-Fetch-Site with a Referer on the same host passes",
"no Sec-Fetch-Site with a foreign Origin is refused",
"no Sec-Fetch-Site with a foreign Origin is refused even with a Referer on the same host",
"no Sec-Fetch-Site with a foreign Referer is refused",
"no Sec-Fetch-Site with a null Origin is refused",
"no Sec-Fetch-Site with an Origin on the same host passes",
"no Sec-Fetch-Site with the same host on another port is refused",
"matches the host without regard to letter case",
"gives no pins to an account created after the upgrade",
"round-trips pins for the local owner",
"drops IDs the caller cannot see",
"an object",
"numbers",
"not JSON",
"empty",
"null",
"rejects a list over the hard limit",
"does not show Studio and Talk as pins without the add-ons",
"lists add-ons by default, and takes a kind that this host reads",
"is empty because Studio and Talk are packaged add-ons",
"lists every entry without an account database",
"strict same-origin fetch",
"same-origin without destination",
"same-host Referer, no Sec-Fetch headers",
"same-host Origin, no Sec-Fetch headers",
"foreign Referer",
"same host, other port",
"foreign Origin wins over same-host Referer",
"no Origin and no Referer",
"cross-site with same-host Referer",
"same-site with same-host Origin",
"same-host Referer but navigation destination",
"same-host Referer but no-cors mode",
"still refuses a same-host Referer with an API key",
"returns the SDK refusal text, the unverified-package text and the missing-release text to the administrator",
"logs the cause of a failed install and types it for the client",
"logs the reason behind a generic denial and leaves the response unchanged",
"names every typed cause of a failed install in the 403 of the dispatch route"
]
}
]
},
"policy": {
"kind": "ginkgo",
"commands": [
[
"go",
"test",
"-count=1",
"-p",
"2",
"-tags",
"auth",
"./core/services/addons/policy",
"-ginkgo.json-report=../../../../.cache/addons/logs/policy.json"
]
],
"cases": [
"enforces the viewer editor owner matrix on fixture resources",
"denies installation administrators and unrelated users any access to user data",
"does not leak resource existence and treats unknown actions as owner mutations",
"never grants the owner role or a grant to the owner and the synthetic principals",
"rejects anonymous and legacy synthetic principals in named mode",
"checks credential and account status on every admission",
"keeps no current-user state shared between concurrent admissions",
"disables sharing in explicit local-owner mode and lets every local caller own the resource",
"refuses a mode switch of populated data without a stopped backed-up migration",
"retains resources and grants across a restart and an uninstall of the package",
"refuses a corrupt store and a second opener",
"stops admitted work of a revoked user and acknowledges only after it ended",
"lets a racing revocation win against read and write admissions",
"serializes writes per resource while reads run concurrently",
"bounds the revocation wait and does not acknowledge a stuck drain",
"invalidates pending proposals on revoke and downgrade and fails closed when it cannot",
"requires explicit creation authority and keeps pending registrations inaccessible",
"reconciles a registration interrupted by a crash from the durable store",
"keeps a record whose existence cannot be established and settles the rest",
"never drops a committed resource and counts pending quota unchanged",
"retries kept records from the loop on a tick and on a kick, and stops on Close",
"closes a loop that never started without waiting",
"maps opaque ids to the trusted addon and owner and keeps an absent policy denying",
"does not acknowledge a retried downgrade while the lowered user's write still runs",
"retries a failed proposal invalidation after the lowered grant is already durable",
"keeps the drain owed across a restart",
"does not cancel work admitted under a later grant when a lowering is retried",
"still waits for and cancels work admitted before the lowering when the regrant is retried",
"stops work admitted after a regrant when the role is lowered again",
"keeps the epoch of the owed drain across a restart",
"keeps a drain mark that a concurrent lowering replaced while a retry was waiting",
"maps a store outage to unavailable and a disabled account to forbidden",
"caps pending and committed registrations per user and in total",
"applies finite defaults when no limit is configured",
"denies creation as unavailable when the authority cannot tell",
"reports an unclassified account or creation check error as unavailable and a definite denial as forbidden",
"does not start the work when revocation cancels the admission before run",
"rejects persisted unknown roles and trailing bytes without resetting the store",
"removes stale temporary files on open",
"stops accepting writes after a failed directory sync and keeps the applied change",
"retains resources and grants across a real manager uninstall and restart",
"stores a pending proposal with its exact effects and never executes it",
"applies exactly the stored arguments once and answers a repeat from the stored receipt",
"refuses changed arguments, other actors, unknown identifiers and an unbound digest",
"never lets an API key, plain text or a boolean approve",
"accepts the local owner as the confirming principal in local-owner mode only",
"expires a proposal and refuses a late or repeated confirmation",
"refuses a proposal made stale by a new generation or a moved revision",
"cancels a proposal for good and restricts who may propose which action",
"never accepts sharing, deletion, reads or unclassified actions as proposals",
"cancels pending proposals when authority is lowered and lets a revocation win the confirmation race",
"persists every transition atomically before it is reported",
"does not dispatch when the executing state cannot be made durable",
"keeps a lost reply unknown, blocks conflicting writes and resolves it by receipt without a replay",
"reports a lost reply from the owner's own gateway with the original operation",
"recovers a crash after dispatch by receipt and a crash before dispatch as unknown without replay",
"keeps pending proposals across a restart and never resets a corrupt store",
"bounds the pending proposals of one user and the store as a whole",
"records expiry and collects settled proposals without any read so a quiet clock cannot fill the store",
"records expiry durably when the owner starts and when it recovers",
"keeps settled proposals for the retention window only",
"keeps one user from starving others and never drops another user's live proposal",
"bounds the stored canonical arguments per user and in total with a typed quota error",
"looks an unresolved receipt up again with backoff for a finite window and never applies again",
"lets only the resource owner's browser session abandon an unresolved outcome and then unblocks writes",
"records a late receipt of an abandoned outcome instead of hiding it",
"settles by lookup instead of abandoning when the receipt is final",
"refuses a stored abandonment that names nobody and keeps looking up in the background",
"binds the digest to the operation, actor, resource, generation, action, arguments and revision",
"refuses a stored proposal whose operation, actor, resource, generation or arguments changed at rest",
"issues resource identifiers the envelope contract accepts",
"is unavailable until it is attached to a policy and a runtime",
"keeps executing, outcome-unknown and abandoned records far past retention and still dedupes them",
"waits for the background run and for lookups in flight before it closes, and writes nothing after",
"lets the owner role list the unresolved proposals of its resource and abandon one by the listed digest",
"names the blocking proposal in the denial only to the resource owner",
"refuses an unbound digest when the owner abandons through the gateway or the broker",
"answers the same typed outage for a resolution whoever proposed the operation",
"returns the applied proposal when the owner cannot read it back after a successful apply",
"does not show another user's blocking operation in a proposal view",
"denies a proposal for an undeclared tool before any preview and stores nothing",
"denies a proposal that names a tool when no tool source is installed",
"rechecks the stored tool at confirmation and never applies a withdrawn tool",
"denies a proposal whose arguments repeat a key and stores nothing",
"reports an unavailable declaration source as unavailable, never as a denial",
"does not apply at confirmation while the declaration source is unavailable, and applies once it recovers",
"reserves a create proposal as a pending resource that nobody can reach",
"commits the reservation on confirmation and makes the proposer the private owner",
"abandons the reservation when a create proposal is cancelled or expires",
"abandons the reservation when the addon rejects the creation",
"keeps a lost create reply pending and unknown and settles it by receipt",
"abandons an unknown create only when the addon confirms the backing is absent",
"settles reservations at restart by asking the addon and keeps those of live proposals",
"bounds concurrent create proposals by the pending quota",
"lets only the proposer confirm, cancel or read a create proposal",
"denies a create proposal when creation authority is revoked before confirmation",
"denies a create proposal for an undeclared tool or an existing resource without reserving",
"does not let reconcile drop the reservation of a creation in flight",
"commits the reservation at recovery when the crash came after the receipt was stored",
"never reads an add-on that cannot answer as a backing that is gone",
"accepts the explicit answer of the declared existence tool, true or false",
"holds the resources of one add-on and leaves another add-on alone",
"cancels admitted work and reports a drain that did not finish",
"restores grants through the account directory and the lowerings since the backup, never beyond them",
"keeps a bounded durable log of lowered access",
"keeps a revocation however many later lowerings of another person follow",
"restores the data but no access when the history may have lost a lowering",
"reads a store that is full of lowerings as one whose history may be cut",
"applies a lowering made after the export whatever time the backup is given",
"refuses a change that was authorized just before the hold began",
"cancels a pending proposal and leaves an executing one outcome-unknown after a restore",
"forgets the records of one add-on and no other",
"maps an owner on a restore to a local-owner store only when nothing named is in it",
"migrates the ownership of a stopped store with a backup and an explicit mapping and refuses a populated downgrade",
"refuses a proposal whose preview the add-on refused, storing nothing",
"settles a confirmation the add-on refused as rejected, never as an unknown outcome",
"R34: returns an admission that was refused before the wire to pending, and a repeat applies",
"R35, R52: a hold that cancels the dispatch before the wire ends the proposal as cancelled, not unknown",
"R38: records a conflict of the add-on as rejected, not unknown",
"R39: still records an unknown outcome when the request may have been sent",
"reports a not-sent confirmation through the gateway as an outage that sent nothing, never as unknown",
"is a refusal that changed nothing, not an outage, and leaves the ID free",
"R4, S4: refuses an editor who claims the write action for a schema tool, and stores nothing",
"R4: refuses an editor who names the schema action for a schema tool",
"derives the action from the tool, so the owner needs the matching claim and gets the schema action",
"still lets an editor propose a data write for a write tool",
"R3: refuses a read tool, a create tool and a tool without a definition",
"runs the declaration check as well as the kind check",
"refuses a named tool when the source cannot report kinds",
"R3: a creation names a create tool, never a schema or data tool",
"retry-after-not-sent: R34 then R37",
"addon-conflict-is-rejected: R38",
"timeout-unknown-then-receipt-committed: R39 then R40",
"runs the work for a current account",
"refuses a stale account and does not run the work",
"refuses an identity that does not fit the mode",
"refuses a held add-on as unavailable, and serves it again after the release",
"refuses an empty add-on ID and a nil work function",
"is reached through the gateway provider"
],
"report": ".cache/addons/logs/policy.json"
},
"proposals": {
"kind": "ginkgo",
"commands": [
[
"go",
"test",
"-count=1",
"-p",
"2",
"-tags",
"auth",
"./core/services/addons/policy",
"-ginkgo.json-report=../../../../.cache/addons/logs/proposals.json"
],
[
"go",
"test",
"-count=1",
"-p",
"2",
"-tags",
"auth",
"./core/http/endpoints/addons",
"-ginkgo.json-report=../../../../.cache/addons/logs/proposals-http.json"
]
],
"cases": [
"requires explicit creation authority and keeps pending registrations inaccessible",
"reconciles a registration interrupted by a crash from the durable store",
"keeps a record whose existence cannot be established and settles the rest",
"never drops a committed resource and counts pending quota unchanged",
"retries kept records from the loop on a tick and on a kick, and stops on Close",
"closes a loop that never started without waiting",
"stops admitted work of a revoked user and acknowledges only after it ended",
"lets a racing revocation win against read and write admissions",
"serializes writes per resource while reads run concurrently",
"bounds the revocation wait and does not acknowledge a stuck drain",
"invalidates pending proposals on revoke and downgrade and fails closed when it cannot",
"maps a store outage to unavailable and a disabled account to forbidden",
"maps opaque ids to the trusted addon and owner and keeps an absent policy denying",
"disables sharing in explicit local-owner mode and lets every local caller own the resource",
"refuses a mode switch of populated data without a stopped backed-up migration",
"retains resources and grants across a restart and an uninstall of the package",
"refuses a corrupt store and a second opener",
"caps pending and committed registrations per user and in total",
"applies finite defaults when no limit is configured",
"denies creation as unavailable when the authority cannot tell",
"does not acknowledge a retried downgrade while the lowered user's write still runs",
"retries a failed proposal invalidation after the lowered grant is already durable",
"keeps the drain owed across a restart",
"does not start the work when revocation cancels the admission before run",
"retains resources and grants across a real manager uninstall and restart",
"rejects persisted unknown roles and trailing bytes without resetting the store",
"removes stale temporary files on open",
"stops accepting writes after a failed directory sync and keeps the applied change",
"enforces the viewer editor owner matrix on fixture resources",
"denies installation administrators and unrelated users any access to user data",
"does not leak resource existence and treats unknown actions as owner mutations",
"never grants the owner role or a grant to the owner and the synthetic principals",
"does not cancel work admitted under a later grant when a lowering is retried",
"still waits for and cancels work admitted before the lowering when the regrant is retried",
"stops work admitted after a regrant when the role is lowered again",
"keeps the epoch of the owed drain across a restart",
"keeps a drain mark that a concurrent lowering replaced while a retry was waiting",
"reports an unclassified account or creation check error as unavailable and a definite denial as forbidden",
"rejects anonymous and legacy synthetic principals in named mode",
"checks credential and account status on every admission",
"keeps no current-user state shared between concurrent admissions",
"stores a pending proposal with its exact effects and never executes it",
"applies exactly the stored arguments once and answers a repeat from the stored receipt",
"refuses changed arguments, other actors, unknown identifiers and an unbound digest",
"never lets an API key, plain text or a boolean approve",
"accepts the local owner as the confirming principal in local-owner mode only",
"expires a proposal and refuses a late or repeated confirmation",
"refuses a proposal made stale by a new generation or a moved revision",
"cancels a proposal for good and restricts who may propose which action",
"never accepts sharing, deletion, reads or unclassified actions as proposals",
"cancels pending proposals when authority is lowered and lets a revocation win the confirmation race",
"persists every transition atomically before it is reported",
"does not dispatch when the executing state cannot be made durable",
"keeps a lost reply unknown, blocks conflicting writes and resolves it by receipt without a replay",
"reports a lost reply from the owner's own gateway with the original operation",
"recovers a crash after dispatch by receipt and a crash before dispatch as unknown without replay",
"keeps pending proposals across a restart and never resets a corrupt store",
"bounds the pending proposals of one user and the store as a whole",
"records expiry and collects settled proposals without any read so a quiet clock cannot fill the store",
"records expiry durably when the owner starts and when it recovers",
"keeps settled proposals for the retention window only",
"keeps one user from starving others and never drops another user's live proposal",
"bounds the stored canonical arguments per user and in total with a typed quota error",
"looks an unresolved receipt up again with backoff for a finite window and never applies again",
"lets only the resource owner's browser session abandon an unresolved outcome and then unblocks writes",
"records a late receipt of an abandoned outcome instead of hiding it",
"settles by lookup instead of abandoning when the receipt is final",
"refuses a stored abandonment that names nobody and keeps looking up in the background",
"binds the digest to the operation, actor, resource, generation, action, arguments and revision",
"refuses a stored proposal whose operation, actor, resource, generation or arguments changed at rest",
"issues resource identifiers the envelope contract accepts",
"is unavailable until it is attached to a policy and a runtime",
"keeps executing, outcome-unknown and abandoned records far past retention and still dedupes them",
"waits for the background run and for lookups in flight before it closes, and writes nothing after",
"lets the owner role list the unresolved proposals of its resource and abandon one by the listed digest",
"names the blocking proposal in the denial only to the resource owner",
"refuses an unbound digest when the owner abandons through the gateway or the broker",
"answers the same typed outage for a resolution whoever proposed the operation",
"returns the applied proposal when the owner cannot read it back after a successful apply",
"does not show another user's blocking operation in a proposal view",
"denies a proposal for an undeclared tool before any preview and stores nothing",
"denies a proposal that names a tool when no tool source is installed",
"rechecks the stored tool at confirmation and never applies a withdrawn tool",
"denies a proposal whose arguments repeat a key and stores nothing",
"reports an unavailable declaration source as unavailable, never as a denial",
"does not apply at confirmation while the declaration source is unavailable, and applies once it recovers",
"reserves a create proposal as a pending resource that nobody can reach",
"commits the reservation on confirmation and makes the proposer the private owner",
"abandons the reservation when a create proposal is cancelled or expires",
"abandons the reservation when the addon rejects the creation",
"keeps a lost create reply pending and unknown and settles it by receipt",
"abandons an unknown create only when the addon confirms the backing is absent",
"settles reservations at restart by asking the addon and keeps those of live proposals",
"bounds concurrent create proposals by the pending quota",
"lets only the proposer confirm, cancel or read a create proposal",
"denies a create proposal when creation authority is revoked before confirmation",
"denies a create proposal for an undeclared tool or an existing resource without reserving",
"does not let reconcile drop the reservation of a creation in flight",
"commits the reservation at recovery when the crash came after the receipt was stored",
"never reads an add-on that cannot answer as a backing that is gone",
"accepts the explicit answer of the declared existence tool, true or false",
"holds the resources of one add-on and leaves another add-on alone",
"cancels admitted work and reports a drain that did not finish",
"restores grants through the account directory and the lowerings since the backup, never beyond them",
"keeps a bounded durable log of lowered access",
"keeps a revocation however many later lowerings of another person follow",
"restores the data but no access when the history may have lost a lowering",
"reads a store that is full of lowerings as one whose history may be cut",
"applies a lowering made after the export whatever time the backup is given",
"refuses a change that was authorized just before the hold began",
"cancels a pending proposal and leaves an executing one outcome-unknown after a restore",
"forgets the records of one add-on and no other",
"maps an owner on a restore to a local-owner store only when nothing named is in it",
"migrates the ownership of a stopped store with a backup and an explicit mapping and refuses a populated downgrade",
"refuses a proposal whose preview the add-on refused, storing nothing",
"settles a confirmation the add-on refused as rejected, never as an unknown outcome",
"stores a proposal from an API key and lets only the proposer's browser session confirm it",
"cancels a proposal from the same chain and never lets typed dispatch or relay confirm",
"denies sharing and deletion proposals and an unauthenticated caller",
"serves the local owner's confirmation only from a same-origin fetch of the host page",
"reports a lost reply with the original operation from forwarding frontends and resolves it by receipt",
"lets only the resource owner's browser session abandon an unresolved outcome and then accepts writes",
"lets the owner role list an editor's unresolved proposal and abandon it by the listed digest from every frontend",
"tells an editor of a blocked write only that it is denied",
"returns the applied proposal when the confirmed operation committed",
"answers an owner outage by the owner's state with the same type from every frontend",
"keeps a proposal confirmable by the same ID after the owner could not reach the addon",
"documents the proposal routes and the proposal schema in the Swagger spec",
"serves one owner journal through two real authenticated HTTP frontends and rejects paused keys",
"serves the synthetic owner through the real chain, denies sharing and rejects named callers",
"checks browser CSRF feature and admin access with real stored keys",
"serves a private file result as a safe attachment over real HTTP",
"never renders hostile names or active media types inline",
"answers one 403 for unknown, foreign, incomplete and expired artifacts and requires the feature and a principal",
"denies the download of a disabled addon and serves it again after enable",
"relays the same bytes, headers and denials through two forwarding frontends",
"keeps a file result of a read denied whole without an artifact store",
"serves the local owner's file only in local-owner mode",
"documents the artifact routes and the artifact schema in the Swagger spec",
"rejects anonymous callers and forged forwarding headers",
"gates the feature and then administration for named keys",
"requires same-origin browser requests for cookie mutations",
"registers only the dispatch, relay and proposal mutations",
"reserves every first path segment the host registers under /api/addons",
"gates the artifact routes by authentication and feature",
"gates the proposal routes by feature and refuses a confirmation from a key before the owner is asked",
"rejects anonymous and forged forwarding authority through real authentication",
"lets callers through only when the deployment selected local-owner mode",
"keeps authentication, the feature gate and administration when accounts exist",
"reports an unknown mutation outcome from a forwarding frontend with the original operation",
"documents every field the error responses emit in the Swagger schema",
"reports an unavailable read as plain unavailability",
"reports a denial as forbidden",
"reports an unclassified account check error as unavailable and a definite denial as forbidden",
"reports an unknown mutation outcome from the owner's own frontend with the original operation",
"lists the enabled installed apps for a reader and the disabled ones too for administrators, the same from every frontend",
"lets only administrators start and stop, through the lifecycle manager, and denies a stale generation",
"serves the verified icon through the host route and denies it identically otherwise",
"reports a lost start as an unknown outcome with its original operation and a lost list as unavailable",
"documents the apps routes and every field of the app view in the Swagger spec",
"lists every registered addon route in the feature registry",
"gates the apps routes by authentication, feature and administration",
"serves catalog search, details and the installed management view to administrators only, the same from every frontend",
"refuses every management call of the owner itself for a caller that is not an administrator",
"saves, refreshes and removes a library by reference and leaves installed addons alone",
"upgrades an installed addon through the typed action and keeps its earlier generation",
"reports a lost source change as an unknown outcome and a lost read as unavailable",
"documents the management actions and every emitted field of the installed view",
"serves the declared files of the current package through every frontend with immutable headers",
"lists the same URLs the route serves, and only for an enabled addon",
"denies every other path, digest, addon and credential form with one answer and no immutable caching",
"accepts a same-origin browser session and refuses a cross-site or direct one",
"withdraws the code the moment the addon is disabled, uninstalled or replaced, even for a page that is still open",
"refuses a declared file that is not a regular file of the package",
"documents the asset route and its binary response in the Swagger spec",
"gives the same 403 on the owner and on a forwarding frontend and never contacts the add-on",
"lists the caller's own pending proposals the same from the owner and every forwarding frontend",
"gives every caller with the feature the same status from every frontend, redacted for non-administrators",
"checks only for an administrator's own browser session, and applies nothing",
"upgrades only to the checked candidate, with the same typed refusals from every frontend, and never twice",
"runs two concurrent upgrades from two frontends once: the same ID shares the answer, another ID is a conflict",
"refuses an incompatible candidate and a library that cannot be read, with a typed answer",
"reports a lost upgrade as an unknown outcome with its original operation, and a lost status read or check as plainly unavailable",
"keeps the update actions out of the tools and names every field of the status in the Swagger spec",
"answers an add-on's invalid-request refusal as a typed 400 from the owner and from a forwarding frontend",
"R34: returns an admission that was refused before the wire to pending, and a repeat applies",
"R35, R52: a hold that cancels the dispatch before the wire ends the proposal as cancelled, not unknown",
"R38: records a conflict of the add-on as rejected, not unknown",
"R39: still records an unknown outcome when the request may have been sent",
"reports a not-sent confirmation through the gateway as an outage that sent nothing, never as unknown",
"is a refusal that changed nothing, not an outage, and leaves the ID free",
"R4, S4: refuses an editor who claims the write action for a schema tool, and stores nothing",
"R4: refuses an editor who names the schema action for a schema tool",
"derives the action from the tool, so the owner needs the matching claim and gets the schema action",
"still lets an editor propose a data write for a write tool",
"R3: refuses a read tool, a create tool and a tool without a definition",
"runs the declaration check as well as the kind check",
"refuses a named tool when the source cannot report kinds",
"R3: a creation names a create tool, never a schema or data tool",
"retry-after-not-sent: R34 then R37",
"addon-conflict-is-rejected: R38",
"timeout-unknown-then-receipt-committed: R39 then R40",
"runs the work for a current account",
"refuses a stale account and does not run the work",
"refuses an identity that does not fit the mode",
"refuses a held add-on as unavailable, and serves it again after the release",
"refuses an empty add-on ID and a nil work function",
"is reached through the gateway provider",
"Sec-Fetch-Site cross-site is refused even with a Referer on the same host",
"Sec-Fetch-Site same-origin passes",
"Sec-Fetch-Site same-site is refused",
"a request without a session cookie is not guarded",
"no Sec-Fetch-Site and no Origin or Referer is refused",
"no Sec-Fetch-Site with a Referer on the same host passes",
"no Sec-Fetch-Site with a foreign Origin is refused",
"no Sec-Fetch-Site with a foreign Origin is refused even with a Referer on the same host",
"no Sec-Fetch-Site with a foreign Referer is refused",
"no Sec-Fetch-Site with a null Origin is refused",
"no Sec-Fetch-Site with an Origin on the same host passes",
"no Sec-Fetch-Site with the same host on another port is refused",
"matches the host without regard to letter case",
"gives no pins to an account created after the upgrade",
"round-trips pins for the local owner",
"drops IDs the caller cannot see",
"an object",
"numbers",
"not JSON",
"empty",
"null",
"rejects a list over the hard limit",
"does not show Studio and Talk as pins without the add-ons",
"lists add-ons by default, and takes a kind that this host reads",
"is empty because Studio and Talk are packaged add-ons",
"lists every entry without an account database",
"strict same-origin fetch",
"same-origin without destination",
"same-host Referer, no Sec-Fetch headers",
"same-host Origin, no Sec-Fetch headers",
"foreign Referer",
"same host, other port",
"foreign Origin wins over same-host Referer",
"no Origin and no Referer",
"cross-site with same-host Referer",
"same-site with same-host Origin",
"same-host Referer but navigation destination",
"same-host Referer but no-cors mode",
"still refuses a same-host Referer with an API key",
"returns the SDK refusal text, the unverified-package text and the missing-release text to the administrator",
"logs the cause of a failed install and types it for the client",
"logs the reason behind a generic denial and leaves the response unchanged",
"returns the same text through a forwarding frontend",
"names every typed cause of a failed install in the 403 of the dispatch route"
],
"report": ".cache/addons/logs/proposals.json",
"reports": [
{
"path": ".cache/addons/logs/proposals.json",
"cases": [
"requires explicit creation authority and keeps pending registrations inaccessible",
"reconciles a registration interrupted by a crash from the durable store",
"keeps a record whose existence cannot be established and settles the rest",
"never drops a committed resource and counts pending quota unchanged",
"retries kept records from the loop on a tick and on a kick, and stops on Close",
"closes a loop that never started without waiting",
"stops admitted work of a revoked user and acknowledges only after it ended",
"lets a racing revocation win against read and write admissions",
"serializes writes per resource while reads run concurrently",
"bounds the revocation wait and does not acknowledge a stuck drain",
"invalidates pending proposals on revoke and downgrade and fails closed when it cannot",
"maps a store outage to unavailable and a disabled account to forbidden",
"maps opaque ids to the trusted addon and owner and keeps an absent policy denying",
"disables sharing in explicit local-owner mode and lets every local caller own the resource",
"refuses a mode switch of populated data without a stopped backed-up migration",
"retains resources and grants across a restart and an uninstall of the package",
"refuses a corrupt store and a second opener",
"caps pending and committed registrations per user and in total",
"applies finite defaults when no limit is configured",
"denies creation as unavailable when the authority cannot tell",
"does not acknowledge a retried downgrade while the lowered user's write still runs",
"retries a failed proposal invalidation after the lowered grant is already durable",
"keeps the drain owed across a restart",
"does not start the work when revocation cancels the admission before run",
"retains resources and grants across a real manager uninstall and restart",
"rejects persisted unknown roles and trailing bytes without resetting the store",
"removes stale temporary files on open",
"stops accepting writes after a failed directory sync and keeps the applied change",
"enforces the viewer editor owner matrix on fixture resources",
"denies installation administrators and unrelated users any access to user data",
"does not leak resource existence and treats unknown actions as owner mutations",
"never grants the owner role or a grant to the owner and the synthetic principals",
"does not cancel work admitted under a later grant when a lowering is retried",
"still waits for and cancels work admitted before the lowering when the regrant is retried",
"stops work admitted after a regrant when the role is lowered again",
"keeps the epoch of the owed drain across a restart",
"keeps a drain mark that a concurrent lowering replaced while a retry was waiting",
"reports an unclassified account or creation check error as unavailable and a definite denial as forbidden",
"rejects anonymous and legacy synthetic principals in named mode",
"checks credential and account status on every admission",
"keeps no current-user state shared between concurrent admissions",
"stores a pending proposal with its exact effects and never executes it",
"applies exactly the stored arguments once and answers a repeat from the stored receipt",
"refuses changed arguments, other actors, unknown identifiers and an unbound digest",
"never lets an API key, plain text or a boolean approve",
"accepts the local owner as the confirming principal in local-owner mode only",
"expires a proposal and refuses a late or repeated confirmation",
"refuses a proposal made stale by a new generation or a moved revision",
"cancels a proposal for good and restricts who may propose which action",
"never accepts sharing, deletion, reads or unclassified actions as proposals",
"cancels pending proposals when authority is lowered and lets a revocation win the confirmation race",
"persists every transition atomically before it is reported",
"does not dispatch when the executing state cannot be made durable",
"keeps a lost reply unknown, blocks conflicting writes and resolves it by receipt without a replay",
"reports a lost reply from the owner's own gateway with the original operation",
"recovers a crash after dispatch by receipt and a crash before dispatch as unknown without replay",
"keeps pending proposals across a restart and never resets a corrupt store",
"bounds the pending proposals of one user and the store as a whole",
"records expiry and collects settled proposals without any read so a quiet clock cannot fill the store",
"records expiry durably when the owner starts and when it recovers",
"keeps settled proposals for the retention window only",
"keeps one user from starving others and never drops another user's live proposal",
"bounds the stored canonical arguments per user and in total with a typed quota error",
"looks an unresolved receipt up again with backoff for a finite window and never applies again",
"lets only the resource owner's browser session abandon an unresolved outcome and then unblocks writes",
"records a late receipt of an abandoned outcome instead of hiding it",
"settles by lookup instead of abandoning when the receipt is final",
"refuses a stored abandonment that names nobody and keeps looking up in the background",
"binds the digest to the operation, actor, resource, generation, action, arguments and revision",
"refuses a stored proposal whose operation, actor, resource, generation or arguments changed at rest",
"issues resource identifiers the envelope contract accepts",
"is unavailable until it is attached to a policy and a runtime",
"keeps executing, outcome-unknown and abandoned records far past retention and still dedupes them",
"waits for the background run and for lookups in flight before it closes, and writes nothing after",
"lets the owner role list the unresolved proposals of its resource and abandon one by the listed digest",
"names the blocking proposal in the denial only to the resource owner",
"refuses an unbound digest when the owner abandons through the gateway or the broker",
"answers the same typed outage for a resolution whoever proposed the operation",
"returns the applied proposal when the owner cannot read it back after a successful apply",
"does not show another user's blocking operation in a proposal view",
"denies a proposal for an undeclared tool before any preview and stores nothing",
"denies a proposal that names a tool when no tool source is installed",
"rechecks the stored tool at confirmation and never applies a withdrawn tool",
"denies a proposal whose arguments repeat a key and stores nothing",
"reports an unavailable declaration source as unavailable, never as a denial",
"does not apply at confirmation while the declaration source is unavailable, and applies once it recovers",
"reserves a create proposal as a pending resource that nobody can reach",
"commits the reservation on confirmation and makes the proposer the private owner",
"abandons the reservation when a create proposal is cancelled or expires",
"abandons the reservation when the addon rejects the creation",
"keeps a lost create reply pending and unknown and settles it by receipt",
"abandons an unknown create only when the addon confirms the backing is absent",
"settles reservations at restart by asking the addon and keeps those of live proposals",
"bounds concurrent create proposals by the pending quota",
"lets only the proposer confirm, cancel or read a create proposal",
"denies a create proposal when creation authority is revoked before confirmation",
"denies a create proposal for an undeclared tool or an existing resource without reserving",
"does not let reconcile drop the reservation of a creation in flight",
"commits the reservation at recovery when the crash came after the receipt was stored",
"never reads an add-on that cannot answer as a backing that is gone",
"accepts the explicit answer of the declared existence tool, true or false",
"holds the resources of one add-on and leaves another add-on alone",
"cancels admitted work and reports a drain that did not finish",
"restores grants through the account directory and the lowerings since the backup, never beyond them",
"keeps a bounded durable log of lowered access",
"keeps a revocation however many later lowerings of another person follow",
"restores the data but no access when the history may have lost a lowering",
"reads a store that is full of lowerings as one whose history may be cut",
"applies a lowering made after the export whatever time the backup is given",
"refuses a change that was authorized just before the hold began",
"cancels a pending proposal and leaves an executing one outcome-unknown after a restore",
"forgets the records of one add-on and no other",
"maps an owner on a restore to a local-owner store only when nothing named is in it",
"migrates the ownership of a stopped store with a backup and an explicit mapping and refuses a populated downgrade",
"refuses a proposal whose preview the add-on refused, storing nothing",
"settles a confirmation the add-on refused as rejected, never as an unknown outcome",
"R34: returns an admission that was refused before the wire to pending, and a repeat applies",
"R35, R52: a hold that cancels the dispatch before the wire ends the proposal as cancelled, not unknown",
"R38: records a conflict of the add-on as rejected, not unknown",
"R39: still records an unknown outcome when the request may have been sent",
"reports a not-sent confirmation through the gateway as an outage that sent nothing, never as unknown",
"is a refusal that changed nothing, not an outage, and leaves the ID free",
"R4, S4: refuses an editor who claims the write action for a schema tool, and stores nothing",
"R4: refuses an editor who names the schema action for a schema tool",
"derives the action from the tool, so the owner needs the matching claim and gets the schema action",
"still lets an editor propose a data write for a write tool",
"R3: refuses a read tool, a create tool and a tool without a definition",
"runs the declaration check as well as the kind check",
"refuses a named tool when the source cannot report kinds",
"R3: a creation names a create tool, never a schema or data tool",
"retry-after-not-sent: R34 then R37",
"addon-conflict-is-rejected: R38",
"timeout-unknown-then-receipt-committed: R39 then R40",
"runs the work for a current account",
"refuses a stale account and does not run the work",
"refuses an identity that does not fit the mode",
"refuses a held add-on as unavailable, and serves it again after the release",
"refuses an empty add-on ID and a nil work function",
"is reached through the gateway provider"
]
},
{
"path": ".cache/addons/logs/proposals-http.json",
"cases": [
"stores a proposal from an API key and lets only the proposer's browser session confirm it",
"cancels a proposal from the same chain and never lets typed dispatch or relay confirm",
"denies sharing and deletion proposals and an unauthenticated caller",
"serves the local owner's confirmation only from a same-origin fetch of the host page",
"reports a lost reply with the original operation from forwarding frontends and resolves it by receipt",
"lets only the resource owner's browser session abandon an unresolved outcome and then accepts writes",
"lets the owner role list an editor's unresolved proposal and abandon it by the listed digest from every frontend",
"tells an editor of a blocked write only that it is denied",
"returns the applied proposal when the confirmed operation committed",
"answers an owner outage by the owner's state with the same type from every frontend",
"keeps a proposal confirmable by the same ID after the owner could not reach the addon",
"documents the proposal routes and the proposal schema in the Swagger spec",
"serves one owner journal through two real authenticated HTTP frontends and rejects paused keys",
"serves the synthetic owner through the real chain, denies sharing and rejects named callers",
"checks browser CSRF feature and admin access with real stored keys",
"serves a private file result as a safe attachment over real HTTP",
"never renders hostile names or active media types inline",
"answers one 403 for unknown, foreign, incomplete and expired artifacts and requires the feature and a principal",
"denies the download of a disabled addon and serves it again after enable",
"relays the same bytes, headers and denials through two forwarding frontends",
"keeps a file result of a read denied whole without an artifact store",
"serves the local owner's file only in local-owner mode",
"documents the artifact routes and the artifact schema in the Swagger spec",
"rejects anonymous callers and forged forwarding headers",
"gates the feature and then administration for named keys",
"requires same-origin browser requests for cookie mutations",
"registers only the dispatch, relay and proposal mutations",
"reserves every first path segment the host registers under /api/addons",
"gates the artifact routes by authentication and feature",
"gates the proposal routes by feature and refuses a confirmation from a key before the owner is asked",
"rejects anonymous and forged forwarding authority through real authentication",
"lets callers through only when the deployment selected local-owner mode",
"keeps authentication, the feature gate and administration when accounts exist",
"reports an unknown mutation outcome from a forwarding frontend with the original operation",
"documents every field the error responses emit in the Swagger schema",
"reports an unavailable read as plain unavailability",
"reports a denial as forbidden",
"reports an unclassified account check error as unavailable and a definite denial as forbidden",
"reports an unknown mutation outcome from the owner's own frontend with the original operation",
"lists the enabled installed apps for a reader and the disabled ones too for administrators, the same from every frontend",
"lets only administrators start and stop, through the lifecycle manager, and denies a stale generation",
"serves the verified icon through the host route and denies it identically otherwise",
"reports a lost start as an unknown outcome with its original operation and a lost list as unavailable",
"documents the apps routes and every field of the app view in the Swagger spec",
"lists every registered addon route in the feature registry",
"gates the apps routes by authentication, feature and administration",
"serves catalog search, details and the installed management view to administrators only, the same from every frontend",
"refuses every management call of the owner itself for a caller that is not an administrator",
"saves, refreshes and removes a library by reference and leaves installed addons alone",
"upgrades an installed addon through the typed action and keeps its earlier generation",
"reports a lost source change as an unknown outcome and a lost read as unavailable",
"documents the management actions and every emitted field of the installed view",
"serves the declared files of the current package through every frontend with immutable headers",
"lists the same URLs the route serves, and only for an enabled addon",
"denies every other path, digest, addon and credential form with one answer and no immutable caching",
"accepts a same-origin browser session and refuses a cross-site or direct one",
"withdraws the code the moment the addon is disabled, uninstalled or replaced, even for a page that is still open",
"refuses a declared file that is not a regular file of the package",
"documents the asset route and its binary response in the Swagger spec",
"gives the same 403 on the owner and on a forwarding frontend and never contacts the add-on",
"lists the caller's own pending proposals the same from the owner and every forwarding frontend",
"gives every caller with the feature the same status from every frontend, redacted for non-administrators",
"checks only for an administrator's own browser session, and applies nothing",
"upgrades only to the checked candidate, with the same typed refusals from every frontend, and never twice",
"runs two concurrent upgrades from two frontends once: the same ID shares the answer, another ID is a conflict",
"refuses an incompatible candidate and a library that cannot be read, with a typed answer",
"reports a lost upgrade as an unknown outcome with its original operation, and a lost status read or check as plainly unavailable",
"keeps the update actions out of the tools and names every field of the status in the Swagger spec",
"answers an add-on's invalid-request refusal as a typed 400 from the owner and from a forwarding frontend",
"returns the same text through a forwarding frontend",
"Sec-Fetch-Site cross-site is refused even with a Referer on the same host",
"Sec-Fetch-Site same-origin passes",
"Sec-Fetch-Site same-site is refused",
"a request without a session cookie is not guarded",
"no Sec-Fetch-Site and no Origin or Referer is refused",
"no Sec-Fetch-Site with a Referer on the same host passes",
"no Sec-Fetch-Site with a foreign Origin is refused",
"no Sec-Fetch-Site with a foreign Origin is refused even with a Referer on the same host",
"no Sec-Fetch-Site with a foreign Referer is refused",
"no Sec-Fetch-Site with a null Origin is refused",
"no Sec-Fetch-Site with an Origin on the same host passes",
"no Sec-Fetch-Site with the same host on another port is refused",
"matches the host without regard to letter case",
"gives no pins to an account created after the upgrade",
"round-trips pins for the local owner",
"drops IDs the caller cannot see",
"an object",
"numbers",
"not JSON",
"empty",
"null",
"rejects a list over the hard limit",
"does not show Studio and Talk as pins without the add-ons",
"lists add-ons by default, and takes a kind that this host reads",
"is empty because Studio and Talk are packaged add-ons",
"lists every entry without an account database",
"strict same-origin fetch",
"same-origin without destination",
"same-host Referer, no Sec-Fetch headers",
"same-host Origin, no Sec-Fetch headers",
"foreign Referer",
"same host, other port",
"foreign Origin wins over same-host Referer",
"no Origin and no Referer",
"cross-site with same-host Referer",
"same-site with same-host Origin",
"same-host Referer but navigation destination",
"same-host Referer but no-cors mode",
"still refuses a same-host Referer with an API key",
"returns the SDK refusal text, the unverified-package text and the missing-release text to the administrator",
"logs the cause of a failed install and types it for the client",
"logs the reason behind a generic denial and leaves the response unchanged",
"names every typed cause of a failed install in the 403 of the dispatch route"
]
}
]
},
"artifacts": {
"kind": "ginkgo",
"commands": [
[
"go",
"test",
"-count=1",
"-p",
"2",
"-tags",
"auth",
"./core/services/addons/artifacts",
"-ginkgo.json-report=../../../../.cache/addons/logs/artifacts.json"
],
[
"go",
"test",
"-count=1",
"-p",
"2",
"-tags",
"auth",
"./core/services/addons/gateway",
"-ginkgo.json-report=../../../../.cache/addons/logs/artifacts-gateway.json"
],
[
"go",
"test",
"-count=1",
"-p",
"2",
"-tags",
"auth",
"./core/http/endpoints/addons",
"-ginkgo.json-report=../../../../.cache/addons/logs/artifacts-http.json"
]
],
"cases": [
"adopts every output of a result or none, and shows the owner only its own status",
"sanitizes attachment names and maps media types to a fixed allowlist",
"applies finite default limits and rejects partial or unbounded overrides",
"keeps staged bytes behind the object store boundary and publishes only complete writes",
"never serves an artifact at or after expiry, including during admission and mid-stream",
"fails a transfer that outlives its artifact",
"fails a transfer whose source is revoked before completion and denies a revoked download",
"stops a download stream when the source is revoked mid-stream",
"requires read access to every source resource at completion and download",
"denies a disabled or unavailable account at ingestion and download",
"denies downloads of a disabled addon, keeps the bytes and serves again only while unexpired with current permissions",
"denies downloads after uninstall and removes the bytes at the next sweep",
"sweeps expired artifacts, abandoned partials and orphan files without touching live transfers",
"enforces per-user, total and size limits atomically under concurrent ingestion",
"bounds concurrent transfers and concurrent downloads",
"cancels a transfer by its context or by its owner and removes the partial bytes",
"returns the same artifact for a repeated request without a second transfer",
"keeps addon handles operation-bound and out of metadata and views",
"keeps complete artifacts across a restart and settles interrupted transfers",
"keeps the bytes of a transfer that completes while a sweep is running",
"never loses the bytes of a complete artifact when sweeps race with several completing transfers",
"answers a transient storage error as unavailable and keeps the bytes and the record",
"marks an artifact corrupt only for missing bytes or a size mismatch",
"answers a download that races with an expiry or a drop like any expired identifier",
"refuses a corrupt metadata store and stops writing after a failed sync",
"waits for background transfers before Close returns and writes nothing after",
"ingests a file result into a private staged artifact with a host-generated identifier",
"never uses an addon handle, URL or path as an identifier or a file path",
"answers one denial for an unknown identifier and for another principal's artifact",
"never serves incomplete, short, long or failed transfers and removes their partial bytes",
"streams ingestion and download without buffering the whole file",
"rejects an output declared larger than one artifact may be before reading it",
"never opens an output for a request that names a tool no source declares",
"denies an output request whose arguments repeat a key and never opens the output",
"reports an unavailable declaration source as unavailable and never opens the output",
"shortens the lifetime and keeps the bounds consistent, and zero keeps the defaults",
"fails the artifact with a fixed reason that says it was refused, not that the add-on is down",
"serves only declared installed generation assets and rejects traversal",
"fails closed without current identity or resource policy and reports the original ID of an unknown mutation outcome",
"reports an unclassified account check error as unavailable on every path and a wrapped denial as forbidden",
"propagates interrupted progress cancellation through the receiving frontend",
"validates finite relay budgets and prevents disabling polling bounds",
"builds a carrier only from complete pinned identities",
"types an unknown mutation outcome as unavailable without losing its operation",
"rejects untrusted peers wrong audience body expiry replay and revoked credentials",
"alternates pinned frontends and rejects untrusted certificates without local fallback",
"reports the original operation after lost mutation replies without retrying",
"rejects a stream longer than its receiving frontend budget",
"rejects a CA signed peer without a pin on the owner side",
"refuses an owner whose CA signed certificate is not the pinned owner",
"returns the artifact status through the owner from every frontend with one denial for the rest",
"types the owner's refusal and outage of a lookup the same from every frontend",
"writes an attachment header that cannot be broken out of",
"rotates the enforced audience on restart and rejects captured requests",
"never expires the response deadline after the relay returned",
"returns the owner's forbidden status for an invalid kind and for missing policy",
"still reports unavailable when the owner is unable to serve and not forbidden",
"reaches the same decision through both frontends and delivers bytes when allowed",
"keeps aborting when revocation happens after bytes were written",
"bounds progress, asset and file relays by their own limit",
"alternates real owner journal status and terminates coarse progress without submitting again",
"reports an account store outage as unavailable and a refused account as forbidden",
"rejects unknown lifecycle argument fields before touching the owner journal",
"reports a runtime that cannot serve as unavailable through both frontends",
"reports an output that ends before its first byte as unavailable",
"fails closed as unavailable for an unclassified owner error",
"keeps authorization and policy denials forbidden",
"keeps a mutation unknown when the runtime fails after the owner applied it",
"keeps a mutation unknown when the owner reports recovery required for its operation",
"reports a mutation as unknown when the owner cannot serve it at all",
"keeps a mutation unknown on the owner's own frontend and leaves reads and denials alone",
"lets unavailability win when an error wraps both a denial and an unavailable cause",
"does not leak attachment headers into an error when the first read fails",
"treats every action except the known reads as a mutation",
"keeps resolved resources under admission for JSON and attachment bytes",
"closes interrupted output and releases admission on disconnect",
"rechecks revoked credentials during attachment copying",
"adopts read outputs as private artifacts inside admission and replaces a forged resource identity",
"refuses at ingest a file result larger than the relay file bound so nothing unservable is staged",
"denies private relays without host resolution and admission",
"serves declared assets of the current enabled generation by package digest only",
"allows only an exact declared tool name and fails closed otherwise",
"never contacts the add-on for an undeclared tool and still serves a declared one",
"denies a repeated key at any depth however it is spelled",
"denies arguments that are not exactly one object",
"separates a denial from an unavailable declaration source",
"answers 503 and never contacts the add-on when the source is unavailable or the arguments repeat a key",
"is the typed invalid request on the owner for a read, never an outage",
"is the typed invalid request on the owner for a proposal call",
"is the typed invalid request on the owner for a json relay",
"is the same typed answer from a forwarding frontend",
"stores a proposal from an API key and lets only the proposer's browser session confirm it",
"cancels a proposal from the same chain and never lets typed dispatch or relay confirm",
"denies sharing and deletion proposals and an unauthenticated caller",
"serves the local owner's confirmation only from a same-origin fetch of the host page",
"reports a lost reply with the original operation from forwarding frontends and resolves it by receipt",
"lets only the resource owner's browser session abandon an unresolved outcome and then accepts writes",
"lets the owner role list an editor's unresolved proposal and abandon it by the listed digest from every frontend",
"tells an editor of a blocked write only that it is denied",
"returns the applied proposal when the confirmed operation committed",
"answers an owner outage by the owner's state with the same type from every frontend",
"keeps a proposal confirmable by the same ID after the owner could not reach the addon",
"documents the proposal routes and the proposal schema in the Swagger spec",
"serves one owner journal through two real authenticated HTTP frontends and rejects paused keys",
"serves the synthetic owner through the real chain, denies sharing and rejects named callers",
"checks browser CSRF feature and admin access with real stored keys",
"serves a private file result as a safe attachment over real HTTP",
"never renders hostile names or active media types inline",
"answers one 403 for unknown, foreign, incomplete and expired artifacts and requires the feature and a principal",
"denies the download of a disabled addon and serves it again after enable",
"relays the same bytes, headers and denials through two forwarding frontends",
"keeps a file result of a read denied whole without an artifact store",
"serves the local owner's file only in local-owner mode",
"documents the artifact routes and the artifact schema in the Swagger spec",
"rejects anonymous callers and forged forwarding headers",
"gates the feature and then administration for named keys",
"requires same-origin browser requests for cookie mutations",
"registers only the dispatch, relay and proposal mutations",
"reserves every first path segment the host registers under /api/addons",
"gates the artifact routes by authentication and feature",
"gates the proposal routes by feature and refuses a confirmation from a key before the owner is asked",
"rejects anonymous and forged forwarding authority through real authentication",
"lets callers through only when the deployment selected local-owner mode",
"keeps authentication, the feature gate and administration when accounts exist",
"reports an unknown mutation outcome from a forwarding frontend with the original operation",
"documents every field the error responses emit in the Swagger schema",
"reports an unavailable read as plain unavailability",
"reports a denial as forbidden",
"reports an unclassified account check error as unavailable and a definite denial as forbidden",
"reports an unknown mutation outcome from the owner's own frontend with the original operation",
"lists the enabled installed apps for a reader and the disabled ones too for administrators, the same from every frontend",
"lets only administrators start and stop, through the lifecycle manager, and denies a stale generation",
"serves the verified icon through the host route and denies it identically otherwise",
"reports a lost start as an unknown outcome with its original operation and a lost list as unavailable",
"documents the apps routes and every field of the app view in the Swagger spec",
"lists every registered addon route in the feature registry",
"gates the apps routes by authentication, feature and administration",
"serves catalog search, details and the installed management view to administrators only, the same from every frontend",
"refuses every management call of the owner itself for a caller that is not an administrator",
"saves, refreshes and removes a library by reference and leaves installed addons alone",
"upgrades an installed addon through the typed action and keeps its earlier generation",
"reports a lost source change as an unknown outcome and a lost read as unavailable",
"documents the management actions and every emitted field of the installed view",
"serves the declared files of the current package through every frontend with immutable headers",
"lists the same URLs the route serves, and only for an enabled addon",
"denies every other path, digest, addon and credential form with one answer and no immutable caching",
"accepts a same-origin browser session and refuses a cross-site or direct one",
"withdraws the code the moment the addon is disabled, uninstalled or replaced, even for a page that is still open",
"refuses a declared file that is not a regular file of the package",
"documents the asset route and its binary response in the Swagger spec",
"gives the same 403 on the owner and on a forwarding frontend and never contacts the add-on",
"lists the caller's own pending proposals the same from the owner and every forwarding frontend",
"gives every caller with the feature the same status from every frontend, redacted for non-administrators",
"checks only for an administrator's own browser session, and applies nothing",
"upgrades only to the checked candidate, with the same typed refusals from every frontend, and never twice",
"runs two concurrent upgrades from two frontends once: the same ID shares the answer, another ID is a conflict",
"refuses an incompatible candidate and a library that cannot be read, with a typed answer",
"reports a lost upgrade as an unknown outcome with its original operation, and a lost status read or check as plainly unavailable",
"keeps the update actions out of the tools and names every field of the status in the Swagger spec",
"answers an add-on's invalid-request refusal as a typed 400 from the owner and from a forwarding frontend",
"crosses the owner's wire as the same typed error, whatever the frontend",
"does not trust a code the host does not know, and cleans the detail the add-on wrote",
"is a stale view for a caller that only knows ErrStale, and a denial otherwise",
"is a mutation on the carrier: a lost answer is an unknown outcome, never a plain outage",
"runs on the owner for the actor the signature binds, and the typed direct dispatch still refuses it",
"keeps the answer of a call that outlasts the write timeout of the owner server",
"is an unknown outcome when the answer is lost",
"runs the backend-releases check for a pinned frontend without an actor",
"refuses a system call from a peer that is not pinned",
"never lets a system call change anything or ride the user-facing route",
"writes the set with private modes and no CA key",
"loads both roles into carriers and serves a frontend call from the owner",
"gives the owner no signing key and the frontend its own",
"accepts two frontends made from the same set",
"refuses a frontend from another generation",
"reads only the files of the role",
"refuses a key file with group or other access",
"refuses an unknown role",
"refuses to overwrite a file and leaves it unchanged",
"needs an owner host",
"says nothing was sent when the add-on is not running, instead of an unknown outcome",
"runs a declared action tool for the calling user, under the act scope, admitted as an add-on call",
"is not reachable through the typed dispatch of the direct API",
"refuses what is not a declared action tool",
"refuses an add-on that did not declare actions",
"is unavailable when the runtime does not serve action tools, and never runs for an unvalidated user",
"reports an unknown outcome, not a refusal, when the runtime fails after the call began",
"runs a resource-less read tool for the calling user only",
"denies a tool that declares a resource when none is given, and never reaches the add-on",
"denies a resource-less read when the admission cannot admit an add-on, or the tool is undeclared",
"keeps its address stable across starts",
"does not share state between different roots",
"fails clearly when the port is in use",
"rejects an invalid port file",
"rejects a port file with a loose mode",
"rejects a port file that links outside the root",
"is not permitted when the add-on denies the person, on the owner and on a forwarding frontend",
"is an unreachable resource when the policy denies it, on the owner and on a forwarding frontend",
"types the denial of a read like the denial of a write, on the owner and on a forwarding frontend",
"crosses the wire of a resource call typed, so a forwarding frontend answers like the owner",
"keeps any other failure to resolve a resource a plain denial, so nothing more is told",
"Sec-Fetch-Site cross-site is refused even with a Referer on the same host",
"Sec-Fetch-Site same-origin passes",
"Sec-Fetch-Site same-site is refused",
"a request without a session cookie is not guarded",
"no Sec-Fetch-Site and no Origin or Referer is refused",
"no Sec-Fetch-Site with a Referer on the same host passes",
"no Sec-Fetch-Site with a foreign Origin is refused",
"no Sec-Fetch-Site with a foreign Origin is refused even with a Referer on the same host",
"no Sec-Fetch-Site with a foreign Referer is refused",
"no Sec-Fetch-Site with a null Origin is refused",
"no Sec-Fetch-Site with an Origin on the same host passes",
"no Sec-Fetch-Site with the same host on another port is refused",
"matches the host without regard to letter case",
"gives no pins to an account created after the upgrade",
"round-trips pins for the local owner",
"drops IDs the caller cannot see",
"an object",
"numbers",
"not JSON",
"empty",
"null",
"rejects a list over the hard limit",
"does not show Studio and Talk as pins without the add-ons",
"lists add-ons by default, and takes a kind that this host reads",
"is empty because Studio and Talk are packaged add-ons",
"lists every entry without an account database",
"strict same-origin fetch",
"same-origin without destination",
"same-host Referer, no Sec-Fetch headers",
"same-host Origin, no Sec-Fetch headers",
"foreign Referer",
"same host, other port",
"foreign Origin wins over same-host Referer",
"no Origin and no Referer",
"cross-site with same-host Referer",
"same-site with same-host Origin",
"same-host Referer but navigation destination",
"same-host Referer but no-cors mode",
"still refuses a same-host Referer with an API key",
"returns the SDK refusal text, the unverified-package text and the missing-release text to the administrator",
"logs the cause of a failed install and types it for the client",
"logs the reason behind a generic denial and leaves the response unchanged",
"returns the same text through a forwarding frontend",
"names every typed cause of a failed install in the 403 of the dispatch route"
],
"report": ".cache/addons/logs/artifacts.json",
"reports": [
{
"path": ".cache/addons/logs/artifacts.json",
"cases": [
"adopts every output of a result or none, and shows the owner only its own status",
"sanitizes attachment names and maps media types to a fixed allowlist",
"applies finite default limits and rejects partial or unbounded overrides",
"keeps staged bytes behind the object store boundary and publishes only complete writes",
"never serves an artifact at or after expiry, including during admission and mid-stream",
"fails a transfer that outlives its artifact",
"fails a transfer whose source is revoked before completion and denies a revoked download",
"stops a download stream when the source is revoked mid-stream",
"requires read access to every source resource at completion and download",
"denies a disabled or unavailable account at ingestion and download",
"denies downloads of a disabled addon, keeps the bytes and serves again only while unexpired with current permissions",
"denies downloads after uninstall and removes the bytes at the next sweep",
"sweeps expired artifacts, abandoned partials and orphan files without touching live transfers",
"enforces per-user, total and size limits atomically under concurrent ingestion",
"bounds concurrent transfers and concurrent downloads",
"cancels a transfer by its context or by its owner and removes the partial bytes",
"returns the same artifact for a repeated request without a second transfer",
"keeps addon handles operation-bound and out of metadata and views",
"keeps complete artifacts across a restart and settles interrupted transfers",
"keeps the bytes of a transfer that completes while a sweep is running",
"never loses the bytes of a complete artifact when sweeps race with several completing transfers",
"answers a transient storage error as unavailable and keeps the bytes and the record",
"marks an artifact corrupt only for missing bytes or a size mismatch",
"answers a download that races with an expiry or a drop like any expired identifier",
"refuses a corrupt metadata store and stops writing after a failed sync",
"waits for background transfers before Close returns and writes nothing after",
"ingests a file result into a private staged artifact with a host-generated identifier",
"never uses an addon handle, URL or path as an identifier or a file path",
"answers one denial for an unknown identifier and for another principal's artifact",
"never serves incomplete, short, long or failed transfers and removes their partial bytes",
"streams ingestion and download without buffering the whole file",
"rejects an output declared larger than one artifact may be before reading it",
"never opens an output for a request that names a tool no source declares",
"denies an output request whose arguments repeat a key and never opens the output",
"reports an unavailable declaration source as unavailable and never opens the output",
"shortens the lifetime and keeps the bounds consistent, and zero keeps the defaults",
"fails the artifact with a fixed reason that says it was refused, not that the add-on is down"
]
},
{
"path": ".cache/addons/logs/artifacts-gateway.json",
"cases": [
"serves only declared installed generation assets and rejects traversal",
"fails closed without current identity or resource policy and reports the original ID of an unknown mutation outcome",
"reports an unclassified account check error as unavailable on every path and a wrapped denial as forbidden",
"propagates interrupted progress cancellation through the receiving frontend",
"validates finite relay budgets and prevents disabling polling bounds",
"builds a carrier only from complete pinned identities",
"types an unknown mutation outcome as unavailable without losing its operation",
"rejects untrusted peers wrong audience body expiry replay and revoked credentials",
"alternates pinned frontends and rejects untrusted certificates without local fallback",
"reports the original operation after lost mutation replies without retrying",
"rejects a stream longer than its receiving frontend budget",
"rejects a CA signed peer without a pin on the owner side",
"refuses an owner whose CA signed certificate is not the pinned owner",
"returns the artifact status through the owner from every frontend with one denial for the rest",
"types the owner's refusal and outage of a lookup the same from every frontend",
"writes an attachment header that cannot be broken out of",
"rotates the enforced audience on restart and rejects captured requests",
"never expires the response deadline after the relay returned",
"returns the owner's forbidden status for an invalid kind and for missing policy",
"still reports unavailable when the owner is unable to serve and not forbidden",
"reaches the same decision through both frontends and delivers bytes when allowed",
"keeps aborting when revocation happens after bytes were written",
"bounds progress, asset and file relays by their own limit",
"alternates real owner journal status and terminates coarse progress without submitting again",
"reports an account store outage as unavailable and a refused account as forbidden",
"rejects unknown lifecycle argument fields before touching the owner journal",
"reports a runtime that cannot serve as unavailable through both frontends",
"reports an output that ends before its first byte as unavailable",
"fails closed as unavailable for an unclassified owner error",
"keeps authorization and policy denials forbidden",
"keeps a mutation unknown when the runtime fails after the owner applied it",
"keeps a mutation unknown when the owner reports recovery required for its operation",
"reports a mutation as unknown when the owner cannot serve it at all",
"keeps a mutation unknown on the owner's own frontend and leaves reads and denials alone",
"lets unavailability win when an error wraps both a denial and an unavailable cause",
"does not leak attachment headers into an error when the first read fails",
"treats every action except the known reads as a mutation",
"keeps resolved resources under admission for JSON and attachment bytes",
"closes interrupted output and releases admission on disconnect",
"rechecks revoked credentials during attachment copying",
"adopts read outputs as private artifacts inside admission and replaces a forged resource identity",
"refuses at ingest a file result larger than the relay file bound so nothing unservable is staged",
"denies private relays without host resolution and admission",
"serves declared assets of the current enabled generation by package digest only",
"allows only an exact declared tool name and fails closed otherwise",
"never contacts the add-on for an undeclared tool and still serves a declared one",
"denies a repeated key at any depth however it is spelled",
"denies arguments that are not exactly one object",
"separates a denial from an unavailable declaration source",
"answers 503 and never contacts the add-on when the source is unavailable or the arguments repeat a key",
"is the typed invalid request on the owner for a read, never an outage",
"is the typed invalid request on the owner for a proposal call",
"is the typed invalid request on the owner for a json relay",
"is the same typed answer from a forwarding frontend",
"crosses the owner's wire as the same typed error, whatever the frontend",
"does not trust a code the host does not know, and cleans the detail the add-on wrote",
"is a stale view for a caller that only knows ErrStale, and a denial otherwise",
"is a mutation on the carrier: a lost answer is an unknown outcome, never a plain outage",
"runs on the owner for the actor the signature binds, and the typed direct dispatch still refuses it",
"keeps the answer of a call that outlasts the write timeout of the owner server",
"is an unknown outcome when the answer is lost",
"runs the backend-releases check for a pinned frontend without an actor",
"refuses a system call from a peer that is not pinned",
"never lets a system call change anything or ride the user-facing route",
"writes the set with private modes and no CA key",
"loads both roles into carriers and serves a frontend call from the owner",
"gives the owner no signing key and the frontend its own",
"accepts two frontends made from the same set",
"refuses a frontend from another generation",
"reads only the files of the role",
"refuses a key file with group or other access",
"refuses an unknown role",
"refuses to overwrite a file and leaves it unchanged",
"needs an owner host",
"says nothing was sent when the add-on is not running, instead of an unknown outcome",
"runs a declared action tool for the calling user, under the act scope, admitted as an add-on call",
"is not reachable through the typed dispatch of the direct API",
"refuses what is not a declared action tool",
"refuses an add-on that did not declare actions",
"is unavailable when the runtime does not serve action tools, and never runs for an unvalidated user",
"reports an unknown outcome, not a refusal, when the runtime fails after the call began",
"runs a resource-less read tool for the calling user only",
"denies a tool that declares a resource when none is given, and never reaches the add-on",
"denies a resource-less read when the admission cannot admit an add-on, or the tool is undeclared",
"keeps its address stable across starts",
"does not share state between different roots",
"fails clearly when the port is in use",
"rejects an invalid port file",
"rejects a port file with a loose mode",
"rejects a port file that links outside the root",
"is not permitted when the add-on denies the person, on the owner and on a forwarding frontend",
"is an unreachable resource when the policy denies it, on the owner and on a forwarding frontend",
"types the denial of a read like the denial of a write, on the owner and on a forwarding frontend",
"crosses the wire of a resource call typed, so a forwarding frontend answers like the owner",
"keeps any other failure to resolve a resource a plain denial, so nothing more is told"
]
},
{
"path": ".cache/addons/logs/artifacts-http.json",
"cases": [
"stores a proposal from an API key and lets only the proposer's browser session confirm it",
"cancels a proposal from the same chain and never lets typed dispatch or relay confirm",
"denies sharing and deletion proposals and an unauthenticated caller",
"serves the local owner's confirmation only from a same-origin fetch of the host page",
"reports a lost reply with the original operation from forwarding frontends and resolves it by receipt",
"lets only the resource owner's browser session abandon an unresolved outcome and then accepts writes",
"lets the owner role list an editor's unresolved proposal and abandon it by the listed digest from every frontend",
"tells an editor of a blocked write only that it is denied",
"returns the applied proposal when the confirmed operation committed",
"answers an owner outage by the owner's state with the same type from every frontend",
"keeps a proposal confirmable by the same ID after the owner could not reach the addon",
"documents the proposal routes and the proposal schema in the Swagger spec",
"serves one owner journal through two real authenticated HTTP frontends and rejects paused keys",
"serves the synthetic owner through the real chain, denies sharing and rejects named callers",
"checks browser CSRF feature and admin access with real stored keys",
"serves a private file result as a safe attachment over real HTTP",
"never renders hostile names or active media types inline",
"answers one 403 for unknown, foreign, incomplete and expired artifacts and requires the feature and a principal",
"denies the download of a disabled addon and serves it again after enable",
"relays the same bytes, headers and denials through two forwarding frontends",
"keeps a file result of a read denied whole without an artifact store",
"serves the local owner's file only in local-owner mode",
"documents the artifact routes and the artifact schema in the Swagger spec",
"rejects anonymous callers and forged forwarding headers",
"gates the feature and then administration for named keys",
"requires same-origin browser requests for cookie mutations",
"registers only the dispatch, relay and proposal mutations",
"reserves every first path segment the host registers under /api/addons",
"gates the artifact routes by authentication and feature",
"gates the proposal routes by feature and refuses a confirmation from a key before the owner is asked",
"rejects anonymous and forged forwarding authority through real authentication",
"lets callers through only when the deployment selected local-owner mode",
"keeps authentication, the feature gate and administration when accounts exist",
"reports an unknown mutation outcome from a forwarding frontend with the original operation",
"documents every field the error responses emit in the Swagger schema",
"reports an unavailable read as plain unavailability",
"reports a denial as forbidden",
"reports an unclassified account check error as unavailable and a definite denial as forbidden",
"reports an unknown mutation outcome from the owner's own frontend with the original operation",
"lists the enabled installed apps for a reader and the disabled ones too for administrators, the same from every frontend",
"lets only administrators start and stop, through the lifecycle manager, and denies a stale generation",
"serves the verified icon through the host route and denies it identically otherwise",
"reports a lost start as an unknown outcome with its original operation and a lost list as unavailable",
"documents the apps routes and every field of the app view in the Swagger spec",
"lists every registered addon route in the feature registry",
"gates the apps routes by authentication, feature and administration",
"serves catalog search, details and the installed management view to administrators only, the same from every frontend",
"refuses every management call of the owner itself for a caller that is not an administrator",
"saves, refreshes and removes a library by reference and leaves installed addons alone",
"upgrades an installed addon through the typed action and keeps its earlier generation",
"reports a lost source change as an unknown outcome and a lost read as unavailable",
"documents the management actions and every emitted field of the installed view",
"serves the declared files of the current package through every frontend with immutable headers",
"lists the same URLs the route serves, and only for an enabled addon",
"denies every other path, digest, addon and credential form with one answer and no immutable caching",
"accepts a same-origin browser session and refuses a cross-site or direct one",
"withdraws the code the moment the addon is disabled, uninstalled or replaced, even for a page that is still open",
"refuses a declared file that is not a regular file of the package",
"documents the asset route and its binary response in the Swagger spec",
"gives the same 403 on the owner and on a forwarding frontend and never contacts the add-on",
"lists the caller's own pending proposals the same from the owner and every forwarding frontend",
"gives every caller with the feature the same status from every frontend, redacted for non-administrators",
"checks only for an administrator's own browser session, and applies nothing",
"upgrades only to the checked candidate, with the same typed refusals from every frontend, and never twice",
"runs two concurrent upgrades from two frontends once: the same ID shares the answer, another ID is a conflict",
"refuses an incompatible candidate and a library that cannot be read, with a typed answer",
"reports a lost upgrade as an unknown outcome with its original operation, and a lost status read or check as plainly unavailable",
"keeps the update actions out of the tools and names every field of the status in the Swagger spec",
"answers an add-on's invalid-request refusal as a typed 400 from the owner and from a forwarding frontend",
"returns the same text through a forwarding frontend",
"Sec-Fetch-Site cross-site is refused even with a Referer on the same host",
"Sec-Fetch-Site same-origin passes",
"Sec-Fetch-Site same-site is refused",
"a request without a session cookie is not guarded",
"no Sec-Fetch-Site and no Origin or Referer is refused",
"no Sec-Fetch-Site with a Referer on the same host passes",
"no Sec-Fetch-Site with a foreign Origin is refused",
"no Sec-Fetch-Site with a foreign Origin is refused even with a Referer on the same host",
"no Sec-Fetch-Site with a foreign Referer is refused",
"no Sec-Fetch-Site with a null Origin is refused",
"no Sec-Fetch-Site with an Origin on the same host passes",
"no Sec-Fetch-Site with the same host on another port is refused",
"matches the host without regard to letter case",
"gives no pins to an account created after the upgrade",
"round-trips pins for the local owner",
"drops IDs the caller cannot see",
"an object",
"numbers",
"not JSON",
"empty",
"null",
"rejects a list over the hard limit",
"does not show Studio and Talk as pins without the add-ons",
"lists add-ons by default, and takes a kind that this host reads",
"is empty because Studio and Talk are packaged add-ons",
"lists every entry without an account database",
"strict same-origin fetch",
"same-origin without destination",
"same-host Referer, no Sec-Fetch headers",
"same-host Origin, no Sec-Fetch headers",
"foreign Referer",
"same host, other port",
"foreign Origin wins over same-host Referer",
"no Origin and no Referer",
"cross-site with same-host Referer",
"same-site with same-host Origin",
"same-host Referer but navigation destination",
"same-host Referer but no-cors mode",
"still refuses a same-host Referer with an API key",
"returns the SDK refusal text, the unverified-package text and the missing-release text to the administrator",
"logs the cause of a failed install and types it for the client",
"logs the reason behind a generic denial and leaves the response unchanged",
"names every typed cause of a failed install in the 403 of the dispatch route"
]
}
]
},
"apps": {
"kind": "ginkgo",
"commands": [
[
"go",
"test",
"-count=1",
"-p",
"2",
"-tags",
"auth",
"./core/services/addons/apps",
"-ginkgo.json-report=../../../../.cache/addons/logs/apps.json"
],
[
"go",
"test",
"-count=1",
"-p",
"2",
"-tags",
"auth",
"./core/services/addons",
"-ginkgo.json-report=../../../.cache/addons/logs/apps-lifecycle.json"
],
[
"go",
"test",
"-count=1",
"-p",
"2",
"-tags",
"auth",
"./core/services/addons/runtime",
"-ginkgo.json-report=../../../../.cache/addons/logs/apps-runtime.json"
],
[
"go",
"test",
"-count=1",
"-p",
"2",
"-tags",
"auth",
"./core/http/endpoints/addons",
"-ginkgo.json-report=../../../../.cache/addons/logs/apps-http.json"
]
],
"cases": [
"lists installed enabled addons for users and adds installed disabled ones only for administrators",
"derives display fields, the main page and the icon URL from the verified manifest only",
"bounds the tool summary and coerces unknown process states to failed",
"shows controls and the management link only to administrators and never leaks owner details",
"describes the immutable UI assets of an enabled addon by the package digest and never otherwise",
"denies enable and disable for a stale generation without recording anything",
"lists the identifiers of installed addons, disabled ones included",
"refuses to list installed identifiers while recovery is required",
"lists apps by visibility and serves an icon only for a visible app at its generation",
"cancels status lookup while a lifecycle writer holds the journal lock",
"retries runtime synchronization after canceled disable and generation upgrade",
"rejects symlinked package roots without touching external staging",
"recovers every durable journal boundary without replaying publication",
"removes abandoned staging without removing published packages on recovery",
"keeps immutable history on successful upgrade and reinstallation",
"excludes competing owners and rejects conflicting durable identities",
"never opens replica roots or elects an absent owner",
"binds duplicate operation IDs to actor and command and serializes conflicts",
"refuses commands and asset reads for an add-on ID the host serves as a route",
"retains generations identity data and grants across uninstall and restart",
"preserves old packages and active generation on manager upgrade failure",
"requires current authoritative administration even for idempotent retries",
"executes enabled owner intent on startup and stops on disable and close without forwarder execution",
"binds lifecycle lookup to current admin and original actor without writes or repair",
"reports the supervisor state of an app through a crash and a restart",
"reads a flat directory in batches and stops at the entry bound",
"adds up nested files and reports a complete walk as not truncated",
"never follows or counts a symbolic link",
"keeps a result for a short time so polling does not walk again",
"stops at the time bound and reports a truncated size",
"does not keep a result cut short by the caller",
"is what the installed view reports for the data directory",
"resolves a package for the current enabled generation and digest only",
"answers from the current installed manifest only and follows a generation change",
"reports a digest-only change of a moving channel, applies nothing and offers the pinned upgrade",
"refuses a second operation ID for the same transition, in flight or done, and applies it once",
"runs concurrent requests with one operation ID once and gives each the same answer",
"serializes conflicting upgrades by the installed digest and refuses the loser without a record",
"refuses a candidate that is not the one the library resolves now",
"refuses an upgrade to the digest that is already installed",
"rechecks compatibility at execution and refuses an incompatible candidate",
"selects a newer immutable version and treats a rewritten version as an integrity error",
"keeps the last good generation when the candidate cannot be staged",
"never switches the library or channel, and a failed check is never up to date",
"lets an administrator refresh and everyone with the feature read a redacted status",
"shows the pending update in the apps list from the cache only",
"does not accept pins without an update checker or on another action",
"keeps the unpinned typed upgrade of an earlier release working",
"registers only ready generation bound service headless and UI capabilities",
"rejects forged registration nonloopback and stale incarnation handshakes",
"bounds readiness and handles exit during start and stop",
"withdraws immediately drains boundedly and rejects stale process identities",
"exhausts restart budget without retaining dead registrations",
"does not inherit secrets and exits when the private parent channel closes",
"fails closed on ambiguous launch identities and preserves unrelated reused PIDs",
"retains a canceled restart slot until cleanup completes and rejects duplicate supervisors",
"rejects nonloopback endpoints and bounds oversized streams and concurrency",
"reports stopped, running, failed, starting and running again across a crash and a restart",
"keeps reporting failed once the restart budget is exhausted",
"rejects foreign supervisor handles and numeric PID substitutions",
"resets restart budget only after sustained authenticated health",
"kills the exact paused child of a killed owner before launching its replacement",
"never reports failed between a launch starting and the restarted process being published",
"reserves a draining slot against concurrent starts",
"waits for a restart launch worker before acknowledging stop",
"exposes a new incarnation client after restart without reviving the old client",
"refuses a missing established ledger and fences failed cleanup publication",
"authenticates every request and separates trusted authority from model arguments",
"bounds output streams cancellation deadlines and stop admission",
"tells a 409 conflict of the add-on from an outage",
"withdraws and initiates every live slot before a cleanup timeout",
"creates one private data directory per addon and passes its path in the startup object",
"gives no data directory without a data root and refuses an unsafe root or addon ID",
"gives an add-on that the host setting names a host endpoint of its own",
"gives an add-on that the host setting does not name no host endpoint",
"closes the host endpoint when the incarnation ends",
"an HTTP 400 answer",
"an HTTP 422 answer",
"keeps a bounded, printable reason and nothing else of the body",
"leaves 503, 500 and 404 as outages",
"rejects anonymous and forged forwarding authority through real authentication",
"lets callers through only when the deployment selected local-owner mode",
"keeps authentication, the feature gate and administration when accounts exist",
"lists the enabled installed apps for a reader and the disabled ones too for administrators, the same from every frontend",
"lets only administrators start and stop, through the lifecycle manager, and denies a stale generation",
"serves the verified icon through the host route and denies it identically otherwise",
"reports a lost start as an unknown outcome with its original operation and a lost list as unavailable",
"documents the apps routes and every field of the app view in the Swagger spec",
"rejects anonymous callers and forged forwarding headers",
"gates the feature and then administration for named keys",
"requires same-origin browser requests for cookie mutations",
"registers only the dispatch, relay and proposal mutations",
"reserves every first path segment the host registers under /api/addons",
"gates the artifact routes by authentication and feature",
"lists every registered addon route in the feature registry",
"gates the apps routes by authentication, feature and administration",
"gates the proposal routes by feature and refuses a confirmation from a key before the owner is asked",
"checks browser CSRF feature and admin access with real stored keys",
"stores a proposal from an API key and lets only the proposer's browser session confirm it",
"cancels a proposal from the same chain and never lets typed dispatch or relay confirm",
"denies sharing and deletion proposals and an unauthenticated caller",
"serves the local owner's confirmation only from a same-origin fetch of the host page",
"reports a lost reply with the original operation from forwarding frontends and resolves it by receipt",
"lets only the resource owner's browser session abandon an unresolved outcome and then accepts writes",
"lets the owner role list an editor's unresolved proposal and abandon it by the listed digest from every frontend",
"tells an editor of a blocked write only that it is denied",
"returns the applied proposal when the confirmed operation committed",
"answers an owner outage by the owner's state with the same type from every frontend",
"keeps a proposal confirmable by the same ID after the owner could not reach the addon",
"documents the proposal routes and the proposal schema in the Swagger spec",
"reports an unknown mutation outcome from a forwarding frontend with the original operation",
"documents every field the error responses emit in the Swagger schema",
"reports an unavailable read as plain unavailability",
"reports a denial as forbidden",
"reports an unclassified account check error as unavailable and a definite denial as forbidden",
"reports an unknown mutation outcome from the owner's own frontend with the original operation",
"serves a private file result as a safe attachment over real HTTP",
"never renders hostile names or active media types inline",
"answers one 403 for unknown, foreign, incomplete and expired artifacts and requires the feature and a principal",
"denies the download of a disabled addon and serves it again after enable",
"relays the same bytes, headers and denials through two forwarding frontends",
"keeps a file result of a read denied whole without an artifact store",
"serves the local owner's file only in local-owner mode",
"documents the artifact routes and the artifact schema in the Swagger spec",
"serves one owner journal through two real authenticated HTTP frontends and rejects paused keys",
"serves the synthetic owner through the real chain, denies sharing and rejects named callers",
"serves catalog search, details and the installed management view to administrators only, the same from every frontend",
"refuses every management call of the owner itself for a caller that is not an administrator",
"saves, refreshes and removes a library by reference and leaves installed addons alone",
"upgrades an installed addon through the typed action and keeps its earlier generation",
"reports a lost source change as an unknown outcome and a lost read as unavailable",
"documents the management actions and every emitted field of the installed view",
"serves the declared files of the current package through every frontend with immutable headers",
"lists the same URLs the route serves, and only for an enabled addon",
"denies every other path, digest, addon and credential form with one answer and no immutable caching",
"accepts a same-origin browser session and refuses a cross-site or direct one",
"withdraws the code the moment the addon is disabled, uninstalled or replaced, even for a page that is still open",
"refuses a declared file that is not a regular file of the package",
"documents the asset route and its binary response in the Swagger spec",
"gives the same 403 on the owner and on a forwarding frontend and never contacts the add-on",
"lists the caller's own pending proposals the same from the owner and every forwarding frontend",
"gives every caller with the feature the same status from every frontend, redacted for non-administrators",
"checks only for an administrator's own browser session, and applies nothing",
"upgrades only to the checked candidate, with the same typed refusals from every frontend, and never twice",
"runs two concurrent upgrades from two frontends once: the same ID shares the answer, another ID is a conflict",
"refuses an incompatible candidate and a library that cannot be read, with a typed answer",
"reports a lost upgrade as an unknown outcome with its original operation, and a lost status read or check as plainly unavailable",
"keeps the update actions out of the tools and names every field of the status in the Swagger spec",
"answers an add-on's invalid-request refusal as a typed 400 from the owner and from a forwarding frontend",
"types a withdrawn client, a full slot table, a bad envelope and a missing schema as not sent",
"keeps a not-sent error an ErrRuntime for callers that do not tell them apart",
"types a refused connection as not sent",
"never types a possibly-sent request as not sent",
"carries the SDK refusal text to the caller of a failed install and keeps the generic error",
"installs an add-on whose SDK range contains the host SDK",
"returns the same text through a forwarding frontend",
"carries the install time to the list and the management view, and none for an old record",
"lists the host controls an add-on is entitled to, whatever its ID",
"copies them at install, upgrade and owner start, and removes them at uninstall",
"never fails the operation when the copy fails",
"fails the install and says the package could not be verified, without installing anything",
"names a release that the library does not list",
"names two libraries that list the same add-on",
"names a library that cannot be read",
"reads the library on demand when the startup refresh has not filled the cache",
"reads the library again when the startup refresh failed",
"writes the owner and storage only, with no address",
"loads a file written in the old format with an address",
"loads when only the address changed",
"refuses a changed owner ID",
"refuses a changed storage ID",
"copies every capability field of the manifest, so a new field cannot be forgotten",
"is offered when the tag moved, pinned to the build the tag names, and upgrades to exactly that build",
"refuses the upgrade when the tag moved again after the check, and installs nothing",
"stamps the first install, keeps the time over an upgrade and stamps it again after an uninstall",
"needs a state root for the owner only",
"upgrades an installed add-on through the same path as a manual upgrade",
"does nothing when no newer version is listed",
"refuses a candidate whose package no longer matches its listed digest and replaces nothing",
"refuses a candidate that fails the signature policy of its library and replaces nothing",
"does not upgrade to a release the host cannot run",
"does nothing without an update checker",
"keeps the manual upgrade closed to a caller who is not an administrator",
"starts the enabled add-ons side by side, so the start takes the slowest ones and not the sum",
"types the add-on's own 'forbidden' answer as a denial of the person, not as an outage",
"keeps a 403 about the envelope itself an outage: it is a host fault, not a permission",
"reaches an add-on that declares actions, as the actor of the envelope, under the act scope",
"never sends a call that is not an act call or has another scope",
"never sends an act call to an add-on that did not declare actions",
"stops an act call when the caller gives up",
"posts the request with the incarnation credential and decodes the answer",
"is not sent to an add-on that declared no connector",
"gives it time to release what it owns before it kills the process",
"kills an add-on that ignores the closing of its startup channel, within the grace period",
"goes to the log line by line with the add-on ID and a cap per line",
"Sec-Fetch-Site cross-site is refused even with a Referer on the same host",
"Sec-Fetch-Site same-origin passes",
"Sec-Fetch-Site same-site is refused",
"a request without a session cookie is not guarded",
"no Sec-Fetch-Site and no Origin or Referer is refused",
"no Sec-Fetch-Site with a Referer on the same host passes",
"no Sec-Fetch-Site with a foreign Origin is refused",
"no Sec-Fetch-Site with a foreign Origin is refused even with a Referer on the same host",
"no Sec-Fetch-Site with a foreign Referer is refused",
"no Sec-Fetch-Site with a null Origin is refused",
"no Sec-Fetch-Site with an Origin on the same host passes",
"no Sec-Fetch-Site with the same host on another port is refused",
"matches the host without regard to letter case",
"gives no pins to an account created after the upgrade",
"round-trips pins for the local owner",
"drops IDs the caller cannot see",
"an object",
"numbers",
"not JSON",
"empty",
"null",
"rejects a list over the hard limit",
"does not show Studio and Talk as pins without the add-ons",
"lists add-ons by default, and takes a kind that this host reads",
"is empty because Studio and Talk are packaged add-ons",
"lists every entry without an account database",
"strict same-origin fetch",
"same-origin without destination",
"same-host Referer, no Sec-Fetch headers",
"same-host Origin, no Sec-Fetch headers",
"foreign Referer",
"same host, other port",
"foreign Origin wins over same-host Referer",
"no Origin and no Referer",
"cross-site with same-host Referer",
"same-site with same-host Origin",
"same-host Referer but navigation destination",
"same-host Referer but no-cors mode",
"still refuses a same-host Referer with an API key",
"returns the SDK refusal text, the unverified-package text and the missing-release text to the administrator",
"logs the cause of a failed install and types it for the client",
"logs the reason behind a generic denial and leaves the response unchanged",
"names every typed cause of a failed install in the 403 of the dispatch route"
],
"report": ".cache/addons/logs/apps.json",
"reports": [
{
"path": ".cache/addons/logs/apps.json",
"cases": [
"lists installed enabled addons for users and adds installed disabled ones only for administrators",
"derives display fields, the main page and the icon URL from the verified manifest only",
"bounds the tool summary and coerces unknown process states to failed",
"shows controls and the management link only to administrators and never leaks owner details",
"describes the immutable UI assets of an enabled addon by the package digest and never otherwise",
"carries the install time to the list and the management view, and none for an old record",
"lists the host controls an add-on is entitled to, whatever its ID"
]
},
{
"path": ".cache/addons/logs/apps-lifecycle.json",
"cases": [
"denies enable and disable for a stale generation without recording anything",
"lists the identifiers of installed addons, disabled ones included",
"refuses to list installed identifiers while recovery is required",
"lists apps by visibility and serves an icon only for a visible app at its generation",
"cancels status lookup while a lifecycle writer holds the journal lock",
"retries runtime synchronization after canceled disable and generation upgrade",
"rejects symlinked package roots without touching external staging",
"recovers every durable journal boundary without replaying publication",
"removes abandoned staging without removing published packages on recovery",
"keeps immutable history on successful upgrade and reinstallation",
"excludes competing owners and rejects conflicting durable identities",
"never opens replica roots or elects an absent owner",
"binds duplicate operation IDs to actor and command and serializes conflicts",
"refuses commands and asset reads for an add-on ID the host serves as a route",
"retains generations identity data and grants across uninstall and restart",
"preserves old packages and active generation on manager upgrade failure",
"requires current authoritative administration even for idempotent retries",
"executes enabled owner intent on startup and stops on disable and close without forwarder execution",
"binds lifecycle lookup to current admin and original actor without writes or repair",
"reports the supervisor state of an app through a crash and a restart",
"reads a flat directory in batches and stops at the entry bound",
"adds up nested files and reports a complete walk as not truncated",
"never follows or counts a symbolic link",
"keeps a result for a short time so polling does not walk again",
"stops at the time bound and reports a truncated size",
"does not keep a result cut short by the caller",
"is what the installed view reports for the data directory",
"resolves a package for the current enabled generation and digest only",
"answers from the current installed manifest only and follows a generation change",
"reports a digest-only change of a moving channel, applies nothing and offers the pinned upgrade",
"refuses a second operation ID for the same transition, in flight or done, and applies it once",
"runs concurrent requests with one operation ID once and gives each the same answer",
"serializes conflicting upgrades by the installed digest and refuses the loser without a record",
"refuses a candidate that is not the one the library resolves now",
"refuses an upgrade to the digest that is already installed",
"rechecks compatibility at execution and refuses an incompatible candidate",
"selects a newer immutable version and treats a rewritten version as an integrity error",
"keeps the last good generation when the candidate cannot be staged",
"never switches the library or channel, and a failed check is never up to date",
"lets an administrator refresh and everyone with the feature read a redacted status",
"shows the pending update in the apps list from the cache only",
"does not accept pins without an update checker or on another action",
"keeps the unpinned typed upgrade of an earlier release working",
"carries the SDK refusal text to the caller of a failed install and keeps the generic error",
"installs an add-on whose SDK range contains the host SDK",
"copies them at install, upgrade and owner start, and removes them at uninstall",
"never fails the operation when the copy fails",
"fails the install and says the package could not be verified, without installing anything",
"names a release that the library does not list",
"names two libraries that list the same add-on",
"names a library that cannot be read",
"reads the library on demand when the startup refresh has not filled the cache",
"reads the library again when the startup refresh failed",
"writes the owner and storage only, with no address",
"loads a file written in the old format with an address",
"loads when only the address changed",
"refuses a changed owner ID",
"refuses a changed storage ID",
"copies every capability field of the manifest, so a new field cannot be forgotten",
"is offered when the tag moved, pinned to the build the tag names, and upgrades to exactly that build",
"refuses the upgrade when the tag moved again after the check, and installs nothing",
"stamps the first install, keeps the time over an upgrade and stamps it again after an uninstall",
"needs a state root for the owner only",
"upgrades an installed add-on through the same path as a manual upgrade",
"does nothing when no newer version is listed",
"refuses a candidate whose package no longer matches its listed digest and replaces nothing",
"refuses a candidate that fails the signature policy of its library and replaces nothing",
"does not upgrade to a release the host cannot run",
"does nothing without an update checker",
"keeps the manual upgrade closed to a caller who is not an administrator",
"starts the enabled add-ons side by side, so the start takes the slowest ones and not the sum"
]
},
{
"path": ".cache/addons/logs/apps-runtime.json",
"cases": [
"registers only ready generation bound service headless and UI capabilities",
"rejects forged registration nonloopback and stale incarnation handshakes",
"bounds readiness and handles exit during start and stop",
"withdraws immediately drains boundedly and rejects stale process identities",
"exhausts restart budget without retaining dead registrations",
"does not inherit secrets and exits when the private parent channel closes",
"fails closed on ambiguous launch identities and preserves unrelated reused PIDs",
"retains a canceled restart slot until cleanup completes and rejects duplicate supervisors",
"rejects nonloopback endpoints and bounds oversized streams and concurrency",
"reports stopped, running, failed, starting and running again across a crash and a restart",
"keeps reporting failed once the restart budget is exhausted",
"rejects foreign supervisor handles and numeric PID substitutions",
"resets restart budget only after sustained authenticated health",
"kills the exact paused child of a killed owner before launching its replacement",
"never reports failed between a launch starting and the restarted process being published",
"reserves a draining slot against concurrent starts",
"waits for a restart launch worker before acknowledging stop",
"exposes a new incarnation client after restart without reviving the old client",
"refuses a missing established ledger and fences failed cleanup publication",
"authenticates every request and separates trusted authority from model arguments",
"bounds output streams cancellation deadlines and stop admission",
"tells a 409 conflict of the add-on from an outage",
"withdraws and initiates every live slot before a cleanup timeout",
"creates one private data directory per addon and passes its path in the startup object",
"gives no data directory without a data root and refuses an unsafe root or addon ID",
"gives an add-on that the host setting names a host endpoint of its own",
"gives an add-on that the host setting does not name no host endpoint",
"closes the host endpoint when the incarnation ends",
"an HTTP 400 answer",
"an HTTP 422 answer",
"keeps a bounded, printable reason and nothing else of the body",
"leaves 503, 500 and 404 as outages",
"types a withdrawn client, a full slot table, a bad envelope and a missing schema as not sent",
"keeps a not-sent error an ErrRuntime for callers that do not tell them apart",
"types a refused connection as not sent",
"never types a possibly-sent request as not sent",
"types the add-on's own 'forbidden' answer as a denial of the person, not as an outage",
"keeps a 403 about the envelope itself an outage: it is a host fault, not a permission",
"reaches an add-on that declares actions, as the actor of the envelope, under the act scope",
"never sends a call that is not an act call or has another scope",
"never sends an act call to an add-on that did not declare actions",
"stops an act call when the caller gives up",
"posts the request with the incarnation credential and decodes the answer",
"is not sent to an add-on that declared no connector",
"gives it time to release what it owns before it kills the process",
"kills an add-on that ignores the closing of its startup channel, within the grace period",
"goes to the log line by line with the add-on ID and a cap per line"
]
},
{
"path": ".cache/addons/logs/apps-http.json",
"cases": [
"rejects anonymous and forged forwarding authority through real authentication",
"lets callers through only when the deployment selected local-owner mode",
"keeps authentication, the feature gate and administration when accounts exist",
"lists the enabled installed apps for a reader and the disabled ones too for administrators, the same from every frontend",
"lets only administrators start and stop, through the lifecycle manager, and denies a stale generation",
"serves the verified icon through the host route and denies it identically otherwise",
"reports a lost start as an unknown outcome with its original operation and a lost list as unavailable",
"documents the apps routes and every field of the app view in the Swagger spec",
"rejects anonymous callers and forged forwarding headers",
"gates the feature and then administration for named keys",
"requires same-origin browser requests for cookie mutations",
"registers only the dispatch, relay and proposal mutations",
"reserves every first path segment the host registers under /api/addons",
"gates the artifact routes by authentication and feature",
"lists every registered addon route in the feature registry",
"gates the apps routes by authentication, feature and administration",
"gates the proposal routes by feature and refuses a confirmation from a key before the owner is asked",
"checks browser CSRF feature and admin access with real stored keys",
"stores a proposal from an API key and lets only the proposer's browser session confirm it",
"cancels a proposal from the same chain and never lets typed dispatch or relay confirm",
"denies sharing and deletion proposals and an unauthenticated caller",
"serves the local owner's confirmation only from a same-origin fetch of the host page",
"reports a lost reply with the original operation from forwarding frontends and resolves it by receipt",
"lets only the resource owner's browser session abandon an unresolved outcome and then accepts writes",
"lets the owner role list an editor's unresolved proposal and abandon it by the listed digest from every frontend",
"tells an editor of a blocked write only that it is denied",
"returns the applied proposal when the confirmed operation committed",
"answers an owner outage by the owner's state with the same type from every frontend",
"keeps a proposal confirmable by the same ID after the owner could not reach the addon",
"documents the proposal routes and the proposal schema in the Swagger spec",
"reports an unknown mutation outcome from a forwarding frontend with the original operation",
"documents every field the error responses emit in the Swagger schema",
"reports an unavailable read as plain unavailability",
"reports a denial as forbidden",
"reports an unclassified account check error as unavailable and a definite denial as forbidden",
"reports an unknown mutation outcome from the owner's own frontend with the original operation",
"serves a private file result as a safe attachment over real HTTP",
"never renders hostile names or active media types inline",
"answers one 403 for unknown, foreign, incomplete and expired artifacts and requires the feature and a principal",
"denies the download of a disabled addon and serves it again after enable",
"relays the same bytes, headers and denials through two forwarding frontends",
"keeps a file result of a read denied whole without an artifact store",
"serves the local owner's file only in local-owner mode",
"documents the artifact routes and the artifact schema in the Swagger spec",
"serves one owner journal through two real authenticated HTTP frontends and rejects paused keys",
"serves the synthetic owner through the real chain, denies sharing and rejects named callers",
"serves catalog search, details and the installed management view to administrators only, the same from every frontend",
"refuses every management call of the owner itself for a caller that is not an administrator",
"saves, refreshes and removes a library by reference and leaves installed addons alone",
"upgrades an installed addon through the typed action and keeps its earlier generation",
"reports a lost source change as an unknown outcome and a lost read as unavailable",
"documents the management actions and every emitted field of the installed view",
"serves the declared files of the current package through every frontend with immutable headers",
"lists the same URLs the route serves, and only for an enabled addon",
"denies every other path, digest, addon and credential form with one answer and no immutable caching",
"accepts a same-origin browser session and refuses a cross-site or direct one",
"withdraws the code the moment the addon is disabled, uninstalled or replaced, even for a page that is still open",
"refuses a declared file that is not a regular file of the package",
"documents the asset route and its binary response in the Swagger spec",
"gives the same 403 on the owner and on a forwarding frontend and never contacts the add-on",
"lists the caller's own pending proposals the same from the owner and every forwarding frontend",
"gives every caller with the feature the same status from every frontend, redacted for non-administrators",
"checks only for an administrator's own browser session, and applies nothing",
"upgrades only to the checked candidate, with the same typed refusals from every frontend, and never twice",
"runs two concurrent upgrades from two frontends once: the same ID shares the answer, another ID is a conflict",
"refuses an incompatible candidate and a library that cannot be read, with a typed answer",
"reports a lost upgrade as an unknown outcome with its original operation, and a lost status read or check as plainly unavailable",
"keeps the update actions out of the tools and names every field of the status in the Swagger spec",
"answers an add-on's invalid-request refusal as a typed 400 from the owner and from a forwarding frontend",
"returns the same text through a forwarding frontend",
"Sec-Fetch-Site cross-site is refused even with a Referer on the same host",
"Sec-Fetch-Site same-origin passes",
"Sec-Fetch-Site same-site is refused",
"a request without a session cookie is not guarded",
"no Sec-Fetch-Site and no Origin or Referer is refused",
"no Sec-Fetch-Site with a Referer on the same host passes",
"no Sec-Fetch-Site with a foreign Origin is refused",
"no Sec-Fetch-Site with a foreign Origin is refused even with a Referer on the same host",
"no Sec-Fetch-Site with a foreign Referer is refused",
"no Sec-Fetch-Site with a null Origin is refused",
"no Sec-Fetch-Site with an Origin on the same host passes",
"no Sec-Fetch-Site with the same host on another port is refused",
"matches the host without regard to letter case",
"gives no pins to an account created after the upgrade",
"round-trips pins for the local owner",
"drops IDs the caller cannot see",
"an object",
"numbers",
"not JSON",
"empty",
"null",
"rejects a list over the hard limit",
"does not show Studio and Talk as pins without the add-ons",
"lists add-ons by default, and takes a kind that this host reads",
"is empty because Studio and Talk are packaged add-ons",
"lists every entry without an account database",
"strict same-origin fetch",
"same-origin without destination",
"same-host Referer, no Sec-Fetch headers",
"same-host Origin, no Sec-Fetch headers",
"foreign Referer",
"same host, other port",
"foreign Origin wins over same-host Referer",
"no Origin and no Referer",
"cross-site with same-host Referer",
"same-site with same-host Origin",
"same-host Referer but navigation destination",
"same-host Referer but no-cors mode",
"still refuses a same-host Referer with an API key",
"returns the SDK refusal text, the unverified-package text and the missing-release text to the administrator",
"logs the cause of a failed install and types it for the client",
"logs the reason behind a generic denial and leaves the response unchanged",
"names every typed cause of a failed install in the 403 of the dispatch route"
]
}
]
},
"gallery-ui": {
"kind": "shell",
"commands": [
[
"sh",
"scripts/addons/gallery_ui.sh"
]
],
"cases": [
"unit: query normalization bounds text, library and page",
"unit: an operation book keeps one identity per action until it is done",
"unit: responses classify the same way everywhere",
"unit: polling backs off on failure, slows when hidden and stays bounded",
"unit: library drafts accept references and refuse secrets before sending",
"unit: tabs: the server decides, the page only avoids showing what it will refuse",
"unit: the installed list puts what needs a person first and filters by state",
"unit: an add-on without an icon gets a stable letter and hue, and a dev build says so",
"unit: app chips never turn an unknown state into running",
"unit: titles follow the language, then the default text, then the id",
"unit: update status comes only from an authoritative check",
"unit: the api sends one dispatch shape and classifies refusals",
"unit: an unknown outcome is read with the original identity and never resubmitted",
"unit: a denial is not retried and an exhausted read is reported as unknown",
"unit: an action book binds one identity to one click and its retries",
"unit: an action book mints a fresh identity once an action is resolved",
"unit: an action book blocks another action on a subject with an unknown outcome until it is resolved or dismissed",
"unit: a completed status that left the add-on unchanged is not reported as done",
"apps: lists enabled apps with state chips, the icon route and Open only for a main page",
"apps: a headless add-on shows its tools and no Open action",
"apps: a reader gets no start, stop, manage or management tabs",
"apps: an administrator starts an app with a fresh operation ID and the listed generation",
"apps: a lost start is read with the same operation ID and never submitted again",
"apps: an unknown start is resolved or dismissed before the next action and never replays its ID",
"apps: dismissing an unknown outcome lets the next click mint a new operation",
"apps: a completed status that left the app unchanged is not shown as done",
"apps: a refused start shows the server denial and refreshes the list",
"apps: the list refreshes on a bounded interval, backs off on errors and stops when left",
"apps: an add-on that contributes UI keeps the list current off the page and its disable stops the reads",
"apps: a viewer without the add-ons feature never requests the list",
"browse: searches the libraries, pages and shows trust and platform facts",
"browse: Install and turn on asks once, installs and turns the add-on on",
"browse: a failed turn on keeps the install, says why in the dialog and can be tried again",
"browse: an add-on that is installed but off offers Turn on and nothing else",
"installed: health is separate from enabled and the details show trust, compatibility and storage",
"installed: an update is shown only from the owner update field and upgrade sends that version",
"installed: removing warns that data is kept before anything is submitted",
"installed: Escape cancels the remove dialog only, then closes the pane, and focus returns to the card",
"installed: a headless add-on keeps its details, health and tools",
"installed: a refusal of the installed list leaves the pane without Details",
"installed: an old Installed address lands on Installed and the management link opens the details",
"libraries: a private library is saved by credential reference and never carries a secret",
"libraries: removing a library says installed add-ons stay and leaves them installed",
"libraries: a refresh reports its result and a failed fetch is shown as failed",
"keyboard: the tab list moves with the arrow keys and actions are reachable",
"narrow: at 400 px the apps page is one column without sideways scrolling",
"theme: the apps page follows the light and dark tokens",
"i18n: the page follows the interface language",
"regression: the backends catalog still searches, pages and shows its empty state",
"unit: the add-on browse list drops backend entries and keeps entries with no kind",
"unit: a refusal shows the server reason and falls back to the generic text",
"unit: the add-on list drops a backend entry, and the backend route still installs one",
"unit: a library signer is named exactly or by a pattern, never both",
"unit: a backend install follows its job through the steps and ends with the result",
"unit: a failed backend install job throws the reason and keeps the step that failed",
"unit: install steps: left steps are done, the reported one runs, the rest wait",
"unit: backends page: a library backend shows its library and the digest it pinned",
"unit: backends page: a newer build in the library is an update state, and a running job wins over it",
"unit: the updates route of the host is read as a list and nothing is sent",
"unit: every locale carries the add-on and navigation keys of English",
"unit: the chats page has its add-on control strings in English",
"unit: the add-on labels use one name and one verb pair",
"unit: what an add-on adds comes from its page and its tools, and nothing is guessed",
"unit: screenshots appear only when the host lists them and they are served by the host",
"unit: the list says first run, no match or none, and a search never claims that nothing is installed",
"unit: featured add-ons are the first three add-on entries that are not installed",
"unit: install and turn on runs the install, then the turn on, each as its own action",
"unit: install and turn on stops at a failed install and retries only the turn on",
"unit: a library entry shows its tool count only when it is above zero, from the installed-view fields",
"unit: the catalog adapter carries toolCount and tools of a release, and defaults them to none",
"unit: the English wording is \"Adds 16 tools\" and \"Adds 1 tool\"",
"unit: addons: the install dialog names each built-in skill the entry replaces, and who already does",
"unit: addons: the details list the skills of an add-on and which replace a built-in one",
"hub: under the legacy switch the Add-ons tab appears only for an account that holds the feature"
]
},
"esm-ui": {
"kind": "shell",
"commands": [
[
"sh",
"scripts/addons/esm_ui.sh"
]
],
"cases": [
"unit: sdk: compatibility accepts only a range that holds the host SDK version",
"unit: sdk: the object is a frozen allowlist that carries the host React and no host internals",
"unit: sdk: hooks run on the host React instance and a wrapper keeps one component type",
"unit: sdk: icons outside the semantic set fall back and theme tokens are a fixed set",
"unit: sdk: navigation stays inside the add-on prefix and its declared pages",
"unit: sdk: api calls carry the add-on and its generation and nothing else is reachable",
"unit: sdk: after the signal aborts every service refuses and each disposer runs once",
"unit: sdk: markDirty reports unsaved edits once per change and notifications are bounded",
"unit: sdk: locale is scoped to the add-on and falls back to the default text",
"unit: sdk: layers are host wrappers with a bounded spec",
"unit: css: every selector is scoped to the add-on root and the global ones are neutralised",
"unit: css: imports, fonts, external urls and unknown at-rules are dropped and keyframes are renamed",
"unit: css: no value that loads a URL survives anywhere in the sheet",
"unit: css: harmless values, escapes in strings and nested rules are kept",
"unit: css: two add-ons that use the same class names get disjoint scopes",
"unit: loader: asset URLs must be same-origin immutable URLs of the add-on own package",
"unit: loader: an incompatible SDK range is never imported and leaves a clear error",
"unit: loader: the module receives only the host SDK, its result is validated and styles are scoped",
"unit: loader: a module without createAddon, with a bad result or a bare import is a load error",
"unit: loader: a hanging import times out and an abort cancels and cleans up",
"unit: loader: dispose runs once, aborts the SDK signal and removes the styles",
"unit: loader: chat actions are limited to declared ids and carry only the conversation context",
"unit: registry: disable, uninstall, crash and update withdraw a loaded add-on at once",
"unit: registry: unsaved edits keep a withdrawn add-on stale until the user reloads",
"unit: registry: a poll never replaces a withdrawn instance; only reload does",
"unit: registry: a hold ends with its last holder and a load that was withdrawn leaves no instance behind",
"unit: registry: navigation and chat actions come only from usable add-ons of the current generation",
"unit: registry: the legacy Add-ons tab lists page links only when the registry has usable add-ons",
"unit: registry: the list is read off the Add-ons page only for a viewer with the feature and a UI contribution",
"go: describes the immutable UI assets of an enabled addon by the package digest and never otherwise",
"go: resolves a package for the current enabled generation and digest only",
"go: serves declared assets of the current enabled generation by package digest only",
"go: serves the declared files of the current package through every frontend with immutable headers",
"go: lists the same URLs the route serves, and only for an enabled addon",
"go: denies every other path, digest, addon and credential form with one answer and no immutable caching",
"go: accepts a same-origin browser session and refuses a cross-site or direct one",
"go: withdraws the code the moment the addon is disabled, uninstalled or replaced, even for a page that is still open",
"go: refuses a declared file that is not a regular file of the package",
"go: documents the asset route and its binary response in the Swagger spec",
"esm: a fixture add-on installed after the host build loads through real authorization and draws in its own root",
"esm: hooks run on the host React and the add-on keeps its state across renders",
"esm: the add-on style sheet is scoped to its root and leaves the host and other add-ons alone",
"esm: a component that throws is contained by the error boundary and the shell keeps working",
"esm: deep links, the bare add-on address and a proxy path prefix reach the same declared page",
"esm: a host that does not provide the add-on SDK range never imports its code and says so",
"esm: a module that imports React by a bare specifier fails to load and no second React is resolved",
"esm: the server decides asset access: undeclared files, traversal, other add-ons, credentials in URLs and foreign sessions are denied",
"esm: an add-on navigates only to its own declared pages and the host draws the add-on navigation",
"esm: dialogs an add-on opens are owned by the host: focus, Escape and the close button",
"esm: a dialog or panel whose render throws is contained and the host app keeps running",
"esm: unsaved edits are guarded when leaving the page",
"esm: the page keeps inside the viewport at 400 px and follows the light and dark themes",
"esm: a member without the add-ons feature gets no add-on page and no code",
"esm: disabling an add-on unmounts it, aborts its signal, drops its styles and denies its code at once",
"esm: a withdrawn add-on with unsaved edits stays on screen until the user decides, and never saves",
"esm: an update withdraws the old generation, denies its code and loads the new one only on an explicit reload"
]
},
"host-slots": {
"kind": "shell",
"commands": [
[
"sh",
"scripts/addons/host_slots.sh"
]
],
"cases": [
"unit: slots: the registry is closed and each slot has a frozen minimal props contract",
"unit: slots: props carry only the contract and never message text or history",
"unit: slots: declared component names come from the manifest only and the module cannot add more",
"unit: slots: the loader hands the host only declared components and never an imperative registration",
"unit: slots: contributions come only from enabled, usable, current-generation add-ons that are ready",
"unit: slots: an action appears only in its declared placement and carries its own target",
"unit: slots: labels follow the language with a safe fallback",
"unit: slots: a renderer is found only for the addon own declared tool and kind",
"unit: slots: an action sends its declared tool and the sanitized context, and results are bounded text",
"unit: slots: disable, crash and update unmount every contribution through the runtime",
"unit: slots: contributions keep the apps list polled while they exist",
"unit: slots: the approval frame decides from the stored proposal and never from the renderer",
"unit: slots: the SDK can present an approval of its own addon only through the host",
"unit: slots: a page that only needs the list reads it once and never retries a failed read",
"unit: slots: a file preview is offered for the extensions it declared and gets only the file facts",
"go: accepts tool and component chat actions, slots and own-tool renderers",
"go: keeps bare chat action identifiers and every earlier fixture valid",
"go: rejects every undeclared, unsafe or inconsistent contribution at install",
"go: keeps the closed slot list and the icon allowlist equal to the host",
"go: lists actions, slots and renderers for an enabled addon and keeps the identifiers",
"go: lists no contribution for a disabled addon, whoever asks",
"go: accepts a file preview slot that names the extensions it handles",
"go: rejects a file preview slot or extension list that is not safe",
"slots: an add-on's settings sections are drawn on the Settings tab of its own details and nowhere else",
"slots: the Settings page lists the add-ons that have settings, each a link to its Settings tab",
"slots: the old anchor of a section on the Settings page opens the add-on's Settings tab",
"slots: the add-on page and its details offer the settings to an administrator only",
"slots: the navigation slot adds its entry below the tile grid of the Add-ons drawer"
]
},
"foundation-acceptance": {
"kind": "shell",
"commands": [
[
"sh",
"scripts/addons/foundation.sh"
]
],
"cases": [
"go: fails closed on every frontend while the owner is down, executes nothing locally and recovers the last good package and data on restart",
"go: refuses a second owner on the same storage and keeps one process per add-on",
"go: stops an add-on process orphaned by an owner crash before it starts the next one",
"go: leaves no process behind when a cluster with an orphaned add-on is taken down",
"go: keeps the last good generation running and its data when an upgrade fails to start",
"go: keeps the last good code and data when the owner is killed in the middle of an upgrade and recovers on restart",
"go: keeps retained data and a consistent lifecycle when the owner is killed in the middle of an enable",
"go: keeps the files of the package of an installed add-on read only",
"go: keeps the last good generation running and the retained data when the new generation cannot start",
"go: restores the last good generation and resumes the same operation when the request is canceled during an upgrade start",
"go: converges on the last good generation after a crash that follows the rollback start and precedes any journal write",
"go: starts the owner when an enabled add-on cannot become ready and fails only that add-on",
"go: gives an ordinary account the apps list and no management on any node",
"go: returns the same typed denial from the owner and from each frontend",
"go: refuses a session on every node once it was ended through one frontend",
"go: refuses an API key on every node once it was revoked through one frontend",
"go: installs the UI, tool and service-only packages from the catalog through a frontend without starting them and leaves the host binary and UI build unchanged",
"go: activates each package through the other frontend and runs one process per add-on under the owner only",
"go: lists the same apps from the owner and both frontends and shows only what each declared",
"go: serves reads of the UI, tool and service-only packages alternately through the owner and both frontends",
"go: denies an account without the feature, a stranger to the resource and an anonymous caller the same way on every node",
"go: takes the actor from the authenticated credential only and ignores forged actor and authority headers",
"go: denies a tool the add-on did not declare and a generation that is not current on every node",
"go: relays JSON and a private file result and downloads the file through a different frontend than the one that produced it",
"go: relays lifecycle status and progress of an operation to the administrator who made it and to nobody else",
"go: serves the immutable UI assets by package digest through a non-owner frontend and refuses everything else",
"go: applies one confirmed change exactly once through a different frontend than the one that proposed it",
"go: reports a lost reply as outcome unknown with the original operation ID and settles it by receipt lookup without a second apply",
"go: upgrades to a new generation, denies the previous generation and its assets, and keeps the retained data",
"go: disables, removes and reinstalls an add-on while its data and grants remain",
"go: never changes the host binary or the shipped UI build over the whole lifecycle",
"regression: model and backend gallery specs (core/gallery)",
"regression: gallery operation specs (core/services/galleryop)",
"regression: process adapter specs (pkg/model)",
"foundation: a member opens the add-on through each non-owner frontend and its module comes from the owner by digest",
"foundation: the owner and both frontends list the same add-on to the same account",
"foundation: a member sees the add-on list only and the server refuses every management request",
"foundation: an account without the add-ons feature gets no apps and no code on any node",
"foundation: an administrator manages through a frontend and the change is the owner's",
"foundation: deep links of the add-on page work behind a proxy path prefix on a non-owner frontend",
"foundation: a session ended through one frontend is refused for add-on assets by the other servers"
]
},
"tables-databases": {
"kind": "ginkgo",
"commands": [
[
"go",
"test",
"-count=1",
"-p",
"2",
"-tags",
"auth",
"./addons/tables/internal/store",
"-ginkgo.json-report=../../../../.cache/addons/logs/tables-databases-store.json"
],
[
"go",
"test",
"-count=1",
"-p",
"2",
"-tags",
"auth",
"./tests/addons/tables",
"-ginkgo.json-report=../../../.cache/addons/logs/tables-databases.json"
]
],
"report": ".cache/addons/logs/tables-databases-store.json",
"reports": [
{
"path": ".cache/addons/logs/tables-databases-store.json",
"cases": [
"enforces the size cap on every connection and fails with a typed capacity error",
"builds a database under a data directory containing percent, question and hash characters",
"leaves no change and no receipt when the process dies before commit, and the ID can still apply",
"finds the committed receipt after a crash between commit and reply and never applies twice",
"replays one operation ID to one receipt and refuses another request under the same ID",
"applies one change once when the same operation arrives concurrently",
"keeps a rejected change out of the receipts so its ID is not burnt",
"encodes the receipt payload so the host can read what changed",
"creates, renames and drops tables with stable internal identifiers and one revision step each",
"adds typed columns, renames them without touching identifiers and never uses a label in SQL",
"validates labels by length, characters and case-insensitive uniqueness",
"refuses type changes, unknown operations, expressions and unknown types",
"encodes typed defaults as literals and survives hostile defaults",
"enforces required columns and refuses unique defaults that would collide",
"adds a unique column through a unique index and refuses duplicates atomically",
"drops a column by rebuilding the table and loses exactly what the preview reported",
"never hands out a row ID again after a column drop rebuilds the table",
"keeps the row ID counter when a column drop rebuilds a table emptied by deletes",
"leaves the original table, data and revision intact when a rebuild fails midway",
"previews exact effects and dependent data loss and changes nothing",
"refuses a stale expected revision with the current revision and applies nothing",
"keeps finite limits on tables and columns",
"migrates a database made before the catalog existed on its first schema change",
"inserts bound rows atomically with defaults, required and unique checks",
"updates by explicit IDs and by filter and bumps only the data revision",
"deletes by IDs or filter and refuses broad, empty or oversized selections",
"previews exact count, sample and conflicts without changing anything",
"refuses a changed revision and never re-evaluates a filter against new rows",
"applies exactly one of two proposals made on the same revision",
"replays a row operation by ID and refuses another request under the same ID",
"leaves no change when the process dies before commit and finds the receipt after commit",
"reserves the row id label so no column can shadow it",
"keeps a row table's data across a column drop that rebuilds it",
"reads selected columns with stable row IDs and typed JSON values",
"filters with bounded AND/OR trees and every operator, matching a reference evaluator on random trees",
"escapes LIKE wildcards in text filters",
"keeps NULL semantics: comparisons never match NULL and is-null finds it",
"sorts with a stable row ID tie-break and pages through a cursor that stops at a revision change",
"counts, sums, averages and bounds groups of aggregates",
"reports a real sum or average that overflows as the typed arithmetic error",
"never lets a label, operator or value reach SQL as text",
"honours hard limits on page size, filter depth, conditions, in-lists, sort keys and result bytes",
"stops a query when the context is cancelled or the deadline passes",
"encodes all five types as JSON and writes 64-bit integers as strings beyond 2^53",
"orders datetimes chronologically across fractional seconds and offsets",
"creates one private WAL database file named by the host resource ID",
"never lets an opaque ID or a name reach outside the storage directory",
"refuses a symbolic link as storage directory, database file or ledger",
"is idempotent by operation ID and never creates a second database",
"serializes concurrent creation of one operation into one database",
"recovers creation after a crash on either side of the file, and hides half-built files",
"renames only the named database and replays a renamed operation without effect",
"reports an unknown database and creates nothing for it",
"honours the busy timeout and the per-operation deadline, then succeeds once the lock is gone",
"encodes its receipts so the host can read them",
"writes a header and one record per row with RFC 4180 quoting, UTF-8 and the documented value forms",
"prefixes text cells and labels that a spreadsheet would run, never numbers",
"honours columns, the row identifier column, filter, sort and the row limit of the query",
"reads one snapshot: writes that commit while the export streams are not in it, and are not blocked by it",
"streams a large table row by row with bounded memory",
"fails cleanly past the row or byte bound and keeps the bound finite by default",
"stops on cancellation, on its deadline and on a failing destination, and reports each",
"does not change the database it reads",
"records the current format of a new store and migrates nothing",
"migrates every database in its own transaction, records the version last and repeats as a no-op",
"leaves a database whose step fails exactly as it was and resumes on the next run",
"refuses data in a newer format, a downgrade and a version it has no path to, and writes nothing",
"leaves no pending line for a change the add-on refused, so the same ID applies the corrected request",
"records an inverse for an insert and removes exactly those rows on undo",
"restores the previous values of an update, for the columns it set only",
"brings deleted rows back with their row IDs and every value, nulls included",
"is idempotent by operation ID: the same ID returns the same receipt and undoes once",
"refuses the same operation ID for another change",
"refuses a stale undo with what changed and overwrites nothing",
"refuses an undo whose expected revision moved between the read and the apply",
"unwinds in order: undoing the latest change makes the earlier one undoable again",
"keeps no change set that is too large and says so at apply time",
"expires a change set after the retention and drops what it held",
"keeps the total of change sets of one database bounded by dropping the oldest",
"answers not found for a change that never existed or belongs to a read",
"removes a created table again and refuses once it was touched",
"renames a table or a column back",
"removes an added column again, with its unique index",
"restores a dropped column with its data, its type, required and unique flags",
"restores a dropped table with its columns, rows and row IDs",
"says a dropped column or table was too large to keep, at apply time",
"renames the database back only while it still has the new name",
"undoes a creation only while the database is untouched, and marks that the resource is deleted",
"keeps the change sets in the database file, so deleting the database removes them"
]
},
{
"path": ".cache/addons/logs/tables-databases.json",
"cases": [
"starts the real executable through the authenticated handshake and refuses unauthenticated callers",
"creates a database under the host-assigned ID and lists it only for people who may read it",
"drops the reservation when the addon refuses the name, and leaves no database",
"drops a reservation at reconcile when the crash came before the database was created",
"commits a reservation at reconcile when the crash came after the database was created",
"never exposes a database that has no host record",
"renames one database by operation, replays safely, and leaves every other database alone",
"rejects an undeclared tool, a forged addon binding and an unknown resource",
"keeps databases and operation receipts across an addon restart",
"fails closed when the addon cannot answer, and drops only for an addon that is not installed",
"creates a database from a chat proposal that only the proposer's session confirms",
"settles reservations at bootstrap by asking the real addon and keeps those of pending proposals",
"reads and mutates rows with the exact preview, refuses wrong actions and keeps receipts across a restart",
"declares the row tools and refuses a row tool the manifest does not name",
"changes the schema as the owner, shows data loss in the preview and refuses an editor at the host and the addon",
"rejects a stale schema revision, replays an operation and keeps receipts across a restart",
"declares the schema tools and refuses any schema tool the manifest does not name",
"applies row changes only on the proposer's confirmation and rejects a proposal whose database moved",
"offers the manifest tools to a permitted user and nothing to a user without the feature or after revocation",
"applies a change a chat makes at once for the chat's user, leaves no proposal, and still refuses a key",
"stores every change as a pending proposal and applies it only on the proposer's own session, exactly once",
"keeps the roles of the host for tool calls and rejects forged fields before the owner sees them",
"lists at most the bound of pending proposals and refuses more than the user's quota",
"tells the model and the chat that a data change can be undone, and undoes it from the person's own tab",
"never lets a key, a tool call, another session or a stranger undo, so a model cannot undo its own work",
"refuses a stale undo with what changed, and unwinds from the newest change to the oldest",
"answers not_found for a change nobody recorded",
"restores a dropped column with its data and puts a dropped table back",
"undoes the creation of a database only while nothing touched it, and deletes it then",
"lets an editor undo a data change but not a schema change"
]
}
],
"cases": [
"enforces the size cap on every connection and fails with a typed capacity error",
"builds a database under a data directory containing percent, question and hash characters",
"leaves no change and no receipt when the process dies before commit, and the ID can still apply",
"finds the committed receipt after a crash between commit and reply and never applies twice",
"replays one operation ID to one receipt and refuses another request under the same ID",
"applies one change once when the same operation arrives concurrently",
"keeps a rejected change out of the receipts so its ID is not burnt",
"encodes the receipt payload so the host can read what changed",
"creates, renames and drops tables with stable internal identifiers and one revision step each",
"adds typed columns, renames them without touching identifiers and never uses a label in SQL",
"validates labels by length, characters and case-insensitive uniqueness",
"refuses type changes, unknown operations, expressions and unknown types",
"encodes typed defaults as literals and survives hostile defaults",
"enforces required columns and refuses unique defaults that would collide",
"adds a unique column through a unique index and refuses duplicates atomically",
"drops a column by rebuilding the table and loses exactly what the preview reported",
"never hands out a row ID again after a column drop rebuilds the table",
"keeps the row ID counter when a column drop rebuilds a table emptied by deletes",
"leaves the original table, data and revision intact when a rebuild fails midway",
"previews exact effects and dependent data loss and changes nothing",
"refuses a stale expected revision with the current revision and applies nothing",
"keeps finite limits on tables and columns",
"migrates a database made before the catalog existed on its first schema change",
"inserts bound rows atomically with defaults, required and unique checks",
"updates by explicit IDs and by filter and bumps only the data revision",
"deletes by IDs or filter and refuses broad, empty or oversized selections",
"previews exact count, sample and conflicts without changing anything",
"refuses a changed revision and never re-evaluates a filter against new rows",
"applies exactly one of two proposals made on the same revision",
"replays a row operation by ID and refuses another request under the same ID",
"leaves no change when the process dies before commit and finds the receipt after commit",
"reserves the row id label so no column can shadow it",
"keeps a row table's data across a column drop that rebuilds it",
"reads selected columns with stable row IDs and typed JSON values",
"filters with bounded AND/OR trees and every operator, matching a reference evaluator on random trees",
"escapes LIKE wildcards in text filters",
"keeps NULL semantics: comparisons never match NULL and is-null finds it",
"sorts with a stable row ID tie-break and pages through a cursor that stops at a revision change",
"counts, sums, averages and bounds groups of aggregates",
"reports a real sum or average that overflows as the typed arithmetic error",
"never lets a label, operator or value reach SQL as text",
"honours hard limits on page size, filter depth, conditions, in-lists, sort keys and result bytes",
"stops a query when the context is cancelled or the deadline passes",
"encodes all five types as JSON and writes 64-bit integers as strings beyond 2^53",
"orders datetimes chronologically across fractional seconds and offsets",
"creates one private WAL database file named by the host resource ID",
"never lets an opaque ID or a name reach outside the storage directory",
"refuses a symbolic link as storage directory, database file or ledger",
"is idempotent by operation ID and never creates a second database",
"serializes concurrent creation of one operation into one database",
"recovers creation after a crash on either side of the file, and hides half-built files",
"renames only the named database and replays a renamed operation without effect",
"reports an unknown database and creates nothing for it",
"honours the busy timeout and the per-operation deadline, then succeeds once the lock is gone",
"encodes its receipts so the host can read them",
"writes a header and one record per row with RFC 4180 quoting, UTF-8 and the documented value forms",
"prefixes text cells and labels that a spreadsheet would run, never numbers",
"honours columns, the row identifier column, filter, sort and the row limit of the query",
"reads one snapshot: writes that commit while the export streams are not in it, and are not blocked by it",
"streams a large table row by row with bounded memory",
"fails cleanly past the row or byte bound and keeps the bound finite by default",
"stops on cancellation, on its deadline and on a failing destination, and reports each",
"does not change the database it reads",
"records the current format of a new store and migrates nothing",
"migrates every database in its own transaction, records the version last and repeats as a no-op",
"leaves a database whose step fails exactly as it was and resumes on the next run",
"refuses data in a newer format, a downgrade and a version it has no path to, and writes nothing",
"leaves no pending line for a change the add-on refused, so the same ID applies the corrected request",
"starts the real executable through the authenticated handshake and refuses unauthenticated callers",
"creates a database under the host-assigned ID and lists it only for people who may read it",
"drops the reservation when the addon refuses the name, and leaves no database",
"drops a reservation at reconcile when the crash came before the database was created",
"commits a reservation at reconcile when the crash came after the database was created",
"never exposes a database that has no host record",
"renames one database by operation, replays safely, and leaves every other database alone",
"rejects an undeclared tool, a forged addon binding and an unknown resource",
"keeps databases and operation receipts across an addon restart",
"fails closed when the addon cannot answer, and drops only for an addon that is not installed",
"creates a database from a chat proposal that only the proposer's session confirms",
"settles reservations at bootstrap by asking the real addon and keeps those of pending proposals",
"reads and mutates rows with the exact preview, refuses wrong actions and keeps receipts across a restart",
"declares the row tools and refuses a row tool the manifest does not name",
"changes the schema as the owner, shows data loss in the preview and refuses an editor at the host and the addon",
"rejects a stale schema revision, replays an operation and keeps receipts across a restart",
"declares the schema tools and refuses any schema tool the manifest does not name",
"applies row changes only on the proposer's confirmation and rejects a proposal whose database moved",
"offers the manifest tools to a permitted user and nothing to a user without the feature or after revocation",
"applies a change a chat makes at once for the chat's user, leaves no proposal, and still refuses a key",
"stores every change as a pending proposal and applies it only on the proposer's own session, exactly once",
"keeps the roles of the host for tool calls and rejects forged fields before the owner sees them",
"lists at most the bound of pending proposals and refuses more than the user's quota",
"records an inverse for an insert and removes exactly those rows on undo",
"restores the previous values of an update, for the columns it set only",
"brings deleted rows back with their row IDs and every value, nulls included",
"is idempotent by operation ID: the same ID returns the same receipt and undoes once",
"refuses the same operation ID for another change",
"refuses a stale undo with what changed and overwrites nothing",
"refuses an undo whose expected revision moved between the read and the apply",
"unwinds in order: undoing the latest change makes the earlier one undoable again",
"keeps no change set that is too large and says so at apply time",
"expires a change set after the retention and drops what it held",
"keeps the total of change sets of one database bounded by dropping the oldest",
"answers not found for a change that never existed or belongs to a read",
"removes a created table again and refuses once it was touched",
"renames a table or a column back",
"removes an added column again, with its unique index",
"restores a dropped column with its data, its type, required and unique flags",
"restores a dropped table with its columns, rows and row IDs",
"says a dropped column or table was too large to keep, at apply time",
"renames the database back only while it still has the new name",
"undoes a creation only while the database is untouched, and marks that the resource is deleted",
"keeps the change sets in the database file, so deleting the database removes them",
"tells the model and the chat that a data change can be undone, and undoes it from the person's own tab",
"never lets a key, a tool call, another session or a stranger undo, so a model cannot undo its own work",
"refuses a stale undo with what changed, and unwinds from the newest change to the oldest",
"answers not_found for a change nobody recorded",
"restores a dropped column with its data and puts a dropped table back",
"undoes the creation of a database only while nothing touched it, and deletes it then",
"lets an editor undo a data change but not a schema change"
]
},
"tables-schema": {
"kind": "ginkgo",
"commands": [
[
"go",
"test",
"-count=1",
"-p",
"2",
"-tags",
"auth",
"./addons/tables/internal/store",
"-ginkgo.json-report=../../../../.cache/addons/logs/tables-schema-store.json"
],
[
"go",
"test",
"-count=1",
"-p",
"2",
"-tags",
"auth",
"./tests/addons/tables",
"-ginkgo.json-report=../../../.cache/addons/logs/tables-schema.json"
]
],
"report": ".cache/addons/logs/tables-schema-store.json",
"reports": [
{
"path": ".cache/addons/logs/tables-schema-store.json",
"cases": [
"enforces the size cap on every connection and fails with a typed capacity error",
"builds a database under a data directory containing percent, question and hash characters",
"leaves no change and no receipt when the process dies before commit, and the ID can still apply",
"finds the committed receipt after a crash between commit and reply and never applies twice",
"replays one operation ID to one receipt and refuses another request under the same ID",
"applies one change once when the same operation arrives concurrently",
"keeps a rejected change out of the receipts so its ID is not burnt",
"encodes the receipt payload so the host can read what changed",
"creates, renames and drops tables with stable internal identifiers and one revision step each",
"adds typed columns, renames them without touching identifiers and never uses a label in SQL",
"validates labels by length, characters and case-insensitive uniqueness",
"refuses type changes, unknown operations, expressions and unknown types",
"encodes typed defaults as literals and survives hostile defaults",
"enforces required columns and refuses unique defaults that would collide",
"adds a unique column through a unique index and refuses duplicates atomically",
"drops a column by rebuilding the table and loses exactly what the preview reported",
"never hands out a row ID again after a column drop rebuilds the table",
"keeps the row ID counter when a column drop rebuilds a table emptied by deletes",
"leaves the original table, data and revision intact when a rebuild fails midway",
"previews exact effects and dependent data loss and changes nothing",
"refuses a stale expected revision with the current revision and applies nothing",
"keeps finite limits on tables and columns",
"migrates a database made before the catalog existed on its first schema change",
"inserts bound rows atomically with defaults, required and unique checks",
"updates by explicit IDs and by filter and bumps only the data revision",
"deletes by IDs or filter and refuses broad, empty or oversized selections",
"previews exact count, sample and conflicts without changing anything",
"refuses a changed revision and never re-evaluates a filter against new rows",
"applies exactly one of two proposals made on the same revision",
"replays a row operation by ID and refuses another request under the same ID",
"leaves no change when the process dies before commit and finds the receipt after commit",
"reserves the row id label so no column can shadow it",
"keeps a row table's data across a column drop that rebuilds it",
"reads selected columns with stable row IDs and typed JSON values",
"filters with bounded AND/OR trees and every operator, matching a reference evaluator on random trees",
"escapes LIKE wildcards in text filters",
"keeps NULL semantics: comparisons never match NULL and is-null finds it",
"sorts with a stable row ID tie-break and pages through a cursor that stops at a revision change",
"counts, sums, averages and bounds groups of aggregates",
"reports a real sum or average that overflows as the typed arithmetic error",
"never lets a label, operator or value reach SQL as text",
"honours hard limits on page size, filter depth, conditions, in-lists, sort keys and result bytes",
"stops a query when the context is cancelled or the deadline passes",
"encodes all five types as JSON and writes 64-bit integers as strings beyond 2^53",
"orders datetimes chronologically across fractional seconds and offsets",
"creates one private WAL database file named by the host resource ID",
"never lets an opaque ID or a name reach outside the storage directory",
"refuses a symbolic link as storage directory, database file or ledger",
"is idempotent by operation ID and never creates a second database",
"serializes concurrent creation of one operation into one database",
"recovers creation after a crash on either side of the file, and hides half-built files",
"renames only the named database and replays a renamed operation without effect",
"reports an unknown database and creates nothing for it",
"honours the busy timeout and the per-operation deadline, then succeeds once the lock is gone",
"encodes its receipts so the host can read them",
"writes a header and one record per row with RFC 4180 quoting, UTF-8 and the documented value forms",
"prefixes text cells and labels that a spreadsheet would run, never numbers",
"honours columns, the row identifier column, filter, sort and the row limit of the query",
"reads one snapshot: writes that commit while the export streams are not in it, and are not blocked by it",
"streams a large table row by row with bounded memory",
"fails cleanly past the row or byte bound and keeps the bound finite by default",
"stops on cancellation, on its deadline and on a failing destination, and reports each",
"does not change the database it reads",
"records the current format of a new store and migrates nothing",
"migrates every database in its own transaction, records the version last and repeats as a no-op",
"leaves a database whose step fails exactly as it was and resumes on the next run",
"refuses data in a newer format, a downgrade and a version it has no path to, and writes nothing",
"leaves no pending line for a change the add-on refused, so the same ID applies the corrected request",
"records an inverse for an insert and removes exactly those rows on undo",
"restores the previous values of an update, for the columns it set only",
"brings deleted rows back with their row IDs and every value, nulls included",
"is idempotent by operation ID: the same ID returns the same receipt and undoes once",
"refuses the same operation ID for another change",
"refuses a stale undo with what changed and overwrites nothing",
"refuses an undo whose expected revision moved between the read and the apply",
"unwinds in order: undoing the latest change makes the earlier one undoable again",
"keeps no change set that is too large and says so at apply time",
"expires a change set after the retention and drops what it held",
"keeps the total of change sets of one database bounded by dropping the oldest",
"answers not found for a change that never existed or belongs to a read",
"removes a created table again and refuses once it was touched",
"renames a table or a column back",
"removes an added column again, with its unique index",
"restores a dropped column with its data, its type, required and unique flags",
"restores a dropped table with its columns, rows and row IDs",
"says a dropped column or table was too large to keep, at apply time",
"renames the database back only while it still has the new name",
"undoes a creation only while the database is untouched, and marks that the resource is deleted",
"keeps the change sets in the database file, so deleting the database removes them"
]
},
{
"path": ".cache/addons/logs/tables-schema.json",
"cases": [
"starts the real executable through the authenticated handshake and refuses unauthenticated callers",
"creates a database under the host-assigned ID and lists it only for people who may read it",
"drops the reservation when the addon refuses the name, and leaves no database",
"drops a reservation at reconcile when the crash came before the database was created",
"commits a reservation at reconcile when the crash came after the database was created",
"never exposes a database that has no host record",
"renames one database by operation, replays safely, and leaves every other database alone",
"rejects an undeclared tool, a forged addon binding and an unknown resource",
"keeps databases and operation receipts across an addon restart",
"fails closed when the addon cannot answer, and drops only for an addon that is not installed",
"creates a database from a chat proposal that only the proposer's session confirms",
"settles reservations at bootstrap by asking the real addon and keeps those of pending proposals",
"reads and mutates rows with the exact preview, refuses wrong actions and keeps receipts across a restart",
"declares the row tools and refuses a row tool the manifest does not name",
"changes the schema as the owner, shows data loss in the preview and refuses an editor at the host and the addon",
"rejects a stale schema revision, replays an operation and keeps receipts across a restart",
"declares the schema tools and refuses any schema tool the manifest does not name",
"applies row changes only on the proposer's confirmation and rejects a proposal whose database moved",
"offers the manifest tools to a permitted user and nothing to a user without the feature or after revocation",
"applies a change a chat makes at once for the chat's user, leaves no proposal, and still refuses a key",
"stores every change as a pending proposal and applies it only on the proposer's own session, exactly once",
"keeps the roles of the host for tool calls and rejects forged fields before the owner sees them",
"lists at most the bound of pending proposals and refuses more than the user's quota",
"tells the model and the chat that a data change can be undone, and undoes it from the person's own tab",
"never lets a key, a tool call, another session or a stranger undo, so a model cannot undo its own work",
"refuses a stale undo with what changed, and unwinds from the newest change to the oldest",
"answers not_found for a change nobody recorded",
"restores a dropped column with its data and puts a dropped table back",
"undoes the creation of a database only while nothing touched it, and deletes it then",
"lets an editor undo a data change but not a schema change"
]
}
],
"cases": [
"enforces the size cap on every connection and fails with a typed capacity error",
"builds a database under a data directory containing percent, question and hash characters",
"leaves no change and no receipt when the process dies before commit, and the ID can still apply",
"finds the committed receipt after a crash between commit and reply and never applies twice",
"replays one operation ID to one receipt and refuses another request under the same ID",
"applies one change once when the same operation arrives concurrently",
"keeps a rejected change out of the receipts so its ID is not burnt",
"encodes the receipt payload so the host can read what changed",
"creates, renames and drops tables with stable internal identifiers and one revision step each",
"adds typed columns, renames them without touching identifiers and never uses a label in SQL",
"validates labels by length, characters and case-insensitive uniqueness",
"refuses type changes, unknown operations, expressions and unknown types",
"encodes typed defaults as literals and survives hostile defaults",
"enforces required columns and refuses unique defaults that would collide",
"adds a unique column through a unique index and refuses duplicates atomically",
"drops a column by rebuilding the table and loses exactly what the preview reported",
"never hands out a row ID again after a column drop rebuilds the table",
"keeps the row ID counter when a column drop rebuilds a table emptied by deletes",
"leaves the original table, data and revision intact when a rebuild fails midway",
"previews exact effects and dependent data loss and changes nothing",
"refuses a stale expected revision with the current revision and applies nothing",
"keeps finite limits on tables and columns",
"migrates a database made before the catalog existed on its first schema change",
"inserts bound rows atomically with defaults, required and unique checks",
"updates by explicit IDs and by filter and bumps only the data revision",
"deletes by IDs or filter and refuses broad, empty or oversized selections",
"previews exact count, sample and conflicts without changing anything",
"refuses a changed revision and never re-evaluates a filter against new rows",
"applies exactly one of two proposals made on the same revision",
"replays a row operation by ID and refuses another request under the same ID",
"leaves no change when the process dies before commit and finds the receipt after commit",
"reserves the row id label so no column can shadow it",
"keeps a row table's data across a column drop that rebuilds it",
"reads selected columns with stable row IDs and typed JSON values",
"filters with bounded AND/OR trees and every operator, matching a reference evaluator on random trees",
"escapes LIKE wildcards in text filters",
"keeps NULL semantics: comparisons never match NULL and is-null finds it",
"sorts with a stable row ID tie-break and pages through a cursor that stops at a revision change",
"counts, sums, averages and bounds groups of aggregates",
"reports a real sum or average that overflows as the typed arithmetic error",
"never lets a label, operator or value reach SQL as text",
"honours hard limits on page size, filter depth, conditions, in-lists, sort keys and result bytes",
"stops a query when the context is cancelled or the deadline passes",
"encodes all five types as JSON and writes 64-bit integers as strings beyond 2^53",
"orders datetimes chronologically across fractional seconds and offsets",
"creates one private WAL database file named by the host resource ID",
"never lets an opaque ID or a name reach outside the storage directory",
"refuses a symbolic link as storage directory, database file or ledger",
"is idempotent by operation ID and never creates a second database",
"serializes concurrent creation of one operation into one database",
"recovers creation after a crash on either side of the file, and hides half-built files",
"renames only the named database and replays a renamed operation without effect",
"reports an unknown database and creates nothing for it",
"honours the busy timeout and the per-operation deadline, then succeeds once the lock is gone",
"encodes its receipts so the host can read them",
"writes a header and one record per row with RFC 4180 quoting, UTF-8 and the documented value forms",
"prefixes text cells and labels that a spreadsheet would run, never numbers",
"honours columns, the row identifier column, filter, sort and the row limit of the query",
"reads one snapshot: writes that commit while the export streams are not in it, and are not blocked by it",
"streams a large table row by row with bounded memory",
"fails cleanly past the row or byte bound and keeps the bound finite by default",
"stops on cancellation, on its deadline and on a failing destination, and reports each",
"does not change the database it reads",
"records the current format of a new store and migrates nothing",
"migrates every database in its own transaction, records the version last and repeats as a no-op",
"leaves a database whose step fails exactly as it was and resumes on the next run",
"refuses data in a newer format, a downgrade and a version it has no path to, and writes nothing",
"leaves no pending line for a change the add-on refused, so the same ID applies the corrected request",
"starts the real executable through the authenticated handshake and refuses unauthenticated callers",
"creates a database under the host-assigned ID and lists it only for people who may read it",
"drops the reservation when the addon refuses the name, and leaves no database",
"drops a reservation at reconcile when the crash came before the database was created",
"commits a reservation at reconcile when the crash came after the database was created",
"never exposes a database that has no host record",
"renames one database by operation, replays safely, and leaves every other database alone",
"rejects an undeclared tool, a forged addon binding and an unknown resource",
"keeps databases and operation receipts across an addon restart",
"fails closed when the addon cannot answer, and drops only for an addon that is not installed",
"creates a database from a chat proposal that only the proposer's session confirms",
"settles reservations at bootstrap by asking the real addon and keeps those of pending proposals",
"reads and mutates rows with the exact preview, refuses wrong actions and keeps receipts across a restart",
"declares the row tools and refuses a row tool the manifest does not name",
"changes the schema as the owner, shows data loss in the preview and refuses an editor at the host and the addon",
"rejects a stale schema revision, replays an operation and keeps receipts across a restart",
"declares the schema tools and refuses any schema tool the manifest does not name",
"applies row changes only on the proposer's confirmation and rejects a proposal whose database moved",
"offers the manifest tools to a permitted user and nothing to a user without the feature or after revocation",
"applies a change a chat makes at once for the chat's user, leaves no proposal, and still refuses a key",
"stores every change as a pending proposal and applies it only on the proposer's own session, exactly once",
"keeps the roles of the host for tool calls and rejects forged fields before the owner sees them",
"lists at most the bound of pending proposals and refuses more than the user's quota",
"records an inverse for an insert and removes exactly those rows on undo",
"restores the previous values of an update, for the columns it set only",
"brings deleted rows back with their row IDs and every value, nulls included",
"is idempotent by operation ID: the same ID returns the same receipt and undoes once",
"refuses the same operation ID for another change",
"refuses a stale undo with what changed and overwrites nothing",
"refuses an undo whose expected revision moved between the read and the apply",
"unwinds in order: undoing the latest change makes the earlier one undoable again",
"keeps no change set that is too large and says so at apply time",
"expires a change set after the retention and drops what it held",
"keeps the total of change sets of one database bounded by dropping the oldest",
"answers not found for a change that never existed or belongs to a read",
"removes a created table again and refuses once it was touched",
"renames a table or a column back",
"removes an added column again, with its unique index",
"restores a dropped column with its data, its type, required and unique flags",
"restores a dropped table with its columns, rows and row IDs",
"says a dropped column or table was too large to keep, at apply time",
"renames the database back only while it still has the new name",
"undoes a creation only while the database is untouched, and marks that the resource is deleted",
"keeps the change sets in the database file, so deleting the database removes them",
"tells the model and the chat that a data change can be undone, and undoes it from the person's own tab",
"never lets a key, a tool call, another session or a stranger undo, so a model cannot undo its own work",
"refuses a stale undo with what changed, and unwinds from the newest change to the oldest",
"answers not_found for a change nobody recorded",
"restores a dropped column with its data and puts a dropped table back",
"undoes the creation of a database only while nothing touched it, and deletes it then",
"lets an editor undo a data change but not a schema change"
]
},
"tables-rows": {
"kind": "ginkgo",
"commands": [
[
"go",
"test",
"-count=1",
"-p",
"2",
"-tags",
"auth",
"./addons/tables/internal/store",
"-ginkgo.json-report=../../../../.cache/addons/logs/tables-rows-store.json"
],
[
"go",
"test",
"-count=1",
"-p",
"2",
"-tags",
"auth",
"./tests/addons/tables",
"-ginkgo.json-report=../../../.cache/addons/logs/tables-rows.json"
]
],
"report": ".cache/addons/logs/tables-rows-store.json",
"reports": [
{
"path": ".cache/addons/logs/tables-rows-store.json",
"cases": [
"enforces the size cap on every connection and fails with a typed capacity error",
"builds a database under a data directory containing percent, question and hash characters",
"leaves no change and no receipt when the process dies before commit, and the ID can still apply",
"finds the committed receipt after a crash between commit and reply and never applies twice",
"replays one operation ID to one receipt and refuses another request under the same ID",
"applies one change once when the same operation arrives concurrently",
"keeps a rejected change out of the receipts so its ID is not burnt",
"encodes the receipt payload so the host can read what changed",
"creates, renames and drops tables with stable internal identifiers and one revision step each",
"adds typed columns, renames them without touching identifiers and never uses a label in SQL",
"validates labels by length, characters and case-insensitive uniqueness",
"refuses type changes, unknown operations, expressions and unknown types",
"encodes typed defaults as literals and survives hostile defaults",
"enforces required columns and refuses unique defaults that would collide",
"adds a unique column through a unique index and refuses duplicates atomically",
"drops a column by rebuilding the table and loses exactly what the preview reported",
"never hands out a row ID again after a column drop rebuilds the table",
"keeps the row ID counter when a column drop rebuilds a table emptied by deletes",
"leaves the original table, data and revision intact when a rebuild fails midway",
"previews exact effects and dependent data loss and changes nothing",
"refuses a stale expected revision with the current revision and applies nothing",
"keeps finite limits on tables and columns",
"migrates a database made before the catalog existed on its first schema change",
"inserts bound rows atomically with defaults, required and unique checks",
"updates by explicit IDs and by filter and bumps only the data revision",
"deletes by IDs or filter and refuses broad, empty or oversized selections",
"previews exact count, sample and conflicts without changing anything",
"refuses a changed revision and never re-evaluates a filter against new rows",
"applies exactly one of two proposals made on the same revision",
"replays a row operation by ID and refuses another request under the same ID",
"leaves no change when the process dies before commit and finds the receipt after commit",
"reserves the row id label so no column can shadow it",
"keeps a row table's data across a column drop that rebuilds it",
"reads selected columns with stable row IDs and typed JSON values",
"filters with bounded AND/OR trees and every operator, matching a reference evaluator on random trees",
"escapes LIKE wildcards in text filters",
"keeps NULL semantics: comparisons never match NULL and is-null finds it",
"sorts with a stable row ID tie-break and pages through a cursor that stops at a revision change",
"counts, sums, averages and bounds groups of aggregates",
"reports a real sum or average that overflows as the typed arithmetic error",
"never lets a label, operator or value reach SQL as text",
"honours hard limits on page size, filter depth, conditions, in-lists, sort keys and result bytes",
"stops a query when the context is cancelled or the deadline passes",
"encodes all five types as JSON and writes 64-bit integers as strings beyond 2^53",
"orders datetimes chronologically across fractional seconds and offsets",
"creates one private WAL database file named by the host resource ID",
"never lets an opaque ID or a name reach outside the storage directory",
"refuses a symbolic link as storage directory, database file or ledger",
"is idempotent by operation ID and never creates a second database",
"serializes concurrent creation of one operation into one database",
"recovers creation after a crash on either side of the file, and hides half-built files",
"renames only the named database and replays a renamed operation without effect",
"reports an unknown database and creates nothing for it",
"honours the busy timeout and the per-operation deadline, then succeeds once the lock is gone",
"encodes its receipts so the host can read them",
"writes a header and one record per row with RFC 4180 quoting, UTF-8 and the documented value forms",
"prefixes text cells and labels that a spreadsheet would run, never numbers",
"honours columns, the row identifier column, filter, sort and the row limit of the query",
"reads one snapshot: writes that commit while the export streams are not in it, and are not blocked by it",
"streams a large table row by row with bounded memory",
"fails cleanly past the row or byte bound and keeps the bound finite by default",
"stops on cancellation, on its deadline and on a failing destination, and reports each",
"does not change the database it reads",
"records the current format of a new store and migrates nothing",
"migrates every database in its own transaction, records the version last and repeats as a no-op",
"leaves a database whose step fails exactly as it was and resumes on the next run",
"refuses data in a newer format, a downgrade and a version it has no path to, and writes nothing",
"leaves no pending line for a change the add-on refused, so the same ID applies the corrected request",
"records an inverse for an insert and removes exactly those rows on undo",
"restores the previous values of an update, for the columns it set only",
"brings deleted rows back with their row IDs and every value, nulls included",
"is idempotent by operation ID: the same ID returns the same receipt and undoes once",
"refuses the same operation ID for another change",
"refuses a stale undo with what changed and overwrites nothing",
"refuses an undo whose expected revision moved between the read and the apply",
"unwinds in order: undoing the latest change makes the earlier one undoable again",
"keeps no change set that is too large and says so at apply time",
"expires a change set after the retention and drops what it held",
"keeps the total of change sets of one database bounded by dropping the oldest",
"answers not found for a change that never existed or belongs to a read",
"removes a created table again and refuses once it was touched",
"renames a table or a column back",
"removes an added column again, with its unique index",
"restores a dropped column with its data, its type, required and unique flags",
"restores a dropped table with its columns, rows and row IDs",
"says a dropped column or table was too large to keep, at apply time",
"renames the database back only while it still has the new name",
"undoes a creation only while the database is untouched, and marks that the resource is deleted",
"keeps the change sets in the database file, so deleting the database removes them"
]
},
{
"path": ".cache/addons/logs/tables-rows.json",
"cases": [
"starts the real executable through the authenticated handshake and refuses unauthenticated callers",
"creates a database under the host-assigned ID and lists it only for people who may read it",
"drops the reservation when the addon refuses the name, and leaves no database",
"drops a reservation at reconcile when the crash came before the database was created",
"commits a reservation at reconcile when the crash came after the database was created",
"never exposes a database that has no host record",
"renames one database by operation, replays safely, and leaves every other database alone",
"rejects an undeclared tool, a forged addon binding and an unknown resource",
"keeps databases and operation receipts across an addon restart",
"fails closed when the addon cannot answer, and drops only for an addon that is not installed",
"creates a database from a chat proposal that only the proposer's session confirms",
"settles reservations at bootstrap by asking the real addon and keeps those of pending proposals",
"reads and mutates rows with the exact preview, refuses wrong actions and keeps receipts across a restart",
"declares the row tools and refuses a row tool the manifest does not name",
"changes the schema as the owner, shows data loss in the preview and refuses an editor at the host and the addon",
"rejects a stale schema revision, replays an operation and keeps receipts across a restart",
"declares the schema tools and refuses any schema tool the manifest does not name",
"applies row changes only on the proposer's confirmation and rejects a proposal whose database moved",
"offers the manifest tools to a permitted user and nothing to a user without the feature or after revocation",
"applies a change a chat makes at once for the chat's user, leaves no proposal, and still refuses a key",
"stores every change as a pending proposal and applies it only on the proposer's own session, exactly once",
"keeps the roles of the host for tool calls and rejects forged fields before the owner sees them",
"lists at most the bound of pending proposals and refuses more than the user's quota",
"tells the model and the chat that a data change can be undone, and undoes it from the person's own tab",
"never lets a key, a tool call, another session or a stranger undo, so a model cannot undo its own work",
"refuses a stale undo with what changed, and unwinds from the newest change to the oldest",
"answers not_found for a change nobody recorded",
"restores a dropped column with its data and puts a dropped table back",
"undoes the creation of a database only while nothing touched it, and deletes it then",
"lets an editor undo a data change but not a schema change"
]
}
],
"cases": [
"enforces the size cap on every connection and fails with a typed capacity error",
"builds a database under a data directory containing percent, question and hash characters",
"leaves no change and no receipt when the process dies before commit, and the ID can still apply",
"finds the committed receipt after a crash between commit and reply and never applies twice",
"replays one operation ID to one receipt and refuses another request under the same ID",
"applies one change once when the same operation arrives concurrently",
"keeps a rejected change out of the receipts so its ID is not burnt",
"encodes the receipt payload so the host can read what changed",
"creates, renames and drops tables with stable internal identifiers and one revision step each",
"adds typed columns, renames them without touching identifiers and never uses a label in SQL",
"validates labels by length, characters and case-insensitive uniqueness",
"refuses type changes, unknown operations, expressions and unknown types",
"encodes typed defaults as literals and survives hostile defaults",
"enforces required columns and refuses unique defaults that would collide",
"adds a unique column through a unique index and refuses duplicates atomically",
"drops a column by rebuilding the table and loses exactly what the preview reported",
"never hands out a row ID again after a column drop rebuilds the table",
"keeps the row ID counter when a column drop rebuilds a table emptied by deletes",
"leaves the original table, data and revision intact when a rebuild fails midway",
"previews exact effects and dependent data loss and changes nothing",
"refuses a stale expected revision with the current revision and applies nothing",
"keeps finite limits on tables and columns",
"migrates a database made before the catalog existed on its first schema change",
"inserts bound rows atomically with defaults, required and unique checks",
"updates by explicit IDs and by filter and bumps only the data revision",
"deletes by IDs or filter and refuses broad, empty or oversized selections",
"previews exact count, sample and conflicts without changing anything",
"refuses a changed revision and never re-evaluates a filter against new rows",
"applies exactly one of two proposals made on the same revision",
"replays a row operation by ID and refuses another request under the same ID",
"leaves no change when the process dies before commit and finds the receipt after commit",
"reserves the row id label so no column can shadow it",
"keeps a row table's data across a column drop that rebuilds it",
"reads selected columns with stable row IDs and typed JSON values",
"filters with bounded AND/OR trees and every operator, matching a reference evaluator on random trees",
"escapes LIKE wildcards in text filters",
"keeps NULL semantics: comparisons never match NULL and is-null finds it",
"sorts with a stable row ID tie-break and pages through a cursor that stops at a revision change",
"counts, sums, averages and bounds groups of aggregates",
"reports a real sum or average that overflows as the typed arithmetic error",
"never lets a label, operator or value reach SQL as text",
"honours hard limits on page size, filter depth, conditions, in-lists, sort keys and result bytes",
"stops a query when the context is cancelled or the deadline passes",
"encodes all five types as JSON and writes 64-bit integers as strings beyond 2^53",
"orders datetimes chronologically across fractional seconds and offsets",
"creates one private WAL database file named by the host resource ID",
"never lets an opaque ID or a name reach outside the storage directory",
"refuses a symbolic link as storage directory, database file or ledger",
"is idempotent by operation ID and never creates a second database",
"serializes concurrent creation of one operation into one database",
"recovers creation after a crash on either side of the file, and hides half-built files",
"renames only the named database and replays a renamed operation without effect",
"reports an unknown database and creates nothing for it",
"honours the busy timeout and the per-operation deadline, then succeeds once the lock is gone",
"encodes its receipts so the host can read them",
"writes a header and one record per row with RFC 4180 quoting, UTF-8 and the documented value forms",
"prefixes text cells and labels that a spreadsheet would run, never numbers",
"honours columns, the row identifier column, filter, sort and the row limit of the query",
"reads one snapshot: writes that commit while the export streams are not in it, and are not blocked by it",
"streams a large table row by row with bounded memory",
"fails cleanly past the row or byte bound and keeps the bound finite by default",
"stops on cancellation, on its deadline and on a failing destination, and reports each",
"does not change the database it reads",
"records the current format of a new store and migrates nothing",
"migrates every database in its own transaction, records the version last and repeats as a no-op",
"leaves a database whose step fails exactly as it was and resumes on the next run",
"refuses data in a newer format, a downgrade and a version it has no path to, and writes nothing",
"leaves no pending line for a change the add-on refused, so the same ID applies the corrected request",
"starts the real executable through the authenticated handshake and refuses unauthenticated callers",
"creates a database under the host-assigned ID and lists it only for people who may read it",
"drops the reservation when the addon refuses the name, and leaves no database",
"drops a reservation at reconcile when the crash came before the database was created",
"commits a reservation at reconcile when the crash came after the database was created",
"never exposes a database that has no host record",
"renames one database by operation, replays safely, and leaves every other database alone",
"rejects an undeclared tool, a forged addon binding and an unknown resource",
"keeps databases and operation receipts across an addon restart",
"fails closed when the addon cannot answer, and drops only for an addon that is not installed",
"creates a database from a chat proposal that only the proposer's session confirms",
"settles reservations at bootstrap by asking the real addon and keeps those of pending proposals",
"reads and mutates rows with the exact preview, refuses wrong actions and keeps receipts across a restart",
"declares the row tools and refuses a row tool the manifest does not name",
"changes the schema as the owner, shows data loss in the preview and refuses an editor at the host and the addon",
"rejects a stale schema revision, replays an operation and keeps receipts across a restart",
"declares the schema tools and refuses any schema tool the manifest does not name",
"applies row changes only on the proposer's confirmation and rejects a proposal whose database moved",
"offers the manifest tools to a permitted user and nothing to a user without the feature or after revocation",
"applies a change a chat makes at once for the chat's user, leaves no proposal, and still refuses a key",
"stores every change as a pending proposal and applies it only on the proposer's own session, exactly once",
"keeps the roles of the host for tool calls and rejects forged fields before the owner sees them",
"lists at most the bound of pending proposals and refuses more than the user's quota",
"records an inverse for an insert and removes exactly those rows on undo",
"restores the previous values of an update, for the columns it set only",
"brings deleted rows back with their row IDs and every value, nulls included",
"is idempotent by operation ID: the same ID returns the same receipt and undoes once",
"refuses the same operation ID for another change",
"refuses a stale undo with what changed and overwrites nothing",
"refuses an undo whose expected revision moved between the read and the apply",
"unwinds in order: undoing the latest change makes the earlier one undoable again",
"keeps no change set that is too large and says so at apply time",
"expires a change set after the retention and drops what it held",
"keeps the total of change sets of one database bounded by dropping the oldest",
"answers not found for a change that never existed or belongs to a read",
"removes a created table again and refuses once it was touched",
"renames a table or a column back",
"removes an added column again, with its unique index",
"restores a dropped column with its data, its type, required and unique flags",
"restores a dropped table with its columns, rows and row IDs",
"says a dropped column or table was too large to keep, at apply time",
"renames the database back only while it still has the new name",
"undoes a creation only while the database is untouched, and marks that the resource is deleted",
"keeps the change sets in the database file, so deleting the database removes them",
"tells the model and the chat that a data change can be undone, and undoes it from the person's own tab",
"never lets a key, a tool call, another session or a stranger undo, so a model cannot undo its own work",
"refuses a stale undo with what changed, and unwinds from the newest change to the oldest",
"answers not_found for a change nobody recorded",
"restores a dropped column with its data and puts a dropped table back",
"undoes the creation of a database only while nothing touched it, and deletes it then",
"lets an editor undo a data change but not a schema change"
]
},
"tables-tools": {
"kind": "shell",
"commands": [
[
"sh",
"scripts/addons/tables_tools.sh"
]
],
"cases": [
"unit: tools: the namespace is the brokered add-on tool names only",
"unit: tools: a proposal result of an add-on tool gives its identifier and nothing else",
"unit: tools: other kinds, other tools and malformed identifiers give no card",
"unit: tools: the stored history keeps the reference of a proposal and no row data",
"unit: tools: the card facts come from the stored proposal and never from model text",
"unit: tools: stale, expired, blocked and settled proposals cannot be decided",
"unit: tools: a confirmation names the displayed proposal and its digest and nothing a model supplied",
"go: accepts the Tables definitions and classifies every model-facing tool",
"go: keeps the schema bytes of a parsed manifest equal to what the runtime echoes back",
"go: rejects a definition that declares an identity, role, approval or operation property",
"go: rejects an undeclared tool, a repeated tool, an unknown kind and a missing or unbounded schema",
"go: binds one actor to an executor and serves tools through the broker only",
"go: refuses to bind an executor when the owner denies the actor",
"go: routes the add-on namespace to the broker and never to another executor",
"go: never offers or runs a tool of an MCP session under the add-on namespace",
"go: reads the opt-in once and answers a surface that has no broker with a typed rejection",
"go: takes the actor from the trusted request context only",
"go: classifies every source file that discovers or executes tools",
"go: flags source that hands sessions to the agent library without the namespace filter",
"go: installs the namespace filter wherever sessions reach the agent library",
"go: names a reason and an enforcement for every rejection and an actor for every route, with real files",
"go: keeps the table of the Tables documentation in step with the matrix",
"go: lets only the brokered consumers import the adapter",
"go: has no add-on tool and no add-on route in the admin assistant catalog",
"go: discovers namespaced tools with schemas from the manifest for enabled running addons only",
"go: offers nothing for a disabled, stopped or failed addon and nothing when the owner cannot answer",
"go: has no tool for sharing, deleting a database, purging retained data or approving",
"go: drops a definition whose namespaced name is not a valid function name or does not fit",
"go: reads through the gateway with the immutable actor, the listed generation and the resource taken out of the arguments",
"go: refuses an oversized result instead of truncating it",
"go: returns file results as private artifact references with no bytes",
"go: passes a denial, an outage and an unknown outcome through unchanged",
"go: turns a row change into a proposal reference and never applies",
"go: proposes schema changes under the schema action and creation with no resource",
"go: gives every call its own operation ID so one call can never replay another",
"go: reports a proposal outage with the typed error and no reference",
"go: rejects forged identity, role, approval and operation fields before anything reaches the owner",
"go: rejects approval aliases, undefined tools and names outside the namespace",
"go: rejects arguments that are not exactly one bounded object with known, typed properties",
"go: has no way to confirm, cancel or resolve a proposal",
"go: uses the actor of each call and nothing a previous call left behind",
"go: refuses an actor without a user or credential before any call",
"go: serves the real gateway type as its backend",
"go: lists the caller's own pending proposals the same from the owner and every forwarding frontend",
"go: offers the manifest tools to a permitted user and nothing to a user without the feature or after revocation",
"go: applies a change a chat makes at once for the chat's user, leaves no proposal, and still refuses a key",
"go: stores every change as a pending proposal and applies it only on the proposer's own session, exactly once",
"go: keeps the roles of the host for tool calls and rejects forged fields before the owner sees them",
"go: lists at most the bound of pending proposals and refuses more than the user's quota",
"go: gives the model an error result that says the request was invalid, for a read and for a change",
"go: keeps an outage an error, never the refused result",
"go: are never offered to a model and are unknown when a model calls them",
"go: applies a row change for the chat adapter, as the actor, with the digest it just stored",
"go: says a change can be undone when the add-on kept a change set, with the change ID and what undo does",
"go: says why a change cannot be undone when the add-on says so, and never trusts an undo note with a bad ID",
"go: gives a reason when the add-on says nothing about undo",
"go: keeps the result with the longest undo text small enough for the chat",
"go: stays under the chat's 2 KiB cap for the tool result even with every excerpt at its largest",
"go: keeps the result small enough for the chat to store as valid JSON",
"go: applies a creation and a schema change too",
"go: never confirms for an adapter that is not the chats one, even over an owner that could",
"go: keeps a proposal when the owner cannot apply, so nothing is lost",
"go: withdraws the proposal and reports the error when the apply is refused as stale",
"go: tells the model the call was invalid when the add-on refuses it, and withdraws the proposal",
"go: does not withdraw, and does not claim success, when the outcome is unknown",
"go: does not report a change that the add-on rejected at the apply",
"go: reads the list of add-ons next to the opt-in and consumes both keys",
"go: keeps the boolean form unchanged: a nil list offers every add-on",
"go: offers only the tools of the listed add-ons",
"go: hides the tools of the named add-ons and refuses a call to them as unknown, whatever the list says",
"go: offers nothing for an empty list and for ids that match no add-on",
"go: refuses a call to an add-on that is not listed, as an unknown tool, before the owner is reached",
"go: applies the list through the provider and keeps the actor binding",
"go: passes on the reason the add-on gave, such as a missing engine, and not the generic class",
"go: tells the model a missing permission and an unreachable resource in plain words, for a read and for a change",
"go: accepts a call whose bound body is exactly 1 MiB, end to end, and refuses one byte more",
"go: offers an action tool to the chats adapter and to nobody else",
"go: runs an action tool for the chats adapter as the actor, with the act action, and returns its payload",
"go: tells an action tool which conversation it runs in, from the chat and never from the model",
"go: does not run an action tool for any other adapter, and says the tool is unknown",
"go: is unavailable when the owner cannot act, and never falls back to a read or a proposal",
"go: keeps the argument rules: an identity argument is refused before anything runs",
"go: are listed in any state, with the names they replace and whether they run",
"go: keeps its namespaced name and carries the built-in it shadows, only for a replaceable name"
]
},
"tables-admin": {
"kind": "ginkgo",
"commands": [
[
"go",
"test",
"-count=1",
"-p",
"2",
"-tags",
"auth",
"./tests/addons/tablesadmin",
"-ginkgo.json-report=../../../.cache/addons/logs/tables-admin.json"
]
],
"report": ".cache/addons/logs/tables-admin.json",
"cases": [
"keys a reference by user, conversation and add-on, bounds it per user and in total and expires what is unused",
"is durable, held by one process, never resets a corrupt file and stops writing after a failed sync",
"serves concurrent users without losing a reference",
"keeps the newest bounded number, validates them on load and remaps them with the owner",
"creates private databases by the person's own action, once per operation, and lists them only for their owner",
"keeps the owner, editor and viewer matrix on the UI routes and shows each person only their own role",
"shares whole databases by immutable account ID behind a bounded picker that tells nothing else",
"keeps sharing disabled in local-owner mode with a typed answer and no named users",
"waits for a revoked user's admitted work and cancels it before acknowledging the revocation",
"answers every typed denial exactly as the owner does and carries every mutation to the owner",
"reports an unknown outcome with the original operation ID and leaves reads plainly unavailable when the owner cannot be reached",
"answers the sharing denial of local-owner mode the same from a frontend",
"deletes the data, the grants and the pending proposals only on the owner's typed confirmation and keeps the add-on installed",
"stops and waits for admitted work of every user before it asks the add-on to delete",
"makes the add-on refuse its delete tool under every action but the host's delete action",
"never offers the delete tool to a model, a proposal, a typed read or an agent",
"denies a stale tab: the generation and the revision the owner saw decide, and nothing is removed",
"finishes or undoes a deletion that a crash interrupted at every step",
"keeps the delete tool out of the model tools and their definitions",
"refuses an admin tool that is also a model tool, has a definition, or is not mapped",
"documents every route, every emitted field and every typed answer in the Swagger spec",
"lists every route in the instructions registry, the feature registry and the documentation, with no MCP tool for any",
"keeps one selection per user, conversation and add-on, across people, conversations and restarts",
"lets a tool call omit the database in a conversation and resolves it at the owner with typed errors",
"withdraws the management and the tool path while the add-on is disabled and restores them on enable",
"answers a revoked, deleted or tampered reference like an unknown database and never reuses it",
"applies schema and row changes under the roles of the host, once per operation, with a receipt and no proposal",
"refuses crafted writes by a viewer, an editor's schema change, a revoked editor and an installation administrator",
"carries a UI change to the owner from a forwarding frontend and answers as the owner does",
"exports a table with exact bytes and attachment headers over real HTTP and shows no one else the file",
"keeps a shared database's file private, applies the person's own filter and sort, and denies after the grant is withdrawn",
"serves the same bytes and headers through a forwarding frontend, and fails the same way for a stranger",
"answers a result past the export limit as data with no file",
"binds an output handle to its operation, person and database",
"fails a truncated, grown or vanished stream and never serves it",
"fails the transfer when the store cannot write, and when the source is revoked before completion",
"expires the file only, enforces the quota per person and leaves the database as it was"
]
},
"tables-ui": {
"kind": "shell",
"commands": [
[
"sh",
"scripts/addons/tables_ui.sh"
]
],
"cases": [
"unit: resources: every call carries this add-on and its generation and nothing the add-on chose",
"unit: resources: an operation identifier chosen by the caller is kept across a retry",
"unit: resources: nothing is sent once the add-on is withdrawn",
"unit: resources: a malformed identifier is refused before any request",
"unit: resources: the request of each call names the route, the method and the own-session confirmation",
"unit: resources: an unknown operation and a body the host did not shape are refused",
"unit: resources: typed answers of the host keep their type for the page",
"unit: resources: the client of a stale answer is told it is stale",
"unit: resources: a typed read names the resource the person chose and the client sends it",
"unit: resources: a typed read always carries an operation identifier the owner accepts",
"unit: resources: the conversation header goes on a chat request that uses add-on tools, and only a well-formed one",
"unit: batch: typed rows become wire rows and an untouched optional column is left to its default",
"unit: batch: every cell error is named by row and column and nothing is sent",
"unit: batch: steps stay inside the add-on bounds",
"unit: batch: the selection toggles by row identifier and survives paging",
"unit: layout: Share is offered only where the installation has named accounts",
"unit: layout: a table with no rows offers Add rows once, in its empty state",
"unit: layout: a reader, or a table with no columns, is offered no Add rows",
"unit: errors: each answer of the host gets its own words and recovery",
"unit: codecs: text keeps what was typed, bounds it, and null is explicit",
"unit: codecs: integers are exact up to 64 bits and never silently rounded",
"unit: codecs: reals are finite numbers",
"unit: codecs: booleans are true, false or empty for an optional column",
"unit: codecs: datetimes are read as UTC and sent as RFC 3339",
"unit: codecs: an unknown column type is refused",
"unit: codecs: the editor round-trips stored values",
"unit: codecs: grid text and the unchanged-field test",
"unit: codecs: a datetime with a fraction of a second is not rewritten by editing another field",
"unit: codecs: datetimes are compared as instants and offsets are normalised",
"unit: filters: operators follow the column type",
"unit: filters: a leaf, a list and the null tests are built from typed values",
"unit: filters: a condition that cannot be sent is an error, never dropped",
"unit: query: the arguments are the tool schema and nothing else",
"unit: query: pages go forward by the add-on cursor and back by the ones kept",
"unit: query: a column header cycles ascending, descending and none",
"unit: i18n: every language of the host has every key of the English bundle and nothing else",
"unit: i18n: a translation keeps the placeholders of the English text and carries no markup",
"unit: build: the bundle is plain JavaScript that names nothing it does not define",
"unit: build: the module exports createAddon and imports nothing",
"unit: render: createAddon returns the page, the declared component, a chat action and dispose",
"unit: render: the list, one database and the picker draw their loading state without a host",
"unit: render: what the page read is emptied when the add-on is withdrawn, by signal and by dispose",
"unit: retry: a read that met an unavailable add-on is tried again and then succeeds",
"unit: retry: it gives the last error back after the bound and never loops",
"unit: retry: a refusal, a stale answer or an unknown outcome is never repeated",
"unit: retry: a withdrawn add-on stops the waiting and the reads",
"go: applies schema and row changes under the roles of the host, once per operation, with a receipt and no proposal",
"go: refuses crafted writes by a viewer, an editor's schema change, a revoked editor and an installation administrator",
"go: carries a UI change to the owner from a forwarding frontend and answers as the owner does",
"tables-ui: a new database is private to its owner and a second person sees nothing of it",
"tables-ui: the owner builds a schema and rows, shares by name and each role gets its own controls",
"tables-ui: typed editors, structured filters, sort, paging and bounded batches work on real rows",
"tables-ui: editing another column leaves a datetime with a fraction of a second byte-identical",
"tables-ui: a revoke while a person is editing denies the next save and the page says it is unavailable",
"tables-ui: an installation administrator sees no database of other people and has no data privilege",
"tables-ui: deleting a database shows the warnings, needs the typed name and removes data and shares",
"tables-ui: a tab of an older generation is denied after an upgrade and after a disable",
"tables-ui: the pages work by keyboard, at 400 pixels and in the light and dark themes",
"tables-ui: logging out clears what was read and the next person on the same tab sees none of it",
"tables-ui: in local-owner mode sharing is disabled and the owner still manages databases"
]
},
"tables-csv": {
"kind": "shell",
"commands": [
[
"sh",
"scripts/addons/tables_csv.sh"
]
],
"cases": [
"unit: artifacts: only a host identifier names a file, and the only link is the host route",
"unit: artifacts: the card offers a download only for a complete file that has not expired",
"unit: artifacts: sizes are written with a binary unit",
"unit: artifacts: a tool result keeps well formed identifiers of its own kind only, at most four",
"unit: export: the view becomes the arguments of the tool and nothing a page or a cursor",
"unit: export: the answer is a file, or the reason there is none",
"go: writes a header and one record per row with RFC 4180 quoting, UTF-8 and the documented value forms",
"go: prefixes text cells and labels that a spreadsheet would run, never numbers",
"go: honours columns, the row identifier column, filter, sort and the row limit of the query",
"go: reads one snapshot: writes that commit while the export streams are not in it, and are not blocked by it",
"go: streams a large table row by row with bounded memory",
"go: fails cleanly past the row or byte bound and keeps the bound finite by default",
"go: stops on cancellation, on its deadline and on a failing destination, and reports each",
"go: does not change the database it reads",
"go: answers with one operation-bound CSV output whose bytes the handle streams exactly once",
"go: refuses a handle from another user, another operation, another database or after expiry, and removes expired files",
"go: keeps a handle for a retry until the stream completed",
"go: reports a result past the limit as data without an output, and leaves no file",
"go: removes the staged file when the export fails and bounds what stays staged",
"go: is a read that needs the read action and refuses unknown fields and mutation arguments",
"go: serves the bytes on the protocol output route to the matching envelope only",
"go: exports a table with exact bytes and attachment headers over real HTTP and shows no one else the file",
"go: keeps a shared database's file private, applies the person's own filter and sort, and denies after the grant is withdrawn",
"go: serves the same bytes and headers through a forwarding frontend, and fails the same way for a stranger",
"go: answers a result past the export limit as data with no file",
"go: binds an output handle to its operation, person and database",
"go: fails a truncated, grown or vanished stream and never serves it",
"go: fails the transfer when the store cannot write, and when the source is revoked before completion",
"go: expires the file only, enforces the quota per person and leaves the database as it was",
"go: serves identical bytes and headers from every replica and denies every other way in",
"tables-artifacts: the person exports the view they see and downloads exact bytes with attachment headers",
"tables-artifacts: another person is denied exactly like an unknown file, shared or not",
"tables-artifacts: a viewer exports what they may read and withdrawing the share ends the download",
"tables-artifacts: a result past the export limit gives a message and no file",
"tables-artifacts: a person at the file quota is told so and no file is made",
"tables-artifacts: in local-owner mode the owner exports and downloads with no account",
"go: refuses columns-add under a write action, on preview and on apply",
"go: refuses databases-rename under a write action, on preview and on apply",
"go: refuses tables-create under a write action, on preview and on apply",
"go: refuses columns-add under the schema action with the wrong scope or no actor",
"go: refuses databases-rename under the schema action with the wrong scope or no actor",
"go: refuses tables-create under the schema action with the wrong scope or no actor",
"go: still previews and applies a schema change under the schema action",
"go: says in the receipt of a write that it can be undone, and reads and applies the undo",
"go: rejects a stale undo with a typed code and the words of what changed",
"go: rejects an unknown change as not_found and a repeated one as already_undone",
"go: refuses the undo under any other action or scope, and with no actor",
"go: does not preview the undo: it is applied against the revision the host just read"
]
},
"recovery": {
"kind": "shell",
"commands": [
[
"sh",
"scripts/addons/recovery.sh"
]
],
"cases": [
"unit: recovery: the owner's typed refusals keep their type and nothing else is invented",
"unit: recovery: the banner never reads an unknown state as ready",
"unit: recovery: upgrade progress follows the journaled phases",
"unit: recovery: the verification state is a word before it is a colour",
"unit: recovery: every refusal has words, and an unknown outcome keeps its own",
"unit: recovery: every locale carries the same recovery keys as English",
"unit: recovery: a restore needs a stopped add-on, the typed ID and, from another mode, an account",
"unit: recovery: a purge needs a scope and an add-on that is not running",
"unit: recovery: the client sends the operation as the confirmation header and types the refusals",
"go: backs up, publishes the package, migrates, checks health and publishes the generation in that order",
"go: undoes a failure at every journal phase before the publication and puts the old generation back on its own data",
"go: finishes an upgrade whose publication was made when a later step failed",
"go: applies one rule after a restart at any phase: unpublished is undone, published is finished",
"go: refuses a changed trusted identity and an older data format before it stops or writes anything",
"go: keeps the add-on unavailable in needs-recovery after a failed migration to a new format and retains the package and the recovery copy",
"go: restores the backup itself when a migration that keeps the format fails halfway",
"go: keeps a running add-on unavailable and recoverable when the backup cannot be verified at rollback",
"go: copies a WAL database consistently with a manifest, digests, restricted permissions and the owner state",
"go: holds admission and invalidates pending proposals for the add-on while it copies",
"go: reports a corrupt backup and refuses to use it",
"go: stops before copying when the storage is too small and leaves no partial backup",
"go: leaves no partial backup after a cancellation and starts the add-on again",
"go: starts the add-on again when the copy fails",
"go: keeps the only verified copy and the upgrade recovery copy under an explicit retention policy",
"go: never lets age or count remove the newest verified backup when retention is applied on demand",
"go: restores a local-owner backup to a named account through an explicit mapping",
"go: needs an administrator, the typed add-on ID, an explicit scope and an add-on that is not running",
"go: removes the data and its records but keeps the backups unless they are in the scope",
"go: touches no other add-on",
"go: finishes a purge that stopped after its journal was written",
"go: clears needs-recovery when the data it described is purged",
"go: refuses a backup when the policy cannot drain admitted work",
"go: refuses a backup of another add-on and touches neither data nor access",
"go: never lets a manual backup of half migrated data displace the pinned recovery copy",
"go: puts the data and the owner state back, warns about lost writes and keeps the replaced data as a recovery copy",
"go: counts the operations applied after the backup as lost writes",
"go: does not give back access that was taken away or whose account is gone",
"go: survives a restart that forgets the in-memory state: the revocation log is durable",
"go: refuses a running add-on, a stranger, an unknown backup and an invalid mapping without changing anything",
"go: refuses a backup of another trusted identity or of a newer data format",
"go: resumes or rolls back a restore that stopped at each phase, by one rule",
"go: holds the resources of one add-on and leaves another add-on alone",
"go: cancels admitted work and reports a drain that did not finish",
"go: restores grants through the account directory and the lowerings since the backup, never beyond them",
"go: keeps a bounded durable log of lowered access",
"go: keeps a revocation however many later lowerings of another person follow",
"go: restores the data but no access when the history may have lost a lowering",
"go: reads a store that is full of lowerings as one whose history may be cut",
"go: applies a lowering made after the export whatever time the backup is given",
"go: refuses a change that was authorized just before the hold began",
"go: cancels a pending proposal and leaves an executing one outcome-unknown after a restore",
"go: forgets the records of one add-on and no other",
"go: maps an owner on a restore to a local-owner store only when nothing named is in it",
"go: migrates the ownership of a stopped store with a backup and an explicit mapping and refuses a populated downgrade",
"go: records the current format of a new store and migrates nothing",
"go: migrates every database in its own transaction, records the version last and repeats as a no-op",
"go: leaves a database whose step fails exactly as it was and resumes on the next run",
"go: refuses data in a newer format, a downgrade and a version it has no path to, and writes nothing",
"go: makes a backup only for an administrator's own browser session and lists it",
"go: restores with warnings and does not give back a share that was revoked after the backup",
"go: restores only a backup of the add-on in the route and touches nothing otherwise",
"go: gives a forwarding frontend the same typed answers as the owner",
"go: purges only with the typed ID, a stopped add-on and an explicit scope, and touches nothing else",
"go: is never reachable by a model: no tool, no declared name and no route for an API key",
"go: upgrades an add-on with data through a backup and a migration and keeps its databases",
"go: undoes an upgrade whose package does not start and runs the old generation on its own data",
"go: hands retained data only to the same trusted source on a reinstall",
"go: documents every route and every emitted field in the Swagger spec, the instructions and the feature registry",
"recovery: an administrator backs up from the manage sheet and the backup is listed as verified",
"recovery: a person and a key cannot back up, restore or purge, and only the owner session of an administrator can",
"recovery: the restore dialog warns, asks for the typed ID and a restore does not give back a revoked share",
"recovery: a second backup, the sole recovery copy is kept and the keyboard reaches every action",
"recovery: the page shows a needs-recovery banner with restore and purge as the actions (status mocked)",
"recovery: a purge needs a scope, the typed ID and a stopped add-on, and removes the data and its shares"
]
},
"packaging": {
"kind": "shell",
"commands": [
[
"sh",
"scripts/addons/package_test.sh"
]
],
"cases": [
"go: joins every enabled platform leg into one verified index",
"go: never creates a partial index when an enabled platform has no leg",
"go: refuses duplicate legs, local-check legs, other versions and extra platforms",
"go: refuses a merged layout that lost a platform after the merge",
"go: builds a deterministic platform layout with executable, ui and manifest layers",
"go: restores the validated executable mode on extraction",
"go: refuses a platform that the matrix has not enabled unless it is a local check",
"go: refuses an invalid version, an existing layout and an empty executable",
"go: rejects a package without its entrypoint",
"go: rejects a declared UI whose layer or files are missing",
"go: rejects a package without a required runtime library",
"go: rejects a manifest whose platform differs from the image",
"go: rejects an image config or annotation of another platform",
"go: rejects a manifest version that differs from the release version",
"go: rejects another artifact type",
"go: rejects unexpected layers, roles and layer media types",
"go: rejects an unexpected file in the executable layer",
"go: rejects a blob whose bytes differ from its digest",
"go: rejects a receipt that does not match the image",
"go: rejects invalid extraction permissions",
"go: rejects a UI file that is executable or outside the declared directory",
"go: rejects traversal paths, links and duplicates",
"go: rejects a UI that bundles its own React runtime",
"go: rejects an icon that is not an image of its type",
"go: rejects an invalid platform layout marker or index",
"go: moves development forward and leaves it alone for an older commit",
"go: accepts a diverged branch head and refuses one commit with two contents",
"go: moves latest only to a newer stable version",
"go: refuses reserved or foreign alias names and unpublished digests, leaving aliases unchanged",
"go: promotes a branch channel under its hashed name",
"go: treats a force-pushed branch as the new truth for a push to the same ref",
"go: blocks the alias for anything but a push to the channel's own ref",
"go: refuses development when its commit is unreachable, even for a push",
"go: fails on any git error that is not a plain not-ancestor answer",
"go: tells an unreachable commit from a plain not-ancestor",
"go: accepts the add-on namespace and refuses every other go-skynet repository",
"go: reads a YAML list and refuses JSON, unknown fields and a second document",
"go: refuses missing and backend repositories before any request",
"go: pushes platform digests then the index, and a retry is digest-identical",
"go: rejects overwriting an immutable version with different content",
"go: adopts published content only for the same version and commit",
"go: refuses reserved aliases and mismatched tags as immutable tags",
"go: publishes nothing from a partial or local-check layout",
"go: fails closed when no platform is enabled, the file is absent or empty",
"go: rejects enabled platforms without a native runner or check, duplicates and unknown fields",
"go: prints the enabled platforms with their native runners",
"go: ships the checked-in matrix with every platform disabled until its native check passes",
"go: renders digest-pinned entries with an explicit add-on signer identity",
"go: renders an entry for every first-party add-on from its own template",
"go: refuses missing inputs, backend repositories, bad channels and unknown placeholders",
"go: carries placeholders only: no fabricated URL, registry or namespace",
"go: never publishes from a pull request, whatever the ref",
"go: maps master alone to development and publishes the commit tag",
"go: never publishes from a branch push, whatever the branch is named",
"go: keeps reserved names out of the branch namespace",
"go: separates refs that normalize to the same label",
"go: bounds empty, Unicode and very long branch names",
"go: lets a tag push prepare the immutable version and never move latest",
"go: promotes latest only for a published, stable, non-draft release",
"go: rejects unknown events and a malformed commit",
"go: prints the decision as key=value lines",
"go: accepts the checked-in workflow",
"go: rejects pull_request_target",
"go: rejects secrets in a pull request validation job",
"go: rejects id-token write outside the publishing job",
"go: rejects a registry login or publish in an untrusted job",
"go: rejects publish that does not wait for every platform leg",
"go: rejects publish that can run after a failed leg",
"go: rejects publish that does not need validate",
"go: rejects a package leg that does not need validate",
"go: rejects a validate job that cannot stop the release",
"go: rejects a package or promote job that runs after a failed validate",
"go: keeps validate unprivileged on every event",
"go: rejects promotion that does not wait for signing",
"go: rejects alias promotion before signing",
"go: rejects an alias command inside the publishing job",
"go: rejects a literal latest tag",
"go: rejects backend registries and backend workflows",
"go: rejects a signer identity that is a pattern or the backend workflow",
"go: rejects signing by tag or without referrers and the new bundle format",
"go: rejects missing serialization per channel",
"go: rejects publication that is shared between add-ons",
"go: rejects a workflow that names one add-on by path or skips an add-on in the matrix",
"go: rejects a plan that does not refuse an add-on without an enabled platform",
"go: rejects a plan that does not fail closed on missing configuration",
"go: rejects a plan that does not exit 1 for an add-on without an enabled platform on a publishing event",
"go: rejects a plan that treats any matrix error as no legs",
"go: rejects a repository rule that does not keep the configured repository for tables",
"go: rejects a publish or promote matrix that stops the other add-ons on a failure",
"go: rejects a publish job that downloads the layouts of other add-ons",
"go: rejects a promote job that does not check the digest format",
"go: derives a repository that the add-on tools accept for every add-on from the documented variable",
"go: fails on a publishing event when an add-on has no enabled platform",
"go: publishes when every add-on has an enabled platform",
"go: gives an add-on without an enabled platform no legs on an event that publishes nothing",
"go: fails on a missing or malformed platform file on every event",
"go: rejects a checkout of the pull request head or a persisted token",
"go: rejects write permission at workflow level and a literal platform matrix",
"go: rejects a publishing job without an environment or a gate",
"go: does not trust the backend workflow identity in the documented verification",
"go: installs the package built by package.sh and starts its executable",
"go: is refused when the signature carries another workflow identity",
"go: is refused when the owner policy names the backend workflow",
"go: is refused when the pinned digest is not the published image",
"go: gives identical digests for two builds of the same inputs",
"go: refuses a platform the matrix does not enable and a missing executable of another platform",
"package.sh builds and verifies a local check layout",
"package.sh refuses a platform the matrix has not enabled",
"package.sh refuses an existing non-empty layout",
"package.sh requires its arguments",
"package.sh refuses an invalid version",
"package.sh builds and verifies the voice add-on for the host",
"package.sh refuses a foreign platform without an executable: tables",
"package.sh refuses a foreign platform without an executable: voice",
"package.sh refuses a foreign platform without an executable: face",
"package.sh refuses a foreign platform without an executable: fine-tuning",
"package.sh refuses a foreign platform without an executable: quantization",
"package.sh refuses a foreign platform without an executable: studio",
"package.sh refuses a foreign platform without an executable: talk",
"package.sh refuses a foreign platform without an executable: telegram",
"package.sh refuses a foreign platform without an executable: slack",
"package.sh refuses a foreign platform without an executable for every add-on",
"package.sh builds Tables with cgo and the pure Go add-ons without",
"matrix fails closed while no platform is enabled",
"matrix fails closed without a file",
"channel.sh: a pull request never publishes",
"channel.sh: master publishes development",
"channel.sh: a branch push never publishes, even a branch named latest",
"channel.sh: a tag push prepares the version and moves no alias",
"channel.sh: a published stable release promotes latest",
"channel.sh: a pre-release never promotes latest",
"channel.sh: a draft release fails",
"channel.sh: an unknown event fails",
"channel.sh: a tag that is not a version fails",
"workflow policy accepts the checked-in workflow",
"workflow policy rejects pull_request_target",
"workflow policy rejects a publish job that does not wait for every leg",
"workflow policy rejects a validate job that cannot stop the release",
"scripts never push, tag, sign or log in",
"packaging files never reference backend registries or workflows"
]
},
"updates": {
"kind": "shell",
"commands": [
[
"sh",
"scripts/addons/updates.sh"
]
],
"cases": [
"unit: updates: a failed, unknown or unreadable check is never current",
"unit: updates: an upgrade is offered only for a candidate the owner confirmed, with a digest to pin",
"unit: updates: the owner's typed refusals keep their type and are final answers",
"unit: updates: the apps list marks an update beside the process state, never in place of it",
"unit: updates: times are shown as the reader's own and a bad time as nothing",
"unit: updates: the client sends check and upgrade as the administrator's own action and types the refusals",
"unit: updates: every locale carries the same update keys as English, and words for every state, reason and refusal",
"go: offers a digest-only change of the branch-fix-cache channel with an identical version label",
"go: offers a digest-only change of the development channel with an identical version label",
"go: offers a digest-only change of the latest channel with an identical version label",
"go: is up to date when the channel resolves to the installed digest",
"go: never switches the channel: another channel and other versions are not offered",
"go: selects the highest compatible greater version of the same major",
"go: does not cross a major version",
"go: does not move a stable install to a pre-release and orders pre-releases below their release",
"go: treats a lower version as nothing to offer",
"go: reports the same digest as up to date",
"go: reports a rewritten immutable version as an integrity error, never an update",
"go: never reports an update it cannot pin to a digest",
"go: offers the build the tag names now when it moved, pinned to its digest",
"go: is up to date when the tag still names the installed build",
"go: resolves the tag only on an explicit check, and the status read reuses that answer",
"go: reports a tag that cannot be resolved as check-failed, never as an update",
"go: resolves the tag again at execution, so the upgrade pins what the tag names then",
"go: names the host, SDK and data format ranges a candidate does not fit",
"go: refuses a candidate whose data format ends below the installed one",
"go: reports a platform that is not offered, and prefers the compatible version over a newer incompatible one",
"go: does not check the SDK range of a candidate that declares no UI",
"go: reports a failed library as check-failed with the last success, never as up to date",
"go: names an unavailable source credential and an unreachable library by class",
"go: reports an add-on the library no longer lists as check-failed",
"go: returns an error for an add-on that is not installed and for a canceled caller",
"go: answers a status read from the cache and never evaluates or fetches",
"go: serves a fresh answer from the cache and evaluates again when it is stale",
"go: marks a cached answer older than the time to live as stale",
"go: refreshes the library only on an explicit refresh and applies nothing",
"go: limits explicit refreshes to one per interval and says so",
"go: shares one check among concurrent callers",
"go: never lets an explicit refresh join a plain evaluation that is already in flight",
"go: keeps the work of a canceled caller from spoiling the answer of the others",
"go: bounds the cache and forgets the answer of a replaced package",
"go: redacts the library, channel and digests for a caller who is not an administrator",
"go: keeps the compatibility hint of an entry and refuses a malformed range",
"go: lists the releases of one add-on for every platform, from the cache, and refuses a failed library",
"go: names an unavailable credential reference as a credential failure inside the refresh failure",
"go: reports a digest-only change of a moving channel, applies nothing and offers the pinned upgrade",
"go: refuses a second operation ID for the same transition, in flight or done, and applies it once",
"go: runs concurrent requests with one operation ID once and gives each the same answer",
"go: serializes conflicting upgrades by the installed digest and refuses the loser without a record",
"go: refuses a candidate that is not the one the library resolves now",
"go: refuses an upgrade to the digest that is already installed",
"go: rechecks compatibility at execution and refuses an incompatible candidate",
"go: selects a newer immutable version and treats a rewritten version as an integrity error",
"go: keeps the last good generation when the candidate cannot be staged",
"go: never switches the library or channel, and a failed check is never up to date",
"go: lets an administrator refresh and everyone with the feature read a redacted status",
"go: shows the pending update in the apps list from the cache only",
"go: does not accept pins without an update checker or on another action",
"go: keeps the unpinned typed upgrade of an earlier release working",
"go: is offered when the tag moved, pinned to the build the tag names, and upgrades to exactly that build",
"go: refuses the upgrade when the tag moved again after the check, and installs nothing",
"go: gives every caller with the feature the same status from every frontend, redacted for non-administrators",
"go: checks only for an administrator's own browser session, and applies nothing",
"go: upgrades only to the checked candidate, with the same typed refusals from every frontend, and never twice",
"go: runs two concurrent upgrades from two frontends once: the same ID shares the answer, another ID is a conflict",
"go: refuses an incompatible candidate and a library that cannot be read, with a typed answer",
"go: reports a lost upgrade as an unknown outcome with its original operation, and a lost status read or check as plainly unavailable",
"go: keeps the update actions out of the tools and names every field of the status in the Swagger spec",
"updates: a library with nothing newer is up to date, and a member sees no update mark",
"updates: a moved channel with the same version label is an update, in the list and as a pending mark",
"updates: a member, a key and an outsider cannot check or upgrade",
"updates: the dialog names the library, versions and digests, a cancel sends nothing, and the upgrade backs up and keeps the data",
"updates: two requests for the same transition under different operations run it once",
"updates: a page that is behind cannot upgrade over a newer installed package",
"updates: a candidate this host cannot run shows its reason and has no upgrade",
"updates: an unreachable library is a failed check, never up to date, and says when it was last read",
"updates: on a narrow screen the check is reachable and runs from the keyboard",
"go: ends the checks in flight when it is closed and refuses new ones",
"go: always names the candidate digest of an update, so the upgrade has something to pin",
"go: keeps a stale cached notice readable while a plain check says the update is gone"
]
},
"tables-acceptance": {
"kind": "shell",
"commands": [
[
"sh",
"scripts/addons/tables_acceptance.sh"
]
],
"cases": [
"go: reports an update only on a check, shows a member no digest, refuses a key and applies one pinned candidate with the data and grants kept",
"go: refuses a change prepared on an old schema or data revision from two tabs of two people and applies nothing",
"go: replays an operation ID as one receipt from every node, conflicts on a different request and never applies twice or under a new ID",
"go: settles a revocation that races a confirmation: one outcome, applied at most once, and no work after the revocation",
"go: separates owner, editor, viewer, administrator and stranger across the browser routes, the REST routes and the chat tool consumer",
"go: derives the action of a proposal from the tool kind, so an editor cannot confirm a schema change as a write",
"go: serves the browser module to every account with the feature and to nobody else, from the owner and each frontend",
"go: fails every blocked consumer explicitly and never serves add-on tools to it",
"go: is the administrator's own action on every node and never a key's, a member's or a tool's",
"go: refuses a corrupt backup and a restore that is not allowed, and leaves the data as it was",
"go: restores a verified backup: the data goes back, the add-on starts again and access follows the current accounts",
"go: denies the open tabs of a disabled add-on everywhere and serves them again, with the same data, when it is enabled",
"go: keeps data and grants when the add-on is removed and installed again, and refuses what the old generation prepared",
"go: denies the next call of a paused key on every node and accepts it again when resumed",
"go: denies the browser, the key and the chat everywhere when the add-ons feature is withdrawn",
"go: lowers an editor to a viewer for the next call everywhere and drops the proposals the editor still held",
"go: refuses the session and the key of a disabled account on every node",
"go: ignores actor, forwarding and authority headers and fields on every node",
"go: denies authority, role and approval fields in the arguments of every consumer and creates nothing",
"go: applies a proposal only on the confirmation of the proposer's own tab, with its digest, exactly once",
"go: keeps every acknowledged change and applies no change twice when the Tables process is killed in the middle of a batch",
"go: keeps every acknowledged change and applies no change twice when the owner is killed in the middle of a batch and restarted",
"go: blocks every other write while a confirmation is unresolved, keeps reading, and accepts writes again only after the owner role resolves it",
"go: fails every response type closed with the same typed answer from both frontends, runs nothing there and serves everything again after the restart",
"go: exports a CSV through a frontend and serves the same bytes from every node to its requester only",
"go: stops the downloads of a person whose access to the database was revoked, on every node, and keeps the owner's",
"go: denies downloads while the add-on is disabled and serves a complete file again when it is enabled",
"go: answers the refusal as invalid_request with status 400 on every route and node and changes nothing",
"go: does not consume the operation ID of a refused change",
"go: denies an expired file identically from every node and leaves the data and the backups untouched",
"go: withdraws a transfer held in flight when the add-on is disabled and leaves no downloadable file",
"go: reports a change that committed and lost its answer as unknown, finds it by receipt and replays the same receipt once",
"tables-acceptance: a member opens the databases and a grid through each non-owner frontend and the module comes from the owner by digest",
"tables-acceptance: deep links keep the proxy path prefix on a non-owner frontend and survive a reload",
"tables-acceptance: the grid works by keyboard, at 400 pixels and in both themes on a non-owner frontend",
"tables-acceptance: the page says it is unavailable while the owner is gone and recovers on reload when it is back",
"manifest: the evidence manifest names the platform, the commands, the package digests and every case"
]
},
"library-sources": {
"kind": "shell",
"commands": [
[
"sh",
"scripts/addons/library_ui.sh"
]
],
"cases": [
"each page lists only its own kind, with a Default badge and no kind filter",
"adds a model source of your own, which has no Default badge and stays after a reload",
"turns a default off and removes it: it stays listed as removed, and restoring brings it back",
"shows the conflict message the store gives next to the source that clashes",
"turning it off hides the default galleries and shows the defaults as off, and on brings them back"
]
}
}