Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 18 additions & 6 deletions docs/adr/0001-episode-semantics-boundaries.md
Original file line number Diff line number Diff line change
Expand Up @@ -172,12 +172,24 @@ Mutation testing confirms that disabling this guard makes the focused test
fail. This accepts event IDs as the candidate-v1 publication non-overlap unit,
not as a cross-rule or production policy.

Together, the two fixtures and focused tie/shared-evidence controls accept the
recovery, null-control, deterministic tie-break, and publication
single-consumption hypotheses for their bounded cases only. Background and
alert-volume calibration plus a production complexity design still require
independent evidence. `Detector::analyze()` and `loglens.report.v3` remain
unchanged.
A focused uniform-background alert-volume control uses events exactly 150
seconds apart with threshold five and the inclusive 600-second window. Thirteen
events remain one activity segment and produce one selected candidate. Adding a
fourteenth equally spaced event still leaves one baseline segment but makes
candidate v1 select `line:1` through `line:5` and `line:10` through `line:14`.
There is no density contrast or peak prominence separating these windows. This
falsifies the hypothesis that candidate episode multiplication by itself proves
multiple dense peaks. It blocks production adoption without a calibrated
density-contrast rule or an explicit alert-volume budget; it does not estimate
a real-world false-positive rate.

Together, the two fixtures and focused tie/shared-evidence/background controls
accept the recovery, null-control, deterministic tie-break, and publication
single-consumption hypotheses for their bounded cases. The background control
also resolves one qualitative safety decision: candidate v1 must not move into
production unchanged. Quantitative alert-volume calibration and a production
complexity design still require independent evidence. `Detector::analyze()` and
`loglens.report.v3` remain unchanged.

## Alternatives considered

Expand Down
24 changes: 24 additions & 0 deletions tests/test_episode_candidate_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
sys.path.insert(0, str(REPO_ROOT))

from scripts.episode_candidate_core import ( # noqa: E402
activity_segments,
enumerate_candidate_windows,
select_window_separated_candidates,
)
Expand Down Expand Up @@ -84,6 +85,29 @@ def test_shared_evidence_is_search_membership_not_double_consumption(self) -> No
self.assertEqual(materialized_event_ids, [f"line:{i}" for i in range(1, 7)])
self.assertEqual(len(materialized_event_ids), len(set(materialized_event_ids)))

def test_uniform_threshold_rate_can_multiply_episodes_in_one_segment(self) -> None:
thirteen_events = make_events([150 * offset for offset in range(13)])
fourteen_events = make_events([150 * offset for offset in range(14)])
thirteen_selected = select_window_separated_candidates(
enumerate_candidate_windows(thirteen_events, 5, 600), 600
)
fourteen_selected = select_window_separated_candidates(
enumerate_candidate_windows(fourteen_events, 5, 600), 600
)

self.assertEqual(len(activity_segments(fourteen_events, 600)), 1)
self.assertEqual(
[candidate.event_ids for candidate in thirteen_selected],
[tuple(f"line:{i}" for i in range(1, 6))],
)
self.assertEqual(
[candidate.event_ids for candidate in fourteen_selected],
[
tuple(f"line:{i}" for i in range(1, 6)),
tuple(f"line:{i}" for i in range(10, 15)),
],
)

def test_equal_score_windows_prefer_chronological_key(self) -> None:
candidates = enumerate_candidate_windows(
make_events([0, 1, 2, 3, 600, 601]), 5, 600
Expand Down
Loading