You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The Form-duality contract introduced by #1822 promises that a knowledge database's configuration is validated against the form its ingestor announced. Validation of declared fields works, but fields the ingestor never declared pass straight through and are persisted, so a mistyped knob is accepted, stored and silently ignored at ingestion time. Found while end-to-end verifying #1841.
Current behaviour:POST /knowledge/databases/{database} accepts a configuration containing keys no announced form element declares, and writes them verbatim into BucketEntity.configuration. IngestorConfig sets extra="allow" (packages/core/swiss_ai_hub/core/ingestors/ingestor_config.py:28), so the model built by ModelCreationService.create_config_model and checked by InstanceConfigHelper.validate_config_for_create (packages/api/swiss_ai_hub/api/routes/knowledge/knowledge_service.py:455-457) retains unrecognised fields rather than rejecting them.
Required fields are still caught — a typo that omitsllm_model correctly fails with llm_model: Field required. The gap is optional knobs: the three enrichment flags, vision_model, and any optional field a custom pipeline declares.
Expected behaviour: a configuration carrying a field the ingestor's announced form does not declare is rejected with a 400 naming that field, matching #1822's acceptance criterion.
Repro:
Create a database with a typo on an optional flag and an optional model:
POST /api/v1/{tenant}/knowledge/databases/kbtypo
{"ingestor":"document_ingestion","configuration":{
"name":{"en":"Typo"},"description":{"en":"d"},
"llm_model":"text-generation/Kimi-K2.6","embedding_model":"embedding/bge-m3",
"with_table_refinemnt":false, "vision_modl":"text-generation/MinerU2.5-2509-1.2B"}}
Observed: HTTP 200, and the row stores both misspelled keys.
The pipeline then resolves the defaults for the fields the user meant to set:
user typed with_table_refinemnt=false -> actual with_table_refinement = True
user typed vision_modl=MinerU... -> actual vision model = text-generation/Kimi-K2.6
The user believes they disabled an expensive enrichment step and chose a vision model; neither took effect, and the stored configuration looks deliberate. The same permissiveness lets one ingestor's knobs be submitted to another (crawl_depth from a custom ingestor is accepted by document_ingestion), weakening the per-ingestor isolation #1822 claims.
In scope
Reject a knowledge-database configuration that carries fields the database's ingestor did not announce, with a 400 naming the offending field.
Keep the existing behaviour for rows already stored: a database created before this fix, or whose pipeline has since dropped a field, must keep resolving and ingesting unchanged.
Out of scope
The same extra="allow" on AgentConfig (packages/core/swiss_ai_hub/core/agents/agent_config.py:98), which likely lets agent instances accept undeclared config keys too. The Form stack is shared, so a fix here may generalise — but the agent/process surface needs its own verification and issue rather than being changed blind.
The Form-duality contract introduced by #1822 promises that a knowledge database's
configurationis validated against the form its ingestor announced. Validation of declared fields works, but fields the ingestor never declared pass straight through and are persisted, so a mistyped knob is accepted, stored and silently ignored at ingestion time. Found while end-to-end verifying #1841.Current behaviour:
POST /knowledge/databases/{database}accepts aconfigurationcontaining keys no announced form element declares, and writes them verbatim intoBucketEntity.configuration.IngestorConfigsetsextra="allow"(packages/core/swiss_ai_hub/core/ingestors/ingestor_config.py:28), so the model built byModelCreationService.create_config_modeland checked byInstanceConfigHelper.validate_config_for_create(packages/api/swiss_ai_hub/api/routes/knowledge/knowledge_service.py:455-457) retains unrecognised fields rather than rejecting them.Required fields are still caught — a typo that omits
llm_modelcorrectly fails withllm_model: Field required. The gap is optional knobs: the three enrichment flags,vision_model, and any optional field a custom pipeline declares.Expected behaviour: a configuration carrying a field the ingestor's announced form does not declare is rejected with a 400 naming that field, matching #1822's acceptance criterion.
Repro:
HTTP 200, and the row stores both misspelled keys.The user believes they disabled an expensive enrichment step and chose a vision model; neither took effect, and the stored configuration looks deliberate. The same permissiveness lets one ingestor's knobs be submitted to another (
crawl_depthfrom a custom ingestor is accepted bydocument_ingestion), weakening the per-ingestor isolation #1822 claims.In scope
configurationthat carries fields the database's ingestor did not announce, with a 400 naming the offending field.Out of scope
extra="allow"onAgentConfig(packages/core/swiss_ai_hub/core/agents/agent_config.py:98), which likely lets agent instances accept undeclared config keys too. The Form stack is shared, so a fix here may generalise — but the agent/process surface needs its own verification and issue rather than being changed blind.configuration["embedding_model"]— see feat(rag): Retriever reads the embedding model from the knowledge database #1820 (sibling).Accepted when
make testpasses in the affected scopes.