Context
The empty-discovery warning emitted when a scanned app exposes no function builders is wrong in two places, not one. Reproduced on main (an app with no _function_builders, while another @openapi route is registered):
A function builder could not be built during discovery and was omitted from the spec:
no functions were discovered on the application object (Wrapper);
the generated spec will have empty paths
...while spec["paths"] == ['/api/decorated'].
Two false clauses:
- Back half (
bridge.py:477-478) — "the generated spec will have empty paths". False: the process-wide registry can already hold paths from other decorated apps. (Original scope of this issue.)
- Front half (
spec.py:790-792, _DISCOVERY_SKIPPED_MESSAGE) — "A function builder could not be built during discovery and was omitted from the spec". False: no builder failed to build; the app exposed zero builders. #376 reused the per-builder-failure add_discovery_warning channel for a different failure kind (app exposes nothing), so _collect_discovery_warnings prepends the builder-failure template to an app-level condition.
Fixing only the back half (as PR #384 currently does) still leaves the misleading front sentence.
Root cause
_collect_discovery_warnings (spec.py:857-864) unconditionally prepends _DISCOVERY_SKIPPED_MESSAGE to every recorded (function_name, reason). The app-level empty case (function_name is None) is semantically distinct from a builder-build failure but shares the same warning code and template.
Acceptance Checklist
Out of scope
References
Context
The empty-discovery warning emitted when a scanned app exposes no function builders is wrong in two places, not one. Reproduced on
main(an app with no_function_builders, while another@openapiroute is registered):...while
spec["paths"] == ['/api/decorated'].Two false clauses:
bridge.py:477-478) — "the generated spec will have empty paths". False: the process-wide registry can already hold paths from other decorated apps. (Original scope of this issue.)spec.py:790-792,_DISCOVERY_SKIPPED_MESSAGE) — "A function builder could not be built during discovery and was omitted from the spec". False: no builder failed to build; the app exposed zero builders.#376reused the per-builder-failureadd_discovery_warningchannel for a different failure kind (app exposes nothing), so_collect_discovery_warningsprepends the builder-failure template to an app-level condition.Fixing only the back half (as PR #384 currently does) still leaves the misleading front sentence.
Root cause
_collect_discovery_warnings(spec.py:857-864) unconditionally prepends_DISCOVERY_SKIPPED_MESSAGEto every recorded(function_name, reason). The app-level empty case (function_name is None) is semantically distinct from a builder-build failure but shares the same warning code and template.Acceptance Checklist
bridge.pyreason to claim only the observed fact — "no functions were discovered from the selected application object (<type>)" — no "empty paths" prediction.WarningCode.EMPTY_DISCOVERY(own message template) so--fail-on-warningsusers can tell the two apart; alternatively, branch_collect_discovery_warningsonfunction_name is Noneto skip the builder-failure prefix.cli.py:246,263), unchanged.iter_functionsdocstring atadapters/azure_functions.py:124-125("...so it is / empty list when...") — a sentence was dropped in the#376merge (should read roughly "...so it is skipped rather than raising. Returns an empty list when the app exposes no builders...").Out of scope
References
src/azure_functions_openapi/bridge.py:477src/azure_functions_openapi/spec.py:790-792, 857-864src/azure_functions_openapi/adapters/azure_functions.py:124-125