fix: optional Table.ownership and explicit provider timeouts - #1162
Conversation
Two independent hardening fixes, both the "one missing thing breaks everything" shape. `Table.ownership` was required, and `server/tables.py` splats each raw dict straight into `Table(**t)` — so a Tables app that stops emitting the key fails the *entire* nc_tables_list_tables call, not just one row. Exactly the failure mode `owner_display_name` had in #728, on the field right above it. Nothing in this codebase reads `ownership`, so making it Optional costs nothing. `TableSchema.columns`/`views` get a default_factory for the same reason: an empty table has no views, and a response omitting either list should degrade to an empty list rather than failing. `AnthropicProvider` and `BedrockProvider` pinned no timeout, so they inherited their SDK defaults: 600s for the Anthropic SDK, and 60s read with 3 retries for botocore. Both are long enough that a wedged endpoint reads as a hang rather than a failure. Both now use the 120s read / 5s connect the other providers already use (ollama.py, openai.py), exposed as class constants so the tests assert against the convention rather than a duplicated literal. Mistral is deliberately untouched — #864 already covers it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|
Claude finished @cbcoutinho's task in 1m 49s —— View job Claude finished reviewing
Note: SummaryTwo small, well-isolated hardening fixes. Both are backward-compatible relaxations (required → optional / default-factory), not breaking changes, so no
|



Two independent hardening fixes, both the same "one missing thing breaks
everything" shape.
1.
Table.ownershipfailed the whole listingserver/tables.pysplats each raw dict straight in:So a required
ownershipmeans a Tables app that stops emitting the key failsthe entire
nc_tables_list_tablescall — not one row, all of them. That isprecisely the failure mode
owner_display_namehad in #728, on the fielddirectly above it; only that one got fixed at the time.
Nothing in this codebase reads
ownership(grep only finds an unrelatedbuild_ownership_filterinsearch/), soOptional[str] = Nonecosts nothing.TableSchema.columns/viewsget adefault_factoryfor the same reason — anempty table has no views, and a response omitting either list should degrade to
an empty list rather than failing.
2. Two providers inherited very long SDK default timeouts
AnthropicProviderBedrockProviderollama/openaiBoth defaults are long enough that a wedged endpoint reads as a hang rather
than a failure. The values are class constants so the tests assert against the
convention rather than a duplicated literal, and both constructors still accept
an explicit override.
Bedrock needed
botocore.config.Configrather than an httpx timeout — retriesare left at botocore's default, since Bedrock throttling is expected and handled
upstream.
Deliberately not included
Mistral.
providers/mistral.pyhas the same gap, but #864 already coversit — I found that PR while surveying and left it alone rather than duplicating
someone else's open work.
Test coverage
Tableconstructs with neitherownershipnorowner_display_nameTableSchemaconstructs with neithercolumnsnorviewstests/unit/providers/test_provider_timeouts.py: each provider pins theconvention values, and Anthropic honours an explicitly supplied timeout
Tiers executed locally:
pytest -m unit✅ 2713 passed (CI's exact selection).Contract (Pact): not applicable — provider verification covers only
/api/v1/*, which imports neithermodels/tables.pynorproviders/.Provenance
Table.ownershipwas reported downstream onitsablabla/nextcloud-mcp-server(they fixed the sibling field). That fork's author has not signed the CLA, so no
fork code was copied — the gap was re-verified here and the fix written from
scratch.
This PR was generated with the help of AI, and reviewed by a Human