Description
What
The multi-org branch of App.run() is dead code as far as the test suite is concerned. coverage run --source=sf2loki -m pytest tests/ over the full suite (1045 passed, 1 skipped) reports src/sf2loki/app.py at 96% with 1152-1156 and 669 among the missed lines:
src/sf2loki/app.py:1152—await self._probe_orgs()src/sf2loki/app.py:1156—self._pipeline.set_static_labels(deployment_static_labels(self._cfg.sink.loki.labels))src/sf2loki/app.py:669— thereturninsidedeployment_static_labels(defined atsrc/sf2loki/app.py:660)
No test reaches them:
rg -n "deployment_static_labels" tests/returns nothing. The function has zero unit tests and its only call site is never executed.rg -n "\.run\(\)" tests/returns exactly three sites —tests/test_app_integration.py:142,:456,:487— and all three build a single-org config, so all three take theif not self._multi_orgbranch atsrc/sf2loki/app.py:1131.tests/test_multiorg_app.pycallsappn._probe_orgs()directly (:151,:163) and otherwise only assertsApp.buildwiring. It never drivesApp.run().tests/test_static_labels.pycovers only the single-orgbuild_static_labels(src/sf2loki/app.py:117), and both of its tests assertlabels["sf_org_id"]is present — the opposite of the multi-org invariant.rg -n "set_static_labels" tests/hits onlytests/test_pipeline.py:132and:421, which pass hand-written dicts to the pipeline setter and exercise neither app-level builder.
The invariant the branch encodes: in multi-org mode sf_org_id, environment and org are injected per entry by each org’s OrgSource (src/sf2loki/sources/org_adapter.py), so the shared pipeline must carry only job/service_name plus the operator’s sink.loki.labels. Nothing in the suite pins that composition.
Why it matters
Static labels take precedence over per-entry labels. src/sf2loki/app.py:305-306 merges them as:
if self._static_labels:
entry.labels = {**entry.labels, **self._static_labels}
Two silent-regression paths follow, both of which keep the suite green:
- Cross-org label collapse. A refactor that made multi-org mode set
sf_org_id/environmentstatically would override the per-org valuesOrgSourceinjects, stamping every org’s entries with one org’s identity. Loki bakes labels into streams at ingest, so the misattribution is permanent and not correctable at query time. - Startup crash on every multi-org deployment. A
Configbuilt withorgs:leavessalesforceasNone(verified: constructingtests/test_multiorg_app.py::_multi_cfg()yieldscfg.salesforce is None). Theassert self._cfg.salesforce is not Noneguard atsrc/sf2loki/app.py:1137sits inside the single-org branch only, so a collapsed branch callingbuild_static_labels(environment=self._cfg.salesforce.environment, ...)raisesAttributeErrorbefore readiness on every multi-org start.
Multi-org ingestion (#31) is a shipped feature whose entire run()-level startup sequence — org probe wiring plus deployment-wide label selection — has no end-to-end execution in CI. Any future restructuring of run() is validated for single-org only.
Proposed approach
Add a run()-level multi-org test to tests/test_multiorg_app.py, reusing the fake-collaborator pattern already established in tests/test_app_integration.py:420-500 (replace appn._pipeline, appn._coordinator after App.build):
- Build the app from the existing
_multi_cfg()helper, withservice={"health_addr": "127.0.0.1:0"}so the health server binds an ephemeral port, andsink={"loki": {..., "labels": {"environment": "prod-eu"}}}in a second case to pin operator-label merging. - Replace
appn._orgswith two_OrgAuthentries backed by the existing_OkTokensstand-in so the probe succeeds for both, and record which orgs were probed. - Replace
appn._pipelinewith a fake that capturesset_static_labelsand whoserun()returns immediately (sources exhausted), so_on_pipeline_donesets the global stop andrun()returns. - Set
appn._coordinator = NoopCoordinator()(from sf2loki.coordinate.base import NoopCoordinator). await asyncio.wait_for(appn.run(), timeout=5), withawait appn._health.stop()in afinally.- Assert the captured static labels are exactly
{"job": "sf2loki", "service_name": "sf2loki", **operator_labels}— withsf_org_idandorgabsent, andenvironmentabsent unless supplied bysink.loki.labels— and that both orgs were probed.
Also add direct unit tests for deployment_static_labels (src/sf2loki/app.py:660) in tests/test_static_labels.py, alongside the existing build_static_labels tests: the default set, operator-label override of service_name, and explicit assertions that sf_org_id and org are never present.
An assertion that deployment_static_labels produces no key in {"sf_org_id", "org", "environment"} by default is the guard that catches path 1 above; the run()-level test is the guard that catches path 2.
Imported from GitHub issue #140 on 2026-08-14, when this repo migrated from GitHub Issues to Backlog.md. The original issue has been deleted; its verbatim body, labels and comments are preserved in archive/issues-dump.json (jq '.[] | select(.number == 140)' archive/issues-dump.json).
Filed from the 2026-07-30 full-repo audit (11 finder lanes + adversarial verification per finding).
Acceptance Criteria
- #1
tests/test_static_labels.pyunit-testsdeployment_static_labels: default set equals{"job": "sf2loki", "service_name": "sf2loki"}; operatorsink.loki.labelsmerge last and win;sf_org_idandorgare asserted absent from the default set. - #2
tests/test_multiorg_app.pydrivesawait App.run()with a two-org config through the multi-org branch, asserting the pipeline’s static labels carry nosf_org_id/organd that both orgs were probed. - #3 A second case pins that operator
sink.loki.labels(e.g.environment) still reach the pipeline in multi-org mode. - #4 Coverage of
src/sf2loki/app.pyno longer lists669or1152-1156as missed (coverage run --source=sf2loki -m pytest tests/ && coverage report -m --include='*sf2loki/app.py'). - #5 Mutating
src/sf2loki/app.py:1156to callbuild_static_labelsinstead fails the new tests rather than raising an unrelatedAttributeErroronly at runtime. - #6
just gategreen.
Definition of Done
- #1 just gate is green (ruff check + ruff format –check + mypy src + pytest) — run it, don’t assert it
- #2 just gen-config run and its output committed, if config.py changed (CI drift gate fails otherwise)
- #3 committed straight to main with a conventional-commit message, and pushed