doberman tune reads rows with read_decisions and hands them to build_friction_report and generate_proposals in src/doberman/policy/friction.py. Since #699 the ambient monitor writes rows too, tagged source_context = "ambient:<collector_id>". Those rows were observed, never enforced, so nobody was interrupted by them.
friction.py has no filter, so ambient AUTH and BLOCK rows inflate the weekly rates and can push a proposal past min_occurrences on their own. The device-metrics rollup in storage/log.py already skips rows whose source_context starts with ambient:; the friction report should do the same.
Done when:
- rows whose
source_context starts with ambient: are dropped in one place in friction.py, so both the report and the proposals see the filter
- a test feeds five ambient AUTH rows with the same action type and path class and asserts no proposal comes out, and the rates ignore them
- a
changelog.d/<PR>.fix.md fragment
doberman tunereads rows withread_decisionsand hands them tobuild_friction_reportandgenerate_proposalsinsrc/doberman/policy/friction.py. Since #699 the ambient monitor writes rows too, taggedsource_context = "ambient:<collector_id>". Those rows were observed, never enforced, so nobody was interrupted by them.friction.pyhas no filter, so ambient AUTH and BLOCK rows inflate the weekly rates and can push a proposal pastmin_occurrenceson their own. The device-metrics rollup instorage/log.pyalready skips rows whosesource_contextstarts withambient:; the friction report should do the same.Done when:
source_contextstarts withambient:are dropped in one place infriction.py, so both the report and the proposals see the filterchangelog.d/<PR>.fix.mdfragment