feat: enhance session completeness tracking in s3_analyzer and seismo_lab

This commit is contained in:
serversdwn
2026-03-11 18:48:42 -04:00
parent 41606d2f31
commit 99d66453fe
3 changed files with 36 additions and 32 deletions

View File

@@ -140,6 +140,15 @@ class Session:
index: int
bw_frames: list[AnnotatedFrame]
s3_frames: list[AnnotatedFrame]
# None = infer from SUB 0x74 presence; True/False = explicitly set by splitter
complete: Optional[bool] = None
def is_complete(self) -> bool:
"""A session is complete if explicitly marked, or if it contains SUB 0x74."""
if self.complete is not None:
return self.complete
return any(af.header is not None and af.header.sub == SESSION_CLOSE_SUB
for af in self.bw_frames)
@property
def all_frames(self) -> list[AnnotatedFrame]:
@@ -384,6 +393,7 @@ def split_sessions_at_marks(
session_offset = 0
bw_prev = s3_prev = 0
n_segments = len(bw_cuts)
for seg_i, (bw_end, s3_end) in enumerate(zip(bw_cuts, s3_cuts)):
bw_chunk = bw_blob[bw_prev:bw_end]
s3_chunk = s3_blob[s3_prev:s3_end]
@@ -394,11 +404,20 @@ def split_sessions_at_marks(
seg_sessions = split_into_sessions(bw_frames, s3_frames)
# A mark-bounded segment is complete by definition — the user placed the
# mark after the read finished. Only the last segment (trailing, unbounded)
# may be genuinely in-progress.
is_last_segment = (seg_i == n_segments - 1)
# Re-index sessions so they are globally unique
for sess in seg_sessions:
sess.index = session_offset
for f in sess.all_frames:
f.session_idx = session_offset
# Explicitly mark completeness: mark-bounded segments are complete;
# the trailing segment falls back to 0x74 inference.
if not is_last_segment:
sess.complete = True
session_offset += 1
all_sessions.append(sess)
@@ -683,11 +702,7 @@ def render_session_report(
n_bw = len(session.bw_frames)
n_s3 = len(session.s3_frames)
total = n_bw + n_s3
is_complete = any(
af.header is not None and af.header.sub == SESSION_CLOSE_SUB
for af in session.bw_frames
)
status = "" if is_complete else " [IN PROGRESS]"
status = "" if session.is_complete() else " [IN PROGRESS]"
lines.append(f"{'='*72}")
lines.append(f"SESSION {session.index}{status}")
@@ -847,11 +862,7 @@ def render_claude_export(
lines += ["## Capture Summary", ""]
lines.append(f"Sessions found: {len(sessions)}")
for sess in sessions:
is_complete = any(
af.header is not None and af.header.sub == SESSION_CLOSE_SUB
for af in sess.bw_frames
)
status = "complete" if is_complete else "partial/in-progress"
status = "complete" if sess.is_complete() else "partial/in-progress"
n_bw, n_s3 = len(sess.bw_frames), len(sess.s3_frames)
changed = len(diffs[sess.index] or []) if sess.index < len(diffs) else 0
changed_str = f" ({changed} SUBs changed vs prev)" if sess.index > 0 else " (baseline)"
@@ -1119,14 +1130,7 @@ def live_loop(
# Check for session close
all_sessions = split_into_sessions(bw_annotated, s3_annotated)
# A complete session has the closing 0x74
complete_sessions = [
s for s in all_sessions
if any(
af.header is not None and af.header.sub == SESSION_CLOSE_SUB
for af in s.bw_frames
)
]
complete_sessions = [s for s in all_sessions if s.is_complete()]
# Emit reports for newly completed sessions
for sess in complete_sessions[len(sessions):]:
@@ -1157,13 +1161,7 @@ def live_loop(
s3_annotated = annotate_frames(s3_frames_raw, "S3")
bw_annotated = annotate_frames(bw_frames_raw, "BW")
all_sessions = split_into_sessions(bw_annotated, s3_annotated)
incomplete = [
s for s in all_sessions
if not any(
af.header is not None and af.header.sub == SESSION_CLOSE_SUB
for af in s.bw_frames
)
]
incomplete = [s for s in all_sessions if not s.is_complete()]
for sess in incomplete:
report = render_session_report(sess, diffs=None, prev_session_index=None)
out_path = write_report(sess, report, outdir)