diff --git a/README.md b/README.md index 14bae7a2..f532e69a 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,8 @@ capture path for every device. - **Plugins** — drop in a `plugin.json` + worker executable (C++ or Python SDK) - **Sim** — develop and demo without hardware - **LSL bridge** — record any Lab Streaming Layer outlet with zero vendor code -- **Analysis** — QC, features, pose/kinematics, ML bundle jobs on sealed packages +- **Analysis** — QC, features, pose/kinematics, ML bundle jobs on sealed packages; + reopen saved results with their parameters, logs and output inventory ## Architecture (sketch) @@ -58,6 +59,11 @@ existing output directory, and preserves failure output for diagnosis. It does not establish hardware performance, clinical validity, or full product readiness. Tests: `tests/analysis/test_offline_demo.py`. +To inspect that saved job in the desktop, select its `.mmsession` package in +**Analysis**, choose `demo-qc` under **Saved analysis**, then **Open saved result**. +The [operator guide](docs/operator/README.md#open-saved-analysis) describes the +gallery, inspector and read-only result details. + ## Simulation walkthrough (after build prerequisites) ```powershell diff --git a/desktop/capture_desktop/analysis_history.py b/desktop/capture_desktop/analysis_history.py new file mode 100644 index 00000000..1b8fd23a --- /dev/null +++ b/desktop/capture_desktop/analysis_history.py @@ -0,0 +1,164 @@ +# SPDX-License-Identifier: GPL-3.0-only +"""Read saved analysis jobs from the selected package without changing them.""" + +from __future__ import annotations + +import json +from dataclasses import dataclass +from pathlib import Path, PureWindowsPath +from typing import Any + +_JSON_LIMIT = 4 * 1024 * 1024 +_LOG_LIMIT = 256 * 1024 +_STATUSES = {"completed", "completed_with_warnings", "failed"} + + +@dataclass(frozen=True) +class SavedJob: + job_id: str + directory: Path + status: str = "" + created_utc: str = "" + problem: str = "" + + +@dataclass(frozen=True) +class SavedJobDetails: + job: SavedJob + manifest: dict[str, Any] + params_text: str + log_text: str + + +def _direct_path(path: Path) -> None: + if path.is_symlink() or path.is_junction(): + raise ValueError(f"Saved analysis paths must stay inside this package: {path}") + + +def _jobs_root(package: str | Path) -> Path: + if not package: + raise ValueError("Select a package before opening saved analysis.") + root = Path(package).resolve() + if not root.is_dir(): + raise ValueError(f"Package is unavailable: {root}") + for path in (root / "processing", root / "processing" / "jobs"): + _direct_path(path) + if path.exists() and not path.is_dir(): + raise ValueError(f"Analysis job location is not a directory: {path}") + return root / "processing" / "jobs" + + +def _job_directory(package: str | Path, job_id: str) -> Path: + if ( + not isinstance(job_id, str) + or not job_id + or job_id.startswith(".") + or job_id.endswith((".", " ")) + or any(char in '<>:"/\\|?*' or ord(char) < 32 for char in job_id) + or PureWindowsPath(job_id).is_reserved() + ): + raise ValueError("Select a visible analysis job from this package.") + path = _jobs_root(package) / job_id + _direct_path(path) + if not path.is_dir(): + raise ValueError(f"Saved analysis job is unavailable: {job_id}") + return path + + +def job_belongs_to_package(package: str | Path, job_dir: str | Path) -> bool: + """Check the directory itself; recorded packagePath can predate a package copy.""" + if not package or not job_dir: + return False + try: + candidate = Path(job_dir).absolute() + return _job_directory(package, candidate.name) == candidate + except (OSError, ValueError): + return False + + +def _read_json(path: Path) -> dict[str, Any]: + _direct_path(path) + if not path.is_file(): + raise ValueError(f"Saved file is unavailable: {path.name}") + with path.open("rb") as stream: + raw = stream.read(_JSON_LIMIT + 1) + if len(raw) > _JSON_LIMIT: + raise ValueError(f"{path.name} exceeds the 4 MiB viewer limit.") + doc = json.loads(raw) + if not isinstance(doc, dict): + raise ValueError(f"{path.name} must contain a JSON object.") + return doc + + +def _package_session_id(package: str | Path) -> str: + manifest = _read_json(Path(package).resolve() / "manifest.json") + identity = manifest.get("identity") or {} + if not isinstance(identity, dict): + raise ValueError("Package identity is malformed.") + # Only an explicit identity is stable when a package directory is copied. + return str(manifest.get("sessionId") or identity.get("sessionId") or "") + + +def _read_job( + package: str | Path, job_id: str, *, session_id: str +) -> tuple[SavedJob, dict[str, Any]]: + path = _job_directory(package, job_id) + manifest = _read_json(path / "job_manifest.json") + if manifest.get("schemaId") != "capture.analysis_job/1": + raise ValueError("This saved job uses an unsupported manifest schema.") + if manifest.get("jobId") != job_id: + raise ValueError("Saved manifest identity does not match its job directory.") + if session_id and manifest.get("sessionId") != session_id: + raise ValueError("Saved job belongs to a different session.") + status = manifest.get("status") + if not isinstance(status, str) or status not in _STATUSES: + raise ValueError("This job has no completed or failed result to inspect yet.") + outputs = manifest.get("outputs", []) + if not isinstance(outputs, list) or any(not isinstance(row, dict) for row in outputs): + raise ValueError("Saved manifest output inventory is malformed.") + return SavedJob(job_id, path, status, str(manifest.get("createdUtc") or "")), manifest + + +def list_saved_jobs(package: str | Path) -> list[SavedJob]: + """Visible jobs, including explicit unavailable rows; hidden attempts stay hidden.""" + jobs = _jobs_root(package) + if not jobs.exists(): + return [] + session_id = _package_session_id(package) + result = [] + for child in sorted(jobs.iterdir(), key=lambda p: p.name, reverse=True): + if child.name.startswith(".") or not child.is_dir(): + continue + try: + job, _ = _read_job(package, child.name, session_id=session_id) + except (OSError, ValueError, UnicodeError) as exc: + job = SavedJob(child.name, child, problem=str(exc)) + result.append(job) + return result + + +def load_saved_job(package: str | Path, job_id: str) -> SavedJobDetails: + """Re-read the selected job at Open time; no cached catalog row authorizes a path.""" + job, manifest = _read_job(package, job_id, session_id=_package_session_id(package)) + try: + params = _read_json(job.directory / "params.json") + params_text = json.dumps(params, ensure_ascii=False, indent=2, sort_keys=True) + except (OSError, ValueError, UnicodeError) as exc: + params_text = f"Parameters unavailable: {exc}" + try: + logs = job.directory / "logs" + _direct_path(logs) + log = logs / "job.log" + _direct_path(log) + if not log.is_file(): + raise ValueError("No saved job.log file.") + with log.open("rb") as stream: + # Show the end of long logs, where completion/failure diagnostics live. + size = stream.seek(0, 2) + stream.seek(max(0, size - _LOG_LIMIT)) + log_text = stream.read(_LOG_LIMIT).decode("utf-8", errors="replace") + if size > _LOG_LIMIT: + log_text = f"Showing the final {_LOG_LIMIT:,} bytes of {size:,}.\n\n{log_text}" + except (OSError, ValueError) as exc: + log_text = f"Log unavailable: {exc}" + return SavedJobDetails(job, manifest, params_text, log_text) diff --git a/desktop/capture_desktop/screen_analysis.py b/desktop/capture_desktop/screen_analysis.py index 83bd8e5f..b312929b 100644 --- a/desktop/capture_desktop/screen_analysis.py +++ b/desktop/capture_desktop/screen_analysis.py @@ -26,8 +26,10 @@ ) from . import theme +from .analysis_history import SavedJobDetails, job_belongs_to_package, load_saved_job from .persistence import DesktopPersistence from .state import CaptureState, fmt_time +from .widgets_analysis_history import AnalysisHistory from .widgets_analysis_jobs import AnalysisJobExtras, peek_ml_bundle_summary from .widgets_analysis_plots import FigureGallery, JobInspector from .widgets_analysis_scope import WINDOW_COMMANDS, ScopeSelection @@ -134,6 +136,11 @@ def __init__( self._scope_note.setObjectName("Dim") root.addWidget(self._scope_note) + self._history = AnalysisHistory() + self._history.job_loaded.connect(self._show_saved_job) + self._history.view_cleared.connect(self._clear_result_view) + root.addWidget(self._history) + splitter = QSplitter() splitter.setChildrenCollapsible(False) root.addWidget(splitter, 1) @@ -339,6 +346,7 @@ def set_package(self, package_path: str) -> None: self._scope = ScopeSelection() self._package = resolved self._path.setText(resolved) + self._history.set_package(resolved) self._extras.set_package(resolved) self._refresh_summary() self._sync_enabled() @@ -379,6 +387,7 @@ def _sync_enabled(self) -> None: self._btn_use_open.setEnabled(not busy and bool(self._state.package_path)) self._command.setEnabled(not busy) self._gap_policy.setEnabled(not busy) + self._history.set_busy(busy) if locked: self._banner.setText( "Analysis is disabled while the session is arming or recording." @@ -452,8 +461,7 @@ def _start_job(self) -> None: return extra = self._extras.build_extra(command) self._log.clear() - self._gallery.clear() - self._inspector.clear() + self._clear_result_view() self._append_log(f"Starting {command} on {self._package}") self._append_log(f"scope={self._scope.describe()}") self._append_log(f"sources={sources or 'All recorded sources'}") @@ -495,10 +503,37 @@ def _on_finished(self, result: object) -> None: job_dir = str(getattr(result, "job_dir", "") or "") status = str(getattr(result, "status", "") or "") job_id = str(getattr(result, "job_id", "") or "") - self._last_job_dir = job_dir - self._progress.setValue(100) self._append_log(f"Done status={status} job_id={job_id}") self._append_log(f"dir={job_dir}") + if not job_belongs_to_package(self._package, job_dir): + self._append_log( + "Result saved for the previous package; select that package to inspect it." + ) + return + self._progress.setValue(100) + self._history.refresh(preferred_job_id=job_id) + try: + details = load_saved_job(self._package, Path(job_dir).name) + except (OSError, ValueError, UnicodeError) as exc: + self._append_log(f"Result saved, but the viewer could not load it: {exc}") + return + self._show_saved_job(details) + + def _clear_result_view(self) -> None: + self._last_job_dir = "" + self._btn_open_job.setEnabled(False) + self._btn_open_report.setEnabled(False) + self._gallery.clear() + self._inspector.clear() + self._history.clear_loaded() + + @Slot(object) + def _show_saved_job(self, details: SavedJobDetails) -> None: + if not job_belongs_to_package(self._package, details.job.directory): + return + job_dir = str(details.job.directory) + self._last_job_dir = job_dir + self._history.show_loaded(details) self._btn_open_job.setEnabled(bool(job_dir)) report = Path(job_dir) / "reports" / "qc.html" if job_dir else Path() self._btn_open_report.setEnabled(report.is_file()) @@ -518,6 +553,7 @@ def _on_finished(self, result: object) -> None: @Slot(str) def _on_failed(self, message: str) -> None: self._append_log(f"FAIL: {message}") + self._history.refresh() if message.split("\n", 1)[0] != "cancelled": QMessageBox.warning(self, "Analysis failed", message) diff --git a/desktop/capture_desktop/widgets_analysis_history.py b/desktop/capture_desktop/widgets_analysis_history.py new file mode 100644 index 00000000..8798627c --- /dev/null +++ b/desktop/capture_desktop/widgets_analysis_history.py @@ -0,0 +1,220 @@ +# SPDX-License-Identifier: GPL-3.0-only +"""Native saved-result picker and read-only analysis details.""" + +from __future__ import annotations + +import json +from pathlib import Path + +from PySide6.QtCore import Qt, Signal +from PySide6.QtWidgets import ( + QComboBox, + QDialog, + QDialogButtonBox, + QHBoxLayout, + QLabel, + QPlainTextEdit, + QPushButton, + QTabWidget, + QVBoxLayout, + QWidget, +) + +from . import theme +from .analysis_history import SavedJob, SavedJobDetails, list_saved_jobs, load_saved_job + + +class AnalysisHistory(QWidget): + """Explicitly open a saved result; choosing one never starts or edits a job.""" + + job_loaded = Signal(object) # SavedJobDetails + view_cleared = Signal() + + def __init__(self, parent: QWidget | None = None) -> None: + super().__init__(parent) + self._package = "" + self._busy = False + self._loaded: SavedJobDetails | None = None + self._dialog: QDialog | None = None + root = QVBoxLayout(self) + root.setContentsMargins(0, 0, 0, 0) + root.setSpacing(4) + row = QHBoxLayout() + label = QLabel("Saved analysis") + label.setFont(theme.ui(9, bold=True)) + row.addWidget(label) + self._jobs = QComboBox() + self._jobs.setObjectName("analysisHistoryJob") + self._jobs.setAccessibleName("Saved analysis job") + self._jobs.setSizeAdjustPolicy(QComboBox.SizeAdjustPolicy.AdjustToMinimumContentsLengthWithIcon) + self._jobs.setMinimumContentsLength(24) + self._jobs.currentIndexChanged.connect(self._selection_changed) + row.addWidget(self._jobs, 1) + self._refresh = QPushButton("Refresh") + self._refresh.setObjectName("analysisHistoryRefresh") + self._refresh.clicked.connect(lambda: self.refresh()) + row.addWidget(self._refresh) + self._open = QPushButton("Open saved result") + self._open.setObjectName("analysisHistoryOpen") + self._open.clicked.connect(self._open_selected) + row.addWidget(self._open) + self._details = QPushButton("Result details…") + self._details.setObjectName("analysisHistoryDetails") + self._details.clicked.connect(self._show_details) + row.addWidget(self._details) + root.addLayout(row) + self._status = QLabel("Select a package to browse its saved analysis.") + self._status.setObjectName("Dim") + self._status.setTextFormat(Qt.TextFormat.PlainText) + self._status.setWordWrap(True) + self._status.setFont(theme.ui(8)) + root.addWidget(self._status) + self._sync_enabled() + + @property + def package(self) -> str: + return self._package + + @property + def loaded_job_id(self) -> str: + return self._loaded.job.job_id if self._loaded else "" + + def set_package(self, package: str) -> None: + identity = str(Path(package).resolve()) if package else "" + if identity == self._package: + return + self._package = identity + self.clear_loaded() + self.view_cleared.emit() + self.refresh() + + def set_busy(self, busy: bool) -> None: + self._busy = busy + self._sync_enabled() + + def clear_loaded(self) -> None: + self._loaded = None + if self._dialog is not None: + self._dialog.close() + self._dialog = None + self._sync_enabled() + + def _selected(self) -> SavedJob | None: + value = self._jobs.currentData() + return value if isinstance(value, SavedJob) else None + + def _sync_enabled(self, *_args) -> None: + row = self._selected() + self._jobs.setEnabled(bool(self._package) and not self._busy) + self._refresh.setEnabled(bool(self._package) and not self._busy) + self._open.setEnabled(row is not None and not row.problem and not self._busy) + self._details.setEnabled(self._loaded is not None and not self._busy) + if row is not None and row.problem: + self._status.setText(f"{row.job_id}: {row.problem}") + + def _selection_changed(self, *_args) -> None: + row = self._selected() + if row is not None and not row.problem: + self._status.setText( + f"Selected {row.job_id} · {row.status}. Open to inspect this result." + ) + self._sync_enabled() + + def refresh(self, preferred_job_id: str | None = None) -> None: + selected = self._selected() + preferred = preferred_job_id or (selected.job_id if selected else "") + self._jobs.blockSignals(True) + self._jobs.clear() + try: + jobs = list_saved_jobs(self._package) if self._package else [] + except (OSError, ValueError) as exc: + jobs = [] + message = f"Could not read saved analysis: {exc}" + else: + usable = sum(not job.problem for job in jobs) + message = ( + f"{usable} saved result(s). Select a job and open it in the gallery and inspector." + if usable else "No readable saved analysis results in this package." + ) + unavailable = len(jobs) - usable + if unavailable: + message += f" {unavailable} unavailable job(s) are listed with their reason." + found = -1 + for job in jobs: + text = f"{job.job_id} · {job.status if not job.problem else 'unavailable'}" + self._jobs.addItem(text, job) + if job.job_id == preferred: + found = self._jobs.count() - 1 + if found >= 0: + self._jobs.setCurrentIndex(found) + self._jobs.blockSignals(False) + if self._loaded and not any( + job.job_id == self._loaded.job.job_id and not job.problem for job in jobs + ): + self.clear_loaded() + self.view_cleared.emit() + if self._loaded is not None: + self.show_loaded(self._loaded) + else: + self._status.setText(message) + self._sync_enabled() + + def show_loaded(self, details: SavedJobDetails) -> None: + self._loaded = details + job = details.job + when = f" · {job.created_utc}" if job.created_utc else "" + self._status.setText(f"Viewing {job.job_id} · {job.status}{when}") + self._sync_enabled() + + def _open_selected(self) -> None: + selected = self._selected() + if self._busy or selected is None or selected.problem: + return + try: + details = load_saved_job(self._package, selected.job_id) + except (OSError, ValueError, UnicodeError) as exc: + self._status.setText(f"Could not open {selected.job_id}: {exc}. Refresh the job list.") + return + self.show_loaded(details) + self.job_loaded.emit(details) + + def _show_details(self) -> None: + if self._loaded is None or self._busy: + return + if self._dialog is not None: + self._dialog.close() + details = self._loaded + dialog = QDialog(self) + dialog.setAttribute(Qt.WidgetAttribute.WA_DeleteOnClose) + dialog.setObjectName("analysisHistoryDetailsDialog") + dialog.setWindowTitle(f"Analysis result — {details.job.job_id}") + dialog.resize(780, 560) + layout = QVBoxLayout(dialog) + location = QLabel(str(details.job.directory)) + location.setTextFormat(Qt.TextFormat.PlainText) + location.setWordWrap(True) + location.setTextInteractionFlags(Qt.TextInteractionFlag.TextSelectableByMouse) + layout.addWidget(location) + tabs = QTabWidget() + for title, text in ( + ("Parameters", details.params_text), + ("Log", details.log_text), + ("Manifest", json.dumps(details.manifest, ensure_ascii=False, indent=2, + sort_keys=True)), + ): + editor = QPlainTextEdit() + editor.setObjectName(f"analysisHistory{title}") + editor.setReadOnly(True) + editor.setFont(theme.mono(9)) + editor.setPlainText(text) + tabs.addTab(editor, title) + layout.addWidget(tabs, 1) + buttons = QDialogButtonBox(QDialogButtonBox.StandardButton.Close) + buttons.rejected.connect(dialog.close) + layout.addWidget(buttons) + dialog.finished.connect(self._details_closed) + self._dialog = dialog + dialog.show() + + def _details_closed(self, _result: int) -> None: + self._dialog = None diff --git a/desktop/capture_desktop/widgets_analysis_plots.py b/desktop/capture_desktop/widgets_analysis_plots.py index 8938b536..263d65c8 100644 --- a/desktop/capture_desktop/widgets_analysis_plots.py +++ b/desktop/capture_desktop/widgets_analysis_plots.py @@ -173,9 +173,37 @@ def load_job_dir(self, job_dir: Path) -> None: figures_dir = job_dir / "figures" if not figures_dir.is_dir(): return - for png in sorted(figures_dir.glob("*.png")): - if png.name == "sync_dashboard.png": + try: + figures_root = figures_dir.resolve(strict=True) + except (OSError, RuntimeError): + return + for png in sorted(figures_dir.rglob("*.png")): + relative = png.relative_to(figures_dir) + if relative == Path("sync_dashboard.png"): + continue + try: + if not png.is_file() or not png.resolve(strict=True).is_relative_to(figures_root): + continue + except (OSError, RuntimeError): continue + parts = list(relative.with_suffix("").parts) + parts[-1] = parts[-1].replace("_", " ") + if ( + len(parts) == 4 + and parts[0] == "numeric" + and parts[1].startswith("source-") + and parts[2].startswith("stream-") + ): + try: + source = bytes.fromhex(parts[1][7:]).decode("utf-8") + stream = bytes.fromhex(parts[2][7:]).decode("utf-8") + except (ValueError, UnicodeError): + pass + else: + parts = [source, stream, parts[-1]] + title = " / ".join(parts) + if len(relative.parts) == 1: + title = title[:24] scroll = QScrollArea() scroll.setWidgetResizable(True) img = QLabel() @@ -186,7 +214,8 @@ def load_job_dir(self, job_dir: Path) -> None: else: img.setText(f"Could not load {png.name}") scroll.setWidget(img) - self._tabs.addTab(scroll, png.stem.replace("_", " ")[:24]) + index = self._tabs.addTab(scroll, title) + self._tabs.setTabToolTip(index, relative.as_posix()) class JobInspector(QWidget): diff --git a/docs/design/research/PROGRESS.md b/docs/design/research/PROGRESS.md index a8bd0bd4..3007e06e 100644 --- a/docs/design/research/PROGRESS.md +++ b/docs/design/research/PROGRESS.md @@ -1174,3 +1174,68 @@ The second unchanged-source diagnostic separates three actual failures and a lat ### PR84 exact file-model boundary and owned scope receiving (2026-10-08) The unchanged-source Windows probe directly distinguished the literal OS filename from Qt6.12 widget-model normalization. Successful real chooser receiving now uses a representable Unicode/internal-space filename; the original leading-space fixture separately requires exact identity or bounded refusal with prior path unchanged, recording the actual branch in JUnit. No product path normalization or native Windows-dialog claim is introduced. The exact owner-authored PR79 scope wait blob817412fe is adopted with estate-7879c2abc07f credit, preserving every existing bound/assertion and excluding its unrelated QC source. The current picker, narrow focused-button Space correction, one-command read-only JUnit gate, original failures and native receiving packets are preserved. Ordinary full-suite Windows acceptance is still pending for this exact composition. + +## 2026-10-08 — Compose saved analysis with the merged scope controls + +Worker `estate-401c5d17da79`, issue #55: receiving on main `3e3ecc5` +preserves the merged #53/#58 scope controls and normalized package identity +while adding saved-result history. The current screen treats its retained +thread handle as busy from scheduled start through the existing cleanup. +One actual QApplication/QTimer journey passes 24 checks with two real +numeric-feature jobs: saved exact ranges, disabled/restored controls, +read-only reopening, same-package scope retention, and refusal to repaint +a different package after a queued completion. The original 14/19 results +below keep their original inputs; Windows CI and the separately owned +nested-numeric gallery repair remain distinct. Exact source, the startup +negative control and current receipts are in +[current scope receiving](../../evidence/analysis-history-401c5d17da79/current-scope/README.md). + +## 2026-10-08 — Reopen saved analysis in the native workbench + +Worker `estate-401c5d17da79`, issue #55: the Analysis tab now lists retained +completed and failed jobs from its selected package. Explicit Open loads the +existing gallery and inspector; native read-only Parameters, Log and Manifest +tabs expose saved diagnostics. Refresh does not rerun analysis. Package changes +clear the old view, and late results remain attached to their original package. +Unavailable/malformed/foreign jobs remain visible with a refusal reason. + +Authored source `37443f0` passes all 14 focused and retained native UI tests, +including actual successful and failed analysis QThreads. Independent receiving +passes 19 checks through the real QApplication event loop: retained real figures, +same-name jobs in different sessions, stale selection refusal, late completion +and exact saved/raw byte preservation. The original worker, signal wiring, +thread cleanup, gallery, inspector and job formats are preserved. The separately +owned #53/#54 scope controls and #46 provenance writer are outside this change. + +Earlier manual-event-pump crashes/stalls and an empty receipt caused by transient +filesystem exhaustion are retained as non-accepting harness outcomes. The same +first candidate passed its genuine application-event-loop control; no native +cleanup defect is inferred from those manual-pump observations. Qualification is +native Linux Qt/Python 3.12, not a Windows CI, full-product or hardware claim. +Exact source pins, raw logs, independent methods and reviewed native frames are +in [the receiving evidence](../../evidence/analysis-history-401c5d17da79/README.md). + + + +## 2026-10-08 — Show retained nested numeric figures in the native gallery (401c5d17da79) + +Issue #64 completes the desktop presentation path for the numeric PNG layout +already produced by merged #49. The gallery now discovers nested saved PNGs, +shows readable source/stream/channel identities and exact path tooltips, and +retains legacy flat labels, native image pixels and the linked Sync dashboard. +Resolved external PNG links and directories named as images are excluded while +valid sibling figures remain visible. The selected-export owner's construction, +clear and loaded-job hooks, saved-history runtime, handlers and job formats are +unchanged. + +The independent real negative fixture retained two numeric channel PNGs while +the old gallery showed only Sync. Final source f2c8b88 passes seven native Qt +tests and fifteen checks against those exact retained numeric outputs plus a +real legacy EMG/IMU job. Raw/saved hashes and executed source bytes remain exact. +The initial six-case receipt, its real-output run, and the subsequent external +PNG-link failure are retained separately from final qualification. Three actual +native frames were reviewed with the existing original-resolution scrolling. +Source pins, methods, limits and exact receipts are in +docs/evidence/nested-figure-gallery-401c5d17da79/README.md. +Full hosted Windows acceptance and current owner integration remain separate. + diff --git a/docs/evidence/analysis-history-401c5d17da79/README.md b/docs/evidence/analysis-history-401c5d17da79/README.md new file mode 100644 index 00000000..68d7d6ce --- /dev/null +++ b/docs/evidence/analysis-history-401c5d17da79/README.md @@ -0,0 +1,108 @@ +# Saved analysis history — issue 55 + +Researchers can reopen analysis already saved inside a selected `.mmsession` +package, inspect its original parameters and log, and move between packages +without leaving figures from the previous package on screen. This completes the +saved-result history and details portion of the existing workbench plan. + +## Source and scope + +Author: `estate-401c5d17da79 / production_discovery`. +Independent native receiver: `estate-401c5d17da79 / estate_coordination`. +Coordination: [CaptureSuite #55](https://github.com/Jacob-Met/CaptureSuite/issues/55). + +The genuine authored parent is +`72c15d6b623e217291a824e4e4808a385df896a9` (tree +`221cf5c7bb3c3392a7c4186ba0bcf5a8664135d1`). The first feature commit is +`c0b5530c03cce3e42a0430e5411cddf1df716e19`; the accepted runtime successor is +`37443f0d4d5ffa684b5423d58501856cadbe0655` (tree +`3b3184b931a2aaf91beec36c953bff909a77f2f5`). Subsequent documentation and +current-parent composition commits retain these runtime file hashes. + +Production changes comprise a read-only `analysis_history.py` reader, a native +`widgets_analysis_history.py` picker/details window, and small screen hooks. +The existing worker class, signal wiring and thread cleanup remain unchanged; +gallery/inspector implementations, analysis handlers and job-writing formats +remain unchanged. History refreshes during successful or failed result delivery. +Package-bound result selection and a fresh manifest read at Open prevent a +cached selection from opening a disappeared or foreign result. + +The time/source/checkpoint UI in #53, preceding-section resolver in #54 and job +provenance writer in #46 retain their separate owners. Existing #48 destination, +replacement and failure-note behavior is preserved. + +## What ran + +| Qualification | Result | Exact evidence | +| --- | --- | --- | +| Canonical original source | A retained real QC job exists, but reopening its package exposes no history control; the existing inspector can read it when called directly | `author/baseline-receipt.json` | +| Original package lifetime control | Real A figures remain visible after selecting B; an actual late A QC completion binds under B | `independent/baseline-receipt.json` | +| Authored native tests plus retained UI tests | **14 passed**, no skips, 3.21 seconds | `author/author-correction.log` | +| Independent full native receiving | **19 checks passed**, exit 0, 0.914 seconds | `independent/native-candidate-receipt.json` | +| Native details visual check | Parameters/log tabs are readable; selected current-QC/2 package bytes unchanged and no worker started | `visual/details-visual-receipt.json` | + +The eight new tests use real completed and failed jobs, copied packages, malformed +and foreign manifests, missing/long saved details, explicit refresh/open actions, +and genuine successful and failed QThreads. The six retained tests cover the +existing workbench, linked plot output and failure-note/cancellation behavior. +Ruff and source whitespace checks pass for all changed production/test files. + +The independent receiver generates actual EMG/IMU protobuf MCAP and saved native +figures. It reopens two real PNG and two linked plots, switches between distinct +sessions with the same job name, refuses unavailable/foreign results, revalidates +a manifest removed after selection, and delays delivery of a genuinely completed +QC job while switching packages. Its native `QApplication.exec()` and `QTimer` +state machine confirms that saved/raw/source bytes stay unchanged during viewing +and late delivery. Exact methods and helpers are retained under +`independent/methods/`; they preserve their original bounded workspace paths for +audit. The receiver also preserves its complete fixture packet separately. + +## Retained unsuccessful attempts + +Manual `processEvents()` / `QTest.qWait()` pumping is not used as the accepting +worker-lifecycle gate. The first authored polling test timed out during a cold +import and aborted while its fixture deleted a running worker. The independent +first candidate similarly crashed after 15 manual-pump checks; a genuine +application-event-loop control of the same runtime passed five checks. A later +manual-pump run stalled and was stopped with exit 130. These outcomes and raw +traces remain in `author/harness-observations.json` and `independent/`; they do +not establish a native application defect. The accepted full receiving uses the +application event loop. No further worker-lifecycle workaround was introduced. + +A transient shared-filesystem exhaustion left one attempted author's stdout, +XML and process receipt empty. No test result is claimed for that attempt, and +no other worker's files were removed. The subsequent retained logs identify the +successful exact runs. + +## Replay and boundaries + +With the project's Python 3.12 desktop/analysis dependencies already installed, +run from the repository root with an isolated Qt platform and application state: + +```sh +QT_QPA_PLATFORM=offscreen python -m pytest \ + tests/ui/test_analysis_history.py \ + tests/ui/test_analysis_workbench.py \ + tests/ui/test_analysis_failure_notes.py -q -ra +``` + +Qualification used Python 3.12.14 and PySide6 6.11.2 on native Linux with the +offscreen Qt platform. It covers this offline UI flow, not Windows CI, the full +desktop/daemon product, physical hardware or clinical validity. The Mac copy is +source/evidence custody only. Current-main QC/2 composition is independently +qualified in the receiving successor and does not replace the authored pins. + +`artifact-manifest.json` records the exact retained file hashes. The details and +gallery captures are actual reviewed native frames: + +The unchanged repository license gate required SPDX headers on the copied +author baseline and visual scripts. `publication-method-adjustments.json` +records their original and publication hashes; only the leading license comment +was added. The exact originally executed bytes remain in commit `1ce96118` and +its immutable source/evidence packet. Runtime and test files did not change. + +![Reopened saved analysis](visual/native-reopened-b.png) + +![Original saved parameters](visual/details-parameters.png) + +![Original saved log](visual/details-log.png) diff --git a/docs/evidence/analysis-history-401c5d17da79/artifact-manifest.json b/docs/evidence/analysis-history-401c5d17da79/artifact-manifest.json new file mode 100644 index 00000000..eb608ae2 --- /dev/null +++ b/docs/evidence/analysis-history-401c5d17da79/artifact-manifest.json @@ -0,0 +1,130 @@ +{ + "files": { + "README.md": { + "bytes": 6192, + "sha256": "343657c7042415e70fdfbdad52816092e351a515dd3c4b5a80a9c88b643558b0" + }, + "author/author-correction-process.json": { + "bytes": 416, + "sha256": "9918f9d7ab8934d215b3146655bce2d9e7eb9474c33891b6d5201cf21c0c5efd" + }, + "author/author-correction.log": { + "bytes": 901, + "sha256": "e08a988c2851e4544838a15637ec18b1b51da3cd644a4cef3b4ad15405ecd892" + }, + "author/author-focused-2.log": { + "bytes": 900, + "sha256": "eacab3f72f2cea5c3abce75976fe9344c0122304d361d75520caa07f136c99e8" + }, + "author/baseline-history.py": { + "bytes": 3012, + "sha256": "ae3d803367e60939f9b777f2196bd4e59e0e2ed169929b1260ec391279f66538" + }, + "author/baseline-receipt.json": { + "bytes": 2105, + "sha256": "2c1097ab9d8a92e7537d5c5cbe4782c249ce0d1a465ca47d7fa595a2d14c1325" + }, + "author/candidate-correction-freeze.json": { + "bytes": 1389, + "sha256": "93f0356c8d3760a6ca3bdee545c98ca015801478d3841798a8148c3bb26a59d4" + }, + "author/candidate-source-freeze.json": { + "bytes": 1151, + "sha256": "0293af5bd506da3b3d96dc5a932c3354b883b52b971ae28ac6e101160b550556" + }, + "author/harness-observations.json": { + "bytes": 1496, + "sha256": "6b6c5ac27f1a1a3646ef6c29eb9478e7215ee26a29d5f77844119c492e55fbef" + }, + "author/thread-event-loop.log": { + "bytes": 882, + "sha256": "fe86b9402d632b49719899d9482047ee0849e2969067e80f79e727a178057b46" + }, + "author/thread-isolated.log": { + "bytes": 10427, + "sha256": "dfffed04778b3b2845938ab83b959916ca0aa4310ab4006cd31d4b76f10f3a96" + }, + "independent/37443-candidate.log": { + "bytes": 1270, + "sha256": "3e4b3290f4d02af0cf1a6461560532dffcfb8cea4c5d5349da1d49113ba48e30" + }, + "independent/37443-manual-stall-receipt.json": { + "bytes": 780, + "sha256": "93854de2dba53424a7ed661724d1b2391a35491522a748d1dc6427f396e7ecb0" + }, + "independent/baseline-receipt.json": { + "bytes": 7323, + "sha256": "a6a5ed459c4f488fffe7808afa5a9471e5a4a86ed49baeb27e07c6e24ea3e508" + }, + "independent/baseline.log": { + "bytes": 675, + "sha256": "7bb3bcd44d35b3f2bc593d4092cad3b2cad89dce25dcf16a04e81890c810b1c7" + }, + "independent/c0b5530-candidate.log": { + "bytes": 4375, + "sha256": "6aae6bbe36f9f7070a42910ecbbf2297a3dd222d5834cbeabbd816e4003f39b4" + }, + "independent/c0b5530-eventloop-receipt.json": { + "bytes": 2679, + "sha256": "17a363b7ffee224a1f65f1eea6a61c4e83d47e8b30ae68aab07ccb2298c425d1" + }, + "independent/c0b5530-eventloop.log": { + "bytes": 375, + "sha256": "42724fb02c89311d1a34d82672cbc9c9034c7ac9a376ec365c4f6c53bc01ed52" + }, + "independent/c0b5530-failure-receipt.json": { + "bytes": 16780, + "sha256": "541c872437bf641d315a3c9f36b0d1e3c660d3ae3adc2b2c7ec6ec1c570aad40" + }, + "independent/methods/receive_history.py": { + "bytes": 23741, + "sha256": "b46094d3d823145aa07aa088371c6a63343ee7c5d8a06b254c6a4669f8c52da8" + }, + "independent/methods/receive_history_native.py": { + "bytes": 11292, + "sha256": "cb2e6486fc13e6e180fc6e8f83d690f3b3cab84faffce6a7c7b0e3fde791a3cd" + }, + "independent/methods/receive_qt_eventloop.py": { + "bytes": 6194, + "sha256": "f05476354e1d1e40478bcc4ed3e5e753bb3baa99fe1a822e3f12e15018236d7d" + }, + "independent/native-candidate-receipt.json": { + "bytes": 30728, + "sha256": "a555ed445c88a575aff3345222e182d06e3e3d2e535d027a40fa4d90056b6f2f" + }, + "independent/native-candidate.log": { + "bytes": 1543, + "sha256": "4136b7357f0cdba48032573a8f10fc2452b307db28ede09be8230835383e30ae" + }, + "publication-license-check.json": { + "bytes": 396, + "sha256": "e79c616da0229b52eae48a50ac286cf844f4e4e57f25310ac59e77cdacf625ad" + }, + "publication-method-adjustments.json": { + "bytes": 1135, + "sha256": "2dc41a21bb18101c40d8964f3ead9821462b701890b5e042d2bab3097a51b41a" + }, + "visual/details-log.png": { + "bytes": 35244, + "sha256": "b33e93d0026b163744737283234116d9332c4790dffc3cfd0caecad2d4935686" + }, + "visual/details-parameters.png": { + "bytes": 37469, + "sha256": "b5bb8407c06e29a89f47739358c8492d211be803a20e2ef164b00b70e3953484" + }, + "visual/details-visual-receipt.json": { + "bytes": 631, + "sha256": "f25badedc5c82769b9448fefa5521abd2135b907aee66cc025da90d147d416e8" + }, + "visual/details-visual.py": { + "bytes": 3668, + "sha256": "c747bcb5bf519b765186e93b4689666148f6bae1b4c45014adda424371c694ab" + }, + "visual/native-reopened-b.png": { + "bytes": 218488, + "sha256": "810766243e7848e2aa966a588c1c4e2245ad74526870a810232ce89db56635e8" + } + }, + "runtime_commit": "37443f0d4d5ffa684b5423d58501856cadbe0655", + "source_base": "72c15d6b623e217291a824e4e4808a385df896a9" +} diff --git a/docs/evidence/analysis-history-401c5d17da79/author/author-correction-process.json b/docs/evidence/analysis-history-401c5d17da79/author/author-correction-process.json new file mode 100644 index 00000000..82b5908a --- /dev/null +++ b/docs/evidence/analysis-history-401c5d17da79/author/author-correction-process.json @@ -0,0 +1,17 @@ +{ + "exit": 0, + "elapsed": 4.036, + "command": [ + "/workspace/scratch/234cae4aee53/capturesuite-venv/bin/python", + "-m", + "pytest", + "tests/ui/test_analysis_history.py", + "tests/ui/test_analysis_workbench.py", + "tests/ui/test_analysis_failure_notes.py", + "-q", + "-ra", + "-p", + "no:cacheprovider", + "--basetemp=/dev/shm/capturesuite-history-401c5d17da79/tmp/author-correction" + ] +} diff --git a/docs/evidence/analysis-history-401c5d17da79/author/author-correction.log b/docs/evidence/analysis-history-401c5d17da79/author/author-correction.log new file mode 100644 index 00000000..25b37635 --- /dev/null +++ b/docs/evidence/analysis-history-401c5d17da79/author/author-correction.log @@ -0,0 +1,10 @@ +.............. [100%] +=============================== warnings summary =============================== +tests/ui/test_analysis_history.py::test_native_open_and_details_leave_the_package_unchanged + :488: DeprecationWarning: Type google._upb._message.MessageMapContainer uses PyType_Spec with a metaclass that has custom tp_new. This is deprecated and will no longer be allowed in Python 3.14. + +tests/ui/test_analysis_history.py::test_native_open_and_details_leave_the_package_unchanged + :488: DeprecationWarning: Type google._upb._message.ScalarMapContainer uses PyType_Spec with a metaclass that has custom tp_new. This is deprecated and will no longer be allowed in Python 3.14. + +-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html +14 passed, 2 warnings in 3.21s diff --git a/docs/evidence/analysis-history-401c5d17da79/author/author-focused-2.log b/docs/evidence/analysis-history-401c5d17da79/author/author-focused-2.log new file mode 100644 index 00000000..62361817 --- /dev/null +++ b/docs/evidence/analysis-history-401c5d17da79/author/author-focused-2.log @@ -0,0 +1,10 @@ +....... [100%] +=============================== warnings summary =============================== +tests/ui/test_analysis_history.py::test_native_open_and_details_leave_the_package_unchanged + :488: DeprecationWarning: Type google._upb._message.MessageMapContainer uses PyType_Spec with a metaclass that has custom tp_new. This is deprecated and will no longer be allowed in Python 3.14. + +tests/ui/test_analysis_history.py::test_native_open_and_details_leave_the_package_unchanged + :488: DeprecationWarning: Type google._upb._message.ScalarMapContainer uses PyType_Spec with a metaclass that has custom tp_new. This is deprecated and will no longer be allowed in Python 3.14. + +-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html +7 passed, 2 warnings in 2.61s diff --git a/docs/evidence/analysis-history-401c5d17da79/author/baseline-history.py b/docs/evidence/analysis-history-401c5d17da79/author/baseline-history.py new file mode 100644 index 00000000..8cf22dbc --- /dev/null +++ b/docs/evidence/analysis-history-401c5d17da79/author/baseline-history.py @@ -0,0 +1,63 @@ +# SPDX-License-Identifier: GPL-3.0-only +"""Existing-interface baseline: retained job is readable but not offered by Analysis.""" +import hashlib +import json +import os +from pathlib import Path +import shutil +import sys + +ROOT = Path(__file__).resolve().parents[1] +SOURCE = ROOT / 'source' +for package in ('capture_analysis', 'capture_session', 'capture_protocol'): + sys.path.insert(0, str(SOURCE / 'libs/python' / package)) +sys.path.insert(0, str(SOURCE / 'desktop')) +os.environ['QT_QPA_PLATFORM'] = 'offscreen' +for key, suffix in [('LOCALAPPDATA', 'local'), ('APPDATA', 'roaming'), ('XDG_CONFIG_HOME', 'config'), + ('XDG_DATA_HOME', 'data'), ('XDG_CACHE_HOME', 'cache'), ('MPLCONFIGDIR', 'mpl')]: + path = ROOT / 'tmp' / suffix + path.mkdir(exist_ok=True) + os.environ[key] = str(path) + +from capture_analysis import JobParams, run +from capture_desktop.screen_analysis import AnalysisScreen +from capture_desktop.state import CaptureState +from capture_desktop import theme +from PySide6.QtWidgets import QApplication, QPushButton + +package = ROOT / 'evidence/baseline-saved.mmsession' +shutil.copytree(SOURCE / 'tests/fixtures/mini_session', package) +def raw_hashes(): + return {p.relative_to(package).as_posix():hashlib.sha256(p.read_bytes()).hexdigest() + for p in sorted(package.rglob('*')) if p.is_file() and 'processing' not in p.relative_to(package).parts} +before = raw_hashes() +result = run(package, JobParams(command='qc', overwrite_job_id='retained-qc')) +assert before == raw_hashes() +app = QApplication([]) +theme.apply_theme(app, setting='dark') +screen = AnalysisScreen(CaptureState()) +screen.set_package(str(package)) +screen.resize(1220, 850) +screen.show() +app.processEvents() +assert not screen._last_job_dir +assert screen._inspector._meta.text() == 'No job loaded' +assert not screen._btn_open_job.isEnabled() +assert not hasattr(screen, '_history') +buttons = [b.text() for b in screen.findChildren(QPushButton)] +assert not any('saved' in b.casefold() or 'history' in b.casefold() for b in buttons) +screen.grab().save(str(ROOT/'evidence/baseline-no-history.png')) +# The existing reader already understands the retained job, isolating the UI gap. +screen._inspector.load_job_dir(result.job_dir) +assert 'job_id=retained-qc' in screen._inspector._meta.text() +assert before == raw_hashes() +receipt = {'source_commit':'72c15d6b623e217291a824e4e4808a385df896a9', + 'source_tree':'221cf5c7bb3c3392a7c4186ba0bcf5a8664135d1', + 'python':sys.version,'qt_platform':app.platformName(), + 'actual_job_status':result.status,'retained_job':str(result.job_dir), + 'baseline':'feature absent: reopening a package leaves gallery/inspector unbound', + 'existing_inspector_manual_control':True,'raw_unchanged':True, + 'buttons':buttons,'raw_sha256':before} +(ROOT/'evidence/baseline-receipt.json').write_text(json.dumps(receipt,indent=2)+'\n') +print(json.dumps({k:v for k,v in receipt.items() if k!='raw_sha256'},indent=2)) +screen.close() diff --git a/docs/evidence/analysis-history-401c5d17da79/author/baseline-receipt.json b/docs/evidence/analysis-history-401c5d17da79/author/baseline-receipt.json new file mode 100644 index 00000000..37f48433 --- /dev/null +++ b/docs/evidence/analysis-history-401c5d17da79/author/baseline-receipt.json @@ -0,0 +1,34 @@ +{ + "source_commit": "72c15d6b623e217291a824e4e4808a385df896a9", + "source_tree": "221cf5c7bb3c3392a7c4186ba0bcf5a8664135d1", + "python": "3.12.14 (main, Aug 25 2026, 14:00:49) [Clang 22.1.3 ]", + "qt_platform": "offscreen", + "actual_job_status": "completed", + "retained_job": "/dev/shm/capturesuite-history-401c5d17da79/evidence/baseline-saved.mmsession/processing/jobs/retained-qc", + "baseline": "feature absent: reopening a package leaves gallery/inspector unbound", + "existing_inspector_manual_control": true, + "raw_unchanged": true, + "buttons": [ + "Use open session", + "Browse\u2026", + "Run", + "Cancel", + "Open job folder", + "Open QC report (HTML)", + "Save mapping preset" + ], + "raw_sha256": { + "events/annotations.json": "37517e5f3dc66819f61f5a7bb8ace1921282415f10551d2defa5c3eb0985b570", + "events/checkpoints.json": "37517e5f3dc66819f61f5a7bb8ace1921282415f10551d2defa5c3eb0985b570", + "events/sync_anchors.json": "37517e5f3dc66819f61f5a7bb8ace1921282415f10551d2defa5c3eb0985b570", + "integrity.json": "af5d9bacd3eace7e831d48dee83eb5d9f578f4f4819d92218c4b55b0cb3ed556", + "manifest.json": "c5254d3e4c0bc6a0ecaef124dc12d88117d647928a8e1725b71429097438d380", + "sources/sim.emg.main/health/gaps.jsonl": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "sources/sim.emg.main/source.json": "4e7626e51bfb804c27f83bf98ee186a47ec9f36fec0cbd7863ea8ecb1ecfbd10", + "sources/sim.emg.main/streams/sim.emg.main.batch/segments/000000.mcap": "3c4d91b3bf5d48dcf54a598fff5b1b4ee42260b756d6f5df3986da496c6a9649", + "sources/sim.emg.main/streams/sim.emg.main.batch/stream.json": "8f8c02b89fd93e55643151e5222488e1174dd97a6b7a74f3ae5da8215b4d68e1", + "sources/sim.imu.upper/source.json": "a6198f509edc557c1e1d8583a767a540962977751c80a1b6491e3d594b60c7a8", + "sources/sim.imu.upper/streams/sim.imu.upper.frames/segments/000000.mcap": "3c4d91b3bf5d48dcf54a598fff5b1b4ee42260b756d6f5df3986da496c6a9649", + "sources/sim.imu.upper/streams/sim.imu.upper.frames/stream.json": "ec39026bed1b833d4decb0ef7b0efb94c5557a5647bc50addc060bef3a30d50d" + } +} diff --git a/docs/evidence/analysis-history-401c5d17da79/author/candidate-correction-freeze.json b/docs/evidence/analysis-history-401c5d17da79/author/candidate-correction-freeze.json new file mode 100644 index 00000000..f8377a4b --- /dev/null +++ b/docs/evidence/analysis-history-401c5d17da79/author/candidate-correction-freeze.json @@ -0,0 +1,28 @@ +{ + "baseline": "72c15d6b623e217291a824e4e4808a385df896a9", + "previous_candidate": "c0b5530c03cce3e42a0430e5411cddf1df716e19", + "commit": "37443f0d4d5ffa684b5423d58501856cadbe0655", + "tree": "3b3184b931a2aaf91beec36c953bff909a77f2f5", + "inputs": { + "desktop/capture_desktop/analysis_history.py": { + "sha256": "2e0db8cee59ef268d3c91ea0beac7d761d83a3003862841cc9d7f1782fd3543c", + "bytes": 6375 + }, + "desktop/capture_desktop/widgets_analysis_history.py": { + "sha256": "a3b77c87483c1412b50de7ddde1498f6bfd3968002fc3ac3bfa474a2477d9bc4", + "bytes": 8458 + }, + "desktop/capture_desktop/screen_analysis.py": { + "sha256": "98a704e31b14497e012fe5618ad47cc8a772bd2d59775826d71a5bdf41533211", + "bytes": 16407 + }, + "tests/ui/test_analysis_history.py": { + "sha256": "48175547922125c308fa49bbb84149e3dac8903902e7cc64fa7c15b4ca40eccd", + "bytes": 10465 + } + }, + "runtime": "/workspace/scratch/234cae4aee53/capturesuite-venv/bin/python", + "focused_and_retained_tests": "14 passed in3.21s; no skips", + "worker_and_thread_cleanup_ast_identical_to_baseline": true, + "correction": "Refresh failed retained jobs in the failure slot; successful completion already refreshes there. Restore original thread-finished cleanup, eliminating added filesystem work after releasing worker references. Native worker and signal wiring are unchanged." +} diff --git a/docs/evidence/analysis-history-401c5d17da79/author/candidate-source-freeze.json b/docs/evidence/analysis-history-401c5d17da79/author/candidate-source-freeze.json new file mode 100644 index 00000000..dd9c7fcb --- /dev/null +++ b/docs/evidence/analysis-history-401c5d17da79/author/candidate-source-freeze.json @@ -0,0 +1,26 @@ +{ + "baseline": "72c15d6b623e217291a824e4e4808a385df896a9", + "commit": "c0b5530c03cce3e42a0430e5411cddf1df716e19", + "tree": "c384c9553757fb1614405d124a5026ae49b4be71", + "inputs": { + "desktop/capture_desktop/analysis_history.py": { + "sha256": "2e0db8cee59ef268d3c91ea0beac7d761d83a3003862841cc9d7f1782fd3543c", + "bytes": 6375 + }, + "desktop/capture_desktop/widgets_analysis_history.py": { + "sha256": "a3b77c87483c1412b50de7ddde1498f6bfd3968002fc3ac3bfa474a2477d9bc4", + "bytes": 8458 + }, + "desktop/capture_desktop/screen_analysis.py": { + "sha256": "4a2e3eaee50fba5236b5567be993582a557de6fe2c62cc0bf3f424483beefb2b", + "bytes": 16407 + }, + "tests/ui/test_analysis_history.py": { + "sha256": "eabe6a4e663307965ce00a1f9032325bfc7be6357b7a3a91b79820cafc4c0a97", + "bytes": 9023 + } + }, + "runtime": "/workspace/scratch/234cae4aee53/capturesuite-venv/bin/python", + "focused_tests": "7 passed in 2.61s; no skips", + "harness_notes": "Replaced QTest.qWait polling with QEventLoop plus settling cleanup after a timeout/unsafe teardown; production worker and signal wiring remain baseline bytes." +} diff --git a/docs/evidence/analysis-history-401c5d17da79/author/harness-observations.json b/docs/evidence/analysis-history-401c5d17da79/author/harness-observations.json new file mode 100644 index 00000000..bbb9bec3 --- /dev/null +++ b/docs/evidence/analysis-history-401c5d17da79/author/harness-observations.json @@ -0,0 +1,23 @@ +{ + "schema": "capturesuite.history.harness-observations.v1", + "first_author_combined": { + "outcome": "Six focused cases completed, then process exited139 under manual processEvents/QTest.qWait; original output was retained in tool transcript only. No raw-file pass is claimed." + }, + "isolated_author_manual": { + "outcome": "Child exited-6. Pytest fixture teardown ran while first-time pandas import was still active in the worker after the15-second polling deadline.", + "raw_log": "thread-isolated.log" + }, + "author_native_loop": { + "outcome": "Unchanged production bytes passed the isolated real worker through QEventLoop in2.19s and all seven original focused cases in2.61s.", + "raw_logs": [ + "thread-event-loop.log", + "author-focused-2.log" + ] + }, + "transient_enospc": { + "outcome": "Shared tmpfs filled during an attempted combined run/receipt write; stdout/XML/process files were zero-length. No retained test result exists for that attempt. No files outside this lane were removed or changed." + }, + "independent_manual_and_native": { + "outcome": "See independent exact raw logs: c0b5530 manual pumping exited139 after15 checks, whereas its genuine QApplication.exec control passed5 checks. Corrected37443 manual pumping stalled after15 checks and was stopped(exit130); its full QApplication.exec/QTimer state machine passed19 checks. The manual outcomes are harness limitations and are not treated as proof of a native application defect." + } +} diff --git a/docs/evidence/analysis-history-401c5d17da79/author/thread-event-loop.log b/docs/evidence/analysis-history-401c5d17da79/author/thread-event-loop.log new file mode 100644 index 00000000..46c92add --- /dev/null +++ b/docs/evidence/analysis-history-401c5d17da79/author/thread-event-loop.log @@ -0,0 +1,10 @@ +. [100%] +=============================== warnings summary =============================== +tests/ui/test_analysis_history.py::test_real_threaded_completion_populates_history + :488: DeprecationWarning: Type google._upb._message.MessageMapContainer uses PyType_Spec with a metaclass that has custom tp_new. This is deprecated and will no longer be allowed in Python 3.14. + +tests/ui/test_analysis_history.py::test_real_threaded_completion_populates_history + :488: DeprecationWarning: Type google._upb._message.ScalarMapContainer uses PyType_Spec with a metaclass that has custom tp_new. This is deprecated and will no longer be allowed in Python 3.14. + +-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html +1 passed, 2 warnings in 2.19s diff --git a/docs/evidence/analysis-history-401c5d17da79/author/thread-isolated.log b/docs/evidence/analysis-history-401c5d17da79/author/thread-isolated.log new file mode 100644 index 00000000..897576ca --- /dev/null +++ b/docs/evidence/analysis-history-401c5d17da79/author/thread-isolated.log @@ -0,0 +1,99 @@ +FFatal Python error: Aborted + +Thread 0x00007fed030eb6c0 (most recent call first): + File "", line 1191 in get_data + File "", line 1091 in get_code + File "", line 995 in exec_module + File "", line 935 in _load_unlocked + File "", line 1331 in _find_and_load_unlocked + File "", line 1360 in _find_and_load + File "/workspace/scratch/234cae4aee53/capturesuite-venv/lib/python3.12/site-packages/pandas/core/groupby/generic.py", line 64 in + File "", line 488 in _call_with_frames_removed + File "", line 999 in exec_module + File "", line 935 in _load_unlocked + File "", line 1331 in _find_and_load_unlocked + File "", line 1360 in _find_and_load + File "/workspace/scratch/234cae4aee53/capturesuite-venv/lib/python3.12/site-packages/pandas/core/groupby/__init__.py", line 1 in + File "", line 488 in _call_with_frames_removed + File "", line 999 in exec_module + File "", line 935 in _load_unlocked + File "", line 1331 in _find_and_load_unlocked + File "", line 1360 in _find_and_load + File "/workspace/scratch/234cae4aee53/capturesuite-venv/lib/python3.12/site-packages/pandas/core/api.py", line 46 in + File "", line 488 in _call_with_frames_removed + File "", line 999 in exec_module + File "", line 935 in _load_unlocked + File "", line 1331 in _find_and_load_unlocked + File "", line 1360 in _find_and_load + File "/workspace/scratch/234cae4aee53/capturesuite-venv/lib/python3.12/site-packages/pandas/__init__.py", line 46 in + File "", line 488 in _call_with_frames_removed + File "", line 999 in exec_module + File "", line 935 in _load_unlocked + File "", line 1331 in _find_and_load_unlocked + File "", line 1360 in _find_and_load + File "/dev/shm/capturesuite-history-401c5d17da79/source/libs/python/capture_analysis/capture_analysis/features/emg.py", line 7 in + File "", line 488 in _call_with_frames_removed + File "", line 999 in exec_module + File "", line 935 in _load_unlocked + File "", line 1331 in _find_and_load_unlocked + File "", line 1360 in _find_and_load + File "/dev/shm/capturesuite-history-401c5d17da79/source/libs/python/capture_analysis/capture_analysis/plugins/handlers.py", line 14 in + File "", line 488 in _call_with_frames_removed + File "", line 999 in exec_module + File "", line 935 in _load_unlocked + File "", line 1331 in _find_and_load_unlocked + File "", line 1360 in _find_and_load + File "/dev/shm/capturesuite-history-401c5d17da79/source/libs/python/capture_analysis/capture_analysis/pipeline.py", line 16 in + File "", line 488 in _call_with_frames_removed + File "", line 999 in exec_module + File "", line 935 in _load_unlocked + File "", line 1331 in _find_and_load_unlocked + File "", line 1360 in _find_and_load + File "/dev/shm/capturesuite-history-401c5d17da79/source/libs/python/capture_analysis/capture_analysis/jobs.py", line 22 in + File "", line 488 in _call_with_frames_removed + File "", line 999 in exec_module + File "", line 935 in _load_unlocked + File "", line 1331 in _find_and_load_unlocked + File "", line 1360 in _find_and_load + File "/dev/shm/capturesuite-history-401c5d17da79/source/libs/python/capture_analysis/capture_analysis/__init__.py", line 5 in + File "", line 488 in _call_with_frames_removed + File "", line 999 in exec_module + File "", line 935 in _load_unlocked + File "", line 1331 in _find_and_load_unlocked + File "", line 1360 in _find_and_load + File "/dev/shm/capturesuite-history-401c5d17da79/source/desktop/capture_desktop/screen_analysis.py", line 61 in run + +Current thread 0x00007fed24ed9740 (most recent call first): + File "/dev/shm/capturesuite-history-401c5d17da79/source/tests/conftest.py", line 54 in qapp + File "/workspace/scratch/234cae4aee53/capturesuite-venv/lib/python3.12/site-packages/_pytest/fixtures.py", line 1014 in _teardown_yield_fixture + File "/workspace/scratch/234cae4aee53/capturesuite-venv/lib/python3.12/site-packages/_pytest/fixtures.py", line 1156 in finish + File "/workspace/scratch/234cae4aee53/capturesuite-venv/lib/python3.12/site-packages/_pytest/runner.py", line 568 in teardown_exact + File "/workspace/scratch/234cae4aee53/capturesuite-venv/lib/python3.12/site-packages/_pytest/runner.py", line 199 in pytest_runtest_teardown + File "/workspace/scratch/234cae4aee53/capturesuite-venv/lib/python3.12/site-packages/pluggy/_callers.py", line 121 in _multicall + File "/workspace/scratch/234cae4aee53/capturesuite-venv/lib/python3.12/site-packages/pluggy/_manager.py", line 120 in _hookexec + File "/workspace/scratch/234cae4aee53/capturesuite-venv/lib/python3.12/site-packages/pluggy/_hooks.py", line 512 in __call__ + File "/workspace/scratch/234cae4aee53/capturesuite-venv/lib/python3.12/site-packages/_pytest/runner.py", line 250 in + File "/workspace/scratch/234cae4aee53/capturesuite-venv/lib/python3.12/site-packages/_pytest/runner.py", line 361 in from_call + File "/workspace/scratch/234cae4aee53/capturesuite-venv/lib/python3.12/site-packages/_pytest/runner.py", line 249 in call_and_report + File "/workspace/scratch/234cae4aee53/capturesuite-venv/lib/python3.12/site-packages/_pytest/runner.py", line 144 in runtestprotocol + File "/workspace/scratch/234cae4aee53/capturesuite-venv/lib/python3.12/site-packages/_pytest/runner.py", line 118 in pytest_runtest_protocol + File "/workspace/scratch/234cae4aee53/capturesuite-venv/lib/python3.12/site-packages/pluggy/_callers.py", line 121 in _multicall + File "/workspace/scratch/234cae4aee53/capturesuite-venv/lib/python3.12/site-packages/pluggy/_manager.py", line 120 in _hookexec + File "/workspace/scratch/234cae4aee53/capturesuite-venv/lib/python3.12/site-packages/pluggy/_hooks.py", line 512 in __call__ + File "/workspace/scratch/234cae4aee53/capturesuite-venv/lib/python3.12/site-packages/_pytest/main.py", line 408 in pytest_runtestloop + File "/workspace/scratch/234cae4aee53/capturesuite-venv/lib/python3.12/site-packages/pluggy/_callers.py", line 121 in _multicall + File "/workspace/scratch/234cae4aee53/capturesuite-venv/lib/python3.12/site-packages/pluggy/_manager.py", line 120 in _hookexec + File "/workspace/scratch/234cae4aee53/capturesuite-venv/lib/python3.12/site-packages/pluggy/_hooks.py", line 512 in __call__ + File "/workspace/scratch/234cae4aee53/capturesuite-venv/lib/python3.12/site-packages/_pytest/main.py", line 384 in _main + File "/workspace/scratch/234cae4aee53/capturesuite-venv/lib/python3.12/site-packages/_pytest/main.py", line 330 in wrap_session + File "/workspace/scratch/234cae4aee53/capturesuite-venv/lib/python3.12/site-packages/_pytest/main.py", line 377 in pytest_cmdline_main + File "/workspace/scratch/234cae4aee53/capturesuite-venv/lib/python3.12/site-packages/pluggy/_callers.py", line 121 in _multicall + File "/workspace/scratch/234cae4aee53/capturesuite-venv/lib/python3.12/site-packages/pluggy/_manager.py", line 120 in _hookexec + File "/workspace/scratch/234cae4aee53/capturesuite-venv/lib/python3.12/site-packages/pluggy/_hooks.py", line 512 in __call__ + File "/workspace/scratch/234cae4aee53/capturesuite-venv/lib/python3.12/site-packages/_pytest/config/__init__.py", line 229 in _main + File "/workspace/scratch/234cae4aee53/capturesuite-venv/lib/python3.12/site-packages/_pytest/config/__init__.py", line 253 in _console_main + File "/workspace/scratch/234cae4aee53/capturesuite-venv/lib/python3.12/site-packages/pytest/__main__.py", line 9 in + File "", line 88 in _run_code + File "", line 198 in _run_module_as_main + +Extension modules: shiboken6.Shiboken, PySide6.QtCore, PySide6.QtGui, PySide6.QtWidgets, google._upb._message, numpy._core._multiarray_umath, numpy.linalg._umath_linalg, PySide6.QtSvg, PySide6.QtOpenGLWidgets, PySide6.QtTest, PySide6.QtOpenGL, PIL._imaging, kiwisolver._cext, pyarrow.lib, numpy.random._common, numpy.random.bit_generator, numpy.random._bounded_integers, numpy.random._pcg64, numpy.random._generator, numpy.random._mt19937, numpy.random._philox, numpy.random._sfc64, numpy.random.mtrand, _cyutility, pandas._libs._cyutility, pandas._libs.tslibs.ccalendar, pandas._libs.tslibs.np_datetime, pandas._libs.tslibs.dtypes, pandas._libs.tslibs.base, pandas._libs.tslibs.nattype, pandas._libs.tslibs.timezones, pandas._libs.properties, pandas._libs.tslibs.fields, pandas._libs.tslibs.timedeltas, pandas._libs.tslibs.tzconversion, pandas._libs.tslibs.timestamps, pandas._libs.tslibs.offsets, pandas._libs.tslibs.strptime, pandas._libs.tslibs.parsing, pandas._libs.tslibs.conversion, pandas._libs.tslibs.period, pandas._libs.tslibs.vectorized, pandas._libs.ops_dispatch, pandas._libs.missing, pandas._libs.hashtable, pandas._libs.algos, pandas._libs.interval, pandas._libs.lib, pyarrow._compute, pandas._libs.ops, pandas._libs.hashing, pandas._libs.arrays, pandas._libs.tslib, pandas._libs.sparse, pandas._libs.internals (total: 55) diff --git a/docs/evidence/analysis-history-401c5d17da79/current-numeric/README.md b/docs/evidence/analysis-history-401c5d17da79/current-numeric/README.md new file mode 100644 index 00000000..d3168f44 --- /dev/null +++ b/docs/evidence/analysis-history-401c5d17da79/current-numeric/README.md @@ -0,0 +1,72 @@ +# Current numeric output: retained gallery limitation + +During the final current-parent check, main advanced to +`0ed1ccaa023a5327495565d59e1dd0b28b2ee5bd` (tree +`b8990a709744eab58b25b875596c79d0865cce4a`) by accepting numeric analysis +[PR #49](https://github.com/Jacob-Met/CaptureSuite/pull/49), owned by +`estate-e82707f2bc62` under issue #43. The six accepted numeric production +files remain unchanged in this history publication. + +Those handlers write channel figures below +`figures/numeric/source-…/stream-…/channel_*.png`. The existing +`FigureGallery.load_job_dir` enumerates only `figures/*.png`. Its exact +unchanged source is: + +- Path: `desktop/capture_desktop/widgets_analysis_plots.py` +- Git blob: `bb6c3033b5e4ed96a2e08857d38715b836926bf5` +- SHA-256: `85c73f881ee7d60ef2f868f7ff73fc57c0a4ef99a717f7f5015534db23e1ab86` + +## One native reproduction + +Runtime tree `210832e8a07ccc6dff8ead12e9bf45dde3b31652` combines that +actual main with the unchanged, accepted history runtime `37443f0d`. +The receiver uses the current accepted numeric test's small MCAP/protobuf +fixture helpers, then invokes the real `run(..., JobParams(command="all"))`. +It does not run the numeric owner's test suite or change its implementation. + +The actual job writes two valid channel PNGs. Opening the retained job through +the native history selects the correct job and manifest in the inspector, +but the gallery contains only its **Sync** tab. Directly loading the same +job into a standalone instance of the unchanged gallery produces the same +missing channel tabs. This locates the gap in the pre-existing current-main +gallery reader rather than in saved-history selection. + +The process exits 1 with **six positive checks and one failed presentation +check**, no exceptions. All 141 frozen source/fixture files and every generated +package/job byte remain unchanged while viewing; history starts no computation +thread. The only stderr is the standard offscreen `propagateSizeHints` warning. +The current history hooks, job identities and read-only behavior remain intact. + +The snapshot `numeric-run/numeric-history-gap.png` is the first event-callback +frame before later paint/layout settling. Its visible Sync-only tab state is +supporting evidence; the exact widget tab counts and two valid on-disk PNGs in +`numeric-run/receipt.json` are the receiving proof. This frame is not a visual +layout qualification. + +## Publication boundary + +This history PR preserves its three-file production scope and the existing +gallery source. Nested numeric channel figures remain listed in the job's +saved output inventory and accessible in its job folder; the Sync result can +be selected, while individual nested channel tabs await a separately +coordinated gallery repair. This publication does not claim all current +numeric figures are displayed in the gallery. + +The e43 QC/2 success remains separately pinned under `../current-qc/`. +Neither that success nor this current-main finding replaces the author's +14-test receipt or the independent 19-check native history receipt. + +## Exact pins + +| Artifact | SHA-256 | +| --- | --- | +| `check_numeric_gallery.py` | `c6d9c3aaf73e1cfef62c86dc36491440d3d6c6001996f149e2b978c97e2959d8` | +| `numeric-run/receipt.json` | `8e9f7cb7a8ce219b4fea8090cff5e1c602b6d4fb100a6d011983594206e3ef29` | +| `numeric.stdout.log` | `9d5c3d3907cd95f62cf380cc2b5196c33f183bfdeb5665ad0c3af42f2855eeaa` | +| `numeric.stderr.log` | `caeb11f6473c6c7125dd27478e588b85ffd6b31784e9adb1371a60f1661eb00f` | + +The source manifest records the complete 141-file projection, including the +unchanged accepted fixture helper. `process.json` retains the exact command +and 4.471-second execution. Replaying `check_numeric_gallery.py` uses the same +`--source`, `--inputs`, and new private `--output` directory contract as the +current-QC companion. Its output must be outside the verified source. diff --git a/docs/evidence/analysis-history-401c5d17da79/current-numeric/check_numeric_gallery.py b/docs/evidence/analysis-history-401c5d17da79/current-numeric/check_numeric_gallery.py new file mode 100644 index 00000000..ab472b81 --- /dev/null +++ b/docs/evidence/analysis-history-401c5d17da79/current-numeric/check_numeric_gallery.py @@ -0,0 +1,90 @@ +# SPDX-License-Identifier: GPL-3.0-only +"""Observe current numeric artifacts through history and the unchanged gallery.""" +from pathlib import Path +import argparse +import hashlib +import importlib.util +import json +import os +import sys +import traceback + + +def hashes(root): + return {p.relative_to(root).as_posix():hashlib.sha256(p.read_bytes()).hexdigest() + for p in sorted(root.rglob('*')) if p.is_file()} + + +def main(): + parser=argparse.ArgumentParser(description=__doc__) + parser.add_argument('--source',type=Path,required=True) + parser.add_argument('--inputs',type=Path,required=True) + parser.add_argument('--output',type=Path,required=True) + args=parser.parse_args();source=args.source.resolve();out=args.output.resolve() + assert not out.exists() and source not in out.parents and out!=source + manifest=json.loads(args.inputs.read_text());expected={r['path']:r['sha256'] for r in manifest['files']} + assert hashes(source)==expected + out.mkdir(parents=True,exist_ok=False) + for key,leaf in [('LOCALAPPDATA','local'),('APPDATA','roaming'),('XDG_CONFIG_HOME','config'),('XDG_DATA_HOME','data'),('XDG_CACHE_HOME','cache'),('MPLCONFIGDIR','mpl')]: + p=out/'state'/leaf;p.mkdir(parents=True);os.environ[key]=str(p) + os.environ['QT_QPA_PLATFORM']='offscreen';sys.dont_write_bytecode=True + for rel in reversed(['desktop','libs/python/capture_analysis','libs/python/capture_session','libs/python/capture_protocol','libs/python/capture_protocol/capture_protocol/generated','libs/python/capture_worker']): + sys.path.insert(0,str(source/rel)) + report={'canonical_main':manifest['canonical_parent'],'author_source':manifest['author_source'],'runtime_tree':manifest['composition_tree'],'checks':[],'errors':[],'method_sha256':hashlib.sha256(Path(__file__).read_bytes()).hexdigest(),'source_inputs_sha256':hashlib.sha256(args.inputs.read_bytes()).hexdigest()} + def check(name,value):report['checks'].append({'name':name,'passed':bool(value)}) + status=1 + try: + import PySide6 + from PySide6.QtCore import QTimer,QCoreApplication,QEvent + from PySide6.QtWidgets import QApplication + from capture_analysis import run,JobParams + from capture_desktop import theme + from capture_desktop.screen_analysis import AnalysisScreen + from capture_desktop.state import CaptureState + from capture_desktop.widgets_analysis_plots import FigureGallery + fixture_path=source/'tests/analysis/test_numeric_batch_pipeline.py' + spec=importlib.util.spec_from_file_location('accepted_numeric_fixture',fixture_path) + helper=importlib.util.module_from_spec(spec);spec.loader.exec_module(helper) + package=out/'numeric.mmsession';package.mkdir() + (package/'manifest.json').write_text(json.dumps({'sessionId':'history.numeric.current','state':'sealed'})+'\n') + stream=package/'sources/lsl/streams/numeric';stream.mkdir(parents=True) + helper._write_mcap(stream/'segments/000000.mcap',[(1_000_000_000,helper._batch())]) + (stream/'stream.json').write_text(json.dumps({'sourceId':'lsl','streamId':'numeric.stream','modality':'eeg','dataSchemaId':'generic.numeric_batch/1','nominalRateHz':2.0,'units':'V','dimensions':[2]})+'\n') + result=run(package,JobParams(command='all',overwrite_job_id='retained-numeric')) + job=result.job_dir + pngs=sorted(p for p in (job/'figures').rglob('*.png') if p.name!='sync_dashboard.png') + report['figure_paths']=[p.relative_to(job).as_posix() for p in pngs] + report['job_manifest']=json.loads((job/'job_manifest.json').read_text()) + check('current accepted numeric pipeline creates two real channel figures',len(pngs)==2 and all(p.read_bytes().startswith(b'\x89PNG\r\n\x1a\n') for p in pngs)) + before=hashes(package) + app=QApplication([]);theme.apply_theme(app,setting='dark');screen=AnalysisScreen(CaptureState());screen.resize(1280,820) + direct=FigureGallery();direct.resize(900,620) + def receive(): + try: + screen.set_package(str(package));screen.show();screen._history._open.click() + check('history explicitly selects the retained numeric job',screen._history.loaded_job_id=='retained-numeric' and screen._last_job_dir==str(job)) + check('inspector receives that saved manifest', 'job_id=retained-numeric' in screen._inspector._meta.text()) + history_tabs=[screen._gallery._tabs.tabText(i) for i in range(screen._gallery._tabs.count())] + report['history_gallery_tabs']=history_tabs + check('history gallery presents both existing numeric channel figures',screen._gallery._tabs.count()-1==len(pngs)) + direct.load_job_dir(job) + report['direct_gallery_tabs']=[direct._tabs.tabText(i) for i in range(direct._tabs.count())] + check('unchanged direct gallery reproduces the same omitted numeric figures',direct._tabs.count()==1 and report['direct_gallery_tabs']==history_tabs and len(pngs)==2) + check('native history browsing starts no computation thread',screen._thread is None) + check('native viewing preserves every generated and captured byte',hashes(package)==before) + screen.grab().save(str(out/'numeric-history-gap.png')) + except BaseException:report['errors'].append(traceback.format_exc()) + finally:screen.close();direct.close();app.quit() + QTimer.singleShot(0,receive);loop_code=app.exec() + screen.deleteLater();direct.deleteLater();QCoreApplication.sendPostedEvents(None,QEvent.Type.DeferredDelete);app.processEvents() + report.update({'event_loop_exit':loop_code,'pyside6':PySide6.__version__,'python':sys.version,'package_hashes':before,'fixture_helper_sha256':hashlib.sha256(fixture_path.read_bytes()).hexdigest()}) + status=0 if not report['errors'] and all(c['passed'] for c in report['checks']) else 1 + except BaseException:report['errors'].append(traceback.format_exc()) + report['source_unchanged']=hashes(source)==expected + report['exit_code']=status;report['passed']=sum(c['passed'] for c in report['checks']);report['failed']=sum(not c['passed'] for c in report['checks']) + (out/'receipt.json').write_text(json.dumps(report,indent=2)+'\n') + print(json.dumps({k:report[k] for k in ['passed','failed','source_unchanged','exit_code']})) + return status + + +if __name__=='__main__':raise SystemExit(main()) diff --git a/docs/evidence/analysis-history-401c5d17da79/current-numeric/numeric-run/numeric-history-gap.png b/docs/evidence/analysis-history-401c5d17da79/current-numeric/numeric-run/numeric-history-gap.png new file mode 100644 index 00000000..478f1af2 Binary files /dev/null and b/docs/evidence/analysis-history-401c5d17da79/current-numeric/numeric-run/numeric-history-gap.png differ diff --git a/docs/evidence/analysis-history-401c5d17da79/current-numeric/numeric-run/receipt.json b/docs/evidence/analysis-history-401c5d17da79/current-numeric/numeric-run/receipt.json new file mode 100644 index 00000000..bae5c434 --- /dev/null +++ b/docs/evidence/analysis-history-401c5d17da79/current-numeric/numeric-run/receipt.json @@ -0,0 +1,214 @@ +{ + "canonical_main": "0ed1ccaa023a5327495565d59e1dd0b28b2ee5bd", + "author_source": "37443f0d4d5ffa684b5423d58501856cadbe0655", + "runtime_tree": "210832e8a07ccc6dff8ead12e9bf45dde3b31652", + "checks": [ + { + "name": "current accepted numeric pipeline creates two real channel figures", + "passed": true + }, + { + "name": "history explicitly selects the retained numeric job", + "passed": true + }, + { + "name": "inspector receives that saved manifest", + "passed": true + }, + { + "name": "history gallery presents both existing numeric channel figures", + "passed": false + }, + { + "name": "unchanged direct gallery reproduces the same omitted numeric figures", + "passed": true + }, + { + "name": "native history browsing starts no computation thread", + "passed": true + }, + { + "name": "native viewing preserves every generated and captured byte", + "passed": true + } + ], + "errors": [], + "method_sha256": "c6d9c3aaf73e1cfef62c86dc36491440d3d6c6001996f149e2b978c97e2959d8", + "source_inputs_sha256": "2c9e35a372b29e6f4d93e5dd7a844b09fe49129fbf89a5c6e569f984aedaee6b", + "figure_paths": [ + "figures/numeric/source-6c736c/stream-6e756d657269632e73747265616d/channel_0.png", + "figures/numeric/source-6c736c/stream-6e756d657269632e73747265616d/channel_1.png" + ], + "job_manifest": { + "analysisGrids": [], + "captureAnalysisVersion": "0.1.0", + "createdUtc": "2026-10-08T13:22:43Z", + "errors": [], + "evalWindowCount": null, + "featureTables": [ + { + "featureSchemaVersion": 1, + "relativePath": "features/numeric/source-6c736c/stream-6e756d657269632e73747265616d/windows.parquet", + "rows": 3 + } + ], + "gapPolicy": "mask", + "gapSummary": { + "closed": 0, + "maskedNs": 0, + "open": 0, + "validFraction": null + }, + "jobId": "retained-numeric", + "kinematicsRows": null, + "manifestSha256": "399b408a7bcb1cbee8062a926f52b2ceff553fdbf4504d92a629b83898eb4b60", + "mlBundleWindowCount": null, + "modalities": [ + "eeg" + ], + "outputs": [ + { + "bytes": 254, + "kind": "params", + "relativePath": "params.json", + "sha256": "962d5067fb396fca7a5d207bae2aeff4ea16f3218396824de0da670f16b67dc3" + }, + { + "bytes": 1127, + "kind": "qc_json", + "relativePath": "reports/qc.json", + "sha256": "6a7e1c4191f43ce87c04344f81d4b4ffa61b2fa383de413650bdcc02a21b3ba2" + }, + { + "bytes": 2214, + "kind": "qc_html", + "relativePath": "reports/qc.html", + "sha256": "43b9cfbc29c185464e85873ac6c4bfd45a0fa3d45f259d7ea59dcae9464625e5" + }, + { + "bytes": 5358, + "kind": "feature_parquet", + "relativePath": "features/numeric/source-6c736c/stream-6e756d657269632e73747265616d/windows.parquet", + "sha256": "b25e995662e343e5660be848fac61eac15dd63d904ea1fa8d4b58fe66dc68b84" + }, + { + "bytes": 307, + "kind": "feature_csv", + "relativePath": "features/numeric/source-6c736c/stream-6e756d657269632e73747265616d/windows.csv", + "sha256": "9cae194fe5eabbdd3d804b734e609ea732d05f9b5885f6e51dcea9f5840230fe" + }, + { + "bytes": 38048, + "kind": "figure", + "relativePath": "figures/numeric/source-6c736c/stream-6e756d657269632e73747265616d/channel_0.png", + "sha256": "255a352977baf12c5714f71c327cac9ec6fe96377378e7d789433de6335bc73a" + }, + { + "bytes": 38330, + "kind": "figure", + "relativePath": "figures/numeric/source-6c736c/stream-6e756d657269632e73747265616d/channel_1.png", + "sha256": "ae7fd0d484e1dd7756a3a0c599de8aea09ede34d0ad1644775c0b95bce3f6195" + }, + { + "bytes": 2691, + "kind": "feature_schema", + "relativePath": "features/_schema.json", + "sha256": "ea7b96fa667e83b0379515745ee23e659bd640497378b04c267da593d584e264" + }, + { + "bytes": 32213, + "kind": "figure", + "relativePath": "figures/sync_dashboard.png", + "sha256": "e801135335d3a6e50353d82b039a14217f7fe6f931a1f9daa1f37de3ab0e6b02" + }, + { + "bytes": 540, + "kind": "sync_series", + "relativePath": "figures/sync_dashboard_series.json", + "sha256": "1bc0a860646508a6001aed0d312d42338f8b2e9c93592cf5adc7dbeab2277554" + }, + { + "bytes": 4166, + "kind": "manifest", + "relativePath": "job_manifest.json", + "sha256": "a3fa5a3115667361cbaa2ad0b701b50f37a9096b8f5391f9bd7f846bce2447ae" + } + ], + "packagePath": "/dev/shm/hamon-401c5d17da79-capture-history-pr/latest-boundary/numeric-run/numeric.mmsession", + "packageState": "sealed", + "paramsDigest": "fbbd87f4d0bdf05be752987d8e20dfb29df32e3da588706e698f21aa5567f604", + "pluginIds": [ + "emg.envelope.v1", + "imu.kinematics.v1", + "radar.rd_energy.v1", + "radar_doppler.mag.v1", + "video.timing_qc.v1", + "numeric.basic.v1", + "test.dummy.feature.v1" + ], + "pluginManifestVersion": "1.0.0", + "poseJobId": null, + "poseModelId": null, + "poseTables": [], + "schemaId": "capture.analysis_job/1", + "sessionId": "history.numeric.current", + "sourcesSelected": [ + "lsl" + ], + "status": "completed_with_warnings", + "syncAnchorsApplied": { + "anchors": [], + "applied": false + }, + "timeRange": { + "checkpointIds": [], + "endSessionNs": 4611686018427387903, + "mode": "full", + "startSessionNs": -4611686018427387903 + }, + "tooling": { + "captureAnalysis": "0.1.0", + "matplotlib": "3.11.2", + "numpy": "2.5.3", + "pandas": "3.0.6", + "platform": "Linux-6.18.44-x86_64-with-glibc2.39", + "python": "3.12.14", + "scipy": "1.18.1" + }, + "warnings": [ + "package state is 'sealed' (prefer finalized)", + "package duration_ns is unknown/zero \u2014 analysis uses an open time window (integrity entries lack endSessionTimeNs)" + ] + }, + "history_gallery_tabs": [ + "Sync" + ], + "direct_gallery_tabs": [ + "Sync" + ], + "event_loop_exit": 0, + "pyside6": "6.11.2", + "python": "3.12.14 (main, Aug 25 2026, 14:00:49) [Clang 22.1.3 ]", + "package_hashes": { + "manifest.json": "399b408a7bcb1cbee8062a926f52b2ceff553fdbf4504d92a629b83898eb4b60", + "processing/jobs/retained-numeric/features/_schema.json": "ea7b96fa667e83b0379515745ee23e659bd640497378b04c267da593d584e264", + "processing/jobs/retained-numeric/features/numeric/source-6c736c/stream-6e756d657269632e73747265616d/windows.csv": "9cae194fe5eabbdd3d804b734e609ea732d05f9b5885f6e51dcea9f5840230fe", + "processing/jobs/retained-numeric/features/numeric/source-6c736c/stream-6e756d657269632e73747265616d/windows.parquet": "b25e995662e343e5660be848fac61eac15dd63d904ea1fa8d4b58fe66dc68b84", + "processing/jobs/retained-numeric/figures/numeric/source-6c736c/stream-6e756d657269632e73747265616d/channel_0.png": "255a352977baf12c5714f71c327cac9ec6fe96377378e7d789433de6335bc73a", + "processing/jobs/retained-numeric/figures/numeric/source-6c736c/stream-6e756d657269632e73747265616d/channel_1.png": "ae7fd0d484e1dd7756a3a0c599de8aea09ede34d0ad1644775c0b95bce3f6195", + "processing/jobs/retained-numeric/figures/sync_dashboard.png": "e801135335d3a6e50353d82b039a14217f7fe6f931a1f9daa1f37de3ab0e6b02", + "processing/jobs/retained-numeric/figures/sync_dashboard_series.json": "1bc0a860646508a6001aed0d312d42338f8b2e9c93592cf5adc7dbeab2277554", + "processing/jobs/retained-numeric/job_manifest.json": "32dd2883bc55717ef813f36930eed5598124f27fa2a9a7a9817e750cd59bcb6d", + "processing/jobs/retained-numeric/logs/job.log": "7edc38094b8619545017aa8f12c4d0179ab43474343e25d483918f32d48b778a", + "processing/jobs/retained-numeric/params.json": "962d5067fb396fca7a5d207bae2aeff4ea16f3218396824de0da670f16b67dc3", + "processing/jobs/retained-numeric/reports/qc.html": "43b9cfbc29c185464e85873ac6c4bfd45a0fa3d45f259d7ea59dcae9464625e5", + "processing/jobs/retained-numeric/reports/qc.json": "6a7e1c4191f43ce87c04344f81d4b4ffa61b2fa383de413650bdcc02a21b3ba2", + "sources/lsl/streams/numeric/segments/000000.mcap": "f3df8e3cc95f76462c502935aad5abafd4392ed3224c239775650c5b49bcd18f", + "sources/lsl/streams/numeric/stream.json": "1adfb22cb81843c0e5bef319c9c2268ea2746e930232f6d89e154d133e0fa885" + }, + "fixture_helper_sha256": "43369bd0fea48d2c8b7dee1d8128b3bb131b508b7b0a14512fc457fcfdb0ba3c", + "source_unchanged": true, + "exit_code": 1, + "passed": 6, + "failed": 1 +} diff --git a/docs/evidence/analysis-history-401c5d17da79/current-numeric/numeric.stderr.log b/docs/evidence/analysis-history-401c5d17da79/current-numeric/numeric.stderr.log new file mode 100644 index 00000000..09ad4161 --- /dev/null +++ b/docs/evidence/analysis-history-401c5d17da79/current-numeric/numeric.stderr.log @@ -0,0 +1 @@ +This plugin does not support propagateSizeHints() diff --git a/docs/evidence/analysis-history-401c5d17da79/current-numeric/numeric.stdout.log b/docs/evidence/analysis-history-401c5d17da79/current-numeric/numeric.stdout.log new file mode 100644 index 00000000..cb5b3493 --- /dev/null +++ b/docs/evidence/analysis-history-401c5d17da79/current-numeric/numeric.stdout.log @@ -0,0 +1 @@ +{"passed": 6, "failed": 1, "source_unchanged": true, "exit_code": 1} diff --git a/docs/evidence/analysis-history-401c5d17da79/current-numeric/process.json b/docs/evidence/analysis-history-401c5d17da79/current-numeric/process.json new file mode 100644 index 00000000..035a9ec6 --- /dev/null +++ b/docs/evidence/analysis-history-401c5d17da79/current-numeric/process.json @@ -0,0 +1,17 @@ +{ + "command": [ + "/workspace/scratch/234cae4aee53/capturesuite-venv/bin/python", + "-B", + "/dev/shm/hamon-401c5d17da79-capture-history-pr/latest-boundary/check_numeric_gallery.py", + "--source", + "/dev/shm/hamon-401c5d17da79-capture-history-pr/latest-boundary/source", + "--inputs", + "/dev/shm/hamon-401c5d17da79-capture-history-pr/latest-boundary/source-inputs.json", + "--output", + "/dev/shm/hamon-401c5d17da79-capture-history-pr/latest-boundary/numeric-run" + ], + "exit_code": 1, + "seconds": 4.471, + "stdout_sha256": "9d5c3d3907cd95f62cf380cc2b5196c33f183bfdeb5665ad0c3af42f2855eeaa", + "stderr_sha256": "caeb11f6473c6c7125dd27478e588b85ffd6b31784e9adb1371a60f1661eb00f" +} diff --git a/docs/evidence/analysis-history-401c5d17da79/current-numeric/source-inputs.json b/docs/evidence/analysis-history-401c5d17da79/current-numeric/source-inputs.json new file mode 100644 index 00000000..10d5bd06 --- /dev/null +++ b/docs/evidence/analysis-history-401c5d17da79/current-numeric/source-inputs.json @@ -0,0 +1,994 @@ +{ + "canonical_parent": "0ed1ccaa023a5327495565d59e1dd0b28b2ee5bd", + "author_source": "37443f0d4d5ffa684b5423d58501856cadbe0655", + "composition_tree": "210832e8a07ccc6dff8ead12e9bf45dde3b31652", + "files": [ + { + "path": "desktop/capture_desktop/__init__.py", + "mode": "100644", + "git_blob": "48777bd04b62e3b3b877e12311f7257819ab3a07", + "sha256": "8426c94323c4cca0879b8612345e3577d0a75f6239237a28d79d94a42004c3b5", + "bytes": 119 + }, + { + "path": "desktop/capture_desktop/__main__.py", + "mode": "100644", + "git_blob": "f78ccce984b725bf7263407d5b4b2d4c56131433", + "sha256": "8dbad73a7373565a3513ccbb613f11bffdd13a05861c3e8e07392b8d51008aa2", + "bytes": 723 + }, + { + "path": "desktop/capture_desktop/analysis_history.py", + "mode": "100644", + "git_blob": "1b8fd23aee632cc3af19990b9d7685c6a3ed1b5e", + "sha256": "2e0db8cee59ef268d3c91ea0beac7d761d83a3003862841cc9d7f1782fd3543c", + "bytes": 6375 + }, + { + "path": "desktop/capture_desktop/app.py", + "mode": "100644", + "git_blob": "3e6f0d9f31032eb51ddd0ac7deedc3d00d0d386e", + "sha256": "52a6b8d9844d8e0f9f9f1e07f516bf234cf104fdeb85dd5ea5acaa69970235f2", + "bytes": 46414 + }, + { + "path": "desktop/capture_desktop/daemon_link.py", + "mode": "100644", + "git_blob": "620e5a753fbd8448c3a57fcfa6a8b8540ac0bcd0", + "sha256": "ab76628bbe0231c7e5e4d570f2abed01100dddd6a24bb62020b670a6b62427dd", + "bytes": 10899 + }, + { + "path": "desktop/capture_desktop/export_wizard.py", + "mode": "100644", + "git_blob": "b22d0098eb9af3860c654591e411dbab68a0f05d", + "sha256": "fb957ff184109bcb4e379dde30414048e855c93ec390f9b50c7ab603c3cd4e30", + "bytes": 6734 + }, + { + "path": "desktop/capture_desktop/main.py", + "mode": "100644", + "git_blob": "90ad2adebae1f52ffabb889efe43a31dca1b6454", + "sha256": "e61c29a1925f8d85b24438f087dec360a4481a32e0dc2bd8ed8feb6629026e84", + "bytes": 1059 + }, + { + "path": "desktop/capture_desktop/persistence.py", + "mode": "100644", + "git_blob": "2f2da2bfda654009baa0e723465c82c1690a0676", + "sha256": "cdb1fa0094fec72543d5051435850e51d78d79d4bde8d5c83520fa072a2c74c4", + "bytes": 3379 + }, + { + "path": "desktop/capture_desktop/schema_form.py", + "mode": "100644", + "git_blob": "2d5fa62b1448e168e639e3e8879989a3461e1053", + "sha256": "7d825b5dc7566d630f31775df6fcc9def1e916eaff5be17a552bf89f28b3418b", + "bytes": 12206 + }, + { + "path": "desktop/capture_desktop/screen_analysis.py", + "mode": "100644", + "git_blob": "966f89f8cfad679a4a461900569365c50476581b", + "sha256": "98a704e31b14497e012fe5618ad47cc8a772bd2d59775826d71a5bdf41533211", + "bytes": 16407 + }, + { + "path": "desktop/capture_desktop/screen_capture.py", + "mode": "100644", + "git_blob": "b2d3cf05d57484f5efdbb0df85e5f0a065dab3d9", + "sha256": "4e101ddeeaed7f7f2b4ec2ab2e4b1f4f55ebb86f73b394d25cfd2b904cd2572e", + "bytes": 34181 + }, + { + "path": "desktop/capture_desktop/screen_presets.py", + "mode": "100644", + "git_blob": "c143fb87629fb90f656a7a3b4b9f3c136b03f596", + "sha256": "b62d6f4bef6c1f0fc04b9eaf6a8afd1b2eeb17f6ce14946a06b0495ba33d402c", + "bytes": 5230 + }, + { + "path": "desktop/capture_desktop/screen_review.py", + "mode": "100644", + "git_blob": "88a902ca7699faa2964f3fc22ec3348a339905a4", + "sha256": "e5aff59de4b194123ca4c4518b34e7b6103326fbd6b0280e2122d984d01072ec", + "bytes": 7003 + }, + { + "path": "desktop/capture_desktop/screen_settings.py", + "mode": "100644", + "git_blob": "fe6d1e8884b7300e4cb5039b8e86679339e43b4d", + "sha256": "519436946827fac53d0be68270c2929bd1ce615a58b2372e9e3fc10619a7ba6e", + "bytes": 4581 + }, + { + "path": "desktop/capture_desktop/screen_setup.py", + "mode": "100644", + "git_blob": "1df45aac30d63d6ab2e8ddc7efe0db394c513ab1", + "sha256": "01eb01ffffe835fcf5d26120d508800cc3cdac1e91ffaa3d0d2fa669c6326182", + "bytes": 11452 + }, + { + "path": "desktop/capture_desktop/state.py", + "mode": "100644", + "git_blob": "95046ba5ef7f7bbf5685a54b7ae8fd400814148c", + "sha256": "97fc98498f4553fc7f052d0dc4db992cf2fc136ba7c4405cd275bd156c74e314", + "bytes": 17906 + }, + { + "path": "desktop/capture_desktop/theme.py", + "mode": "100644", + "git_blob": "e309ce92bf66f65ca7c111698e1f536f05e4dca9", + "sha256": "c77f24e1afeb06400385bd0d535800f13dc15d972891e1ff8af504cbe5c818f3", + "bytes": 12072 + }, + { + "path": "desktop/capture_desktop/widgets_analysis_history.py", + "mode": "100644", + "git_blob": "8798627cd7d694c5a09c3c402a739a4ec45b6574", + "sha256": "a3b77c87483c1412b50de7ddde1498f6bfd3968002fc3ac3bfa474a2477d9bc4", + "bytes": 8458 + }, + { + "path": "desktop/capture_desktop/widgets_analysis_jobs.py", + "mode": "100644", + "git_blob": "c4d2f4513032d744f1f8066f0c887cda71d9b911", + "sha256": "5cdea6045456e61a58b5525dd224a22a140962d31d2adc5b0102168444468f98", + "bytes": 6304 + }, + { + "path": "desktop/capture_desktop/widgets_analysis_plots.py", + "mode": "100644", + "git_blob": "bb6c3033b5e4ed96a2e08857d38715b836926bf5", + "sha256": "85c73f881ee7d60ef2f868f7ff73fc57c0a4ef99a717f7f5015534db23e1ab86", + "bytes": 9382 + }, + { + "path": "desktop/capture_desktop/widgets_mappings.py", + "mode": "100644", + "git_blob": "62dd1b137ffc54a05aa81f37eb8627dd12e0032a", + "sha256": "89808d37cb0fce476665a24766963c7a509f5b1802d05dedbf9ca44351081f4b", + "bytes": 3658 + }, + { + "path": "desktop/capture_desktop/widgets_modality_expanded.py", + "mode": "100644", + "git_blob": "70d67f7405730707ad67d1da0e71a7e87bf8b68e", + "sha256": "12db25b37e8b2724e5eaabdcb1810aa979633885097b6ec11c33d98a46a83a70", + "bytes": 8566 + }, + { + "path": "desktop/capture_desktop/widgets_preview.py", + "mode": "100644", + "git_blob": "d0a760164a413616ab406a54d81c7b3f9b30d638", + "sha256": "78d79c9af67f7e0cbcee3a3a693a22e72753256ca465bab7edb9c2037822dec4", + "bytes": 27254 + }, + { + "path": "desktop/capture_desktop/widgets_radar_array.py", + "mode": "100644", + "git_blob": "d270e7aa8b36a9a6376cfbd76a46ec6448bb9ae4", + "sha256": "be08874ade0b4d9197ea85cb6ae3b30db75273ddd3c426faaaf28b4f796653a8", + "bytes": 2965 + }, + { + "path": "desktop/capture_desktop/widgets_session_header.py", + "mode": "100644", + "git_blob": "7f3c6e4e78728831fa29c6879cf461ebea5b38ef", + "sha256": "897ad1b241ea6b0582280391c861ae13a5aabe245eb8007283a6f4d5e1fedf27", + "bytes": 3433 + }, + { + "path": "desktop/capture_desktop/widgets_session_timeline.py", + "mode": "100644", + "git_blob": "d85f3c4ea492d587af49ca35c43aa5582806719c", + "sha256": "e7c1c2c679b4d0b0fa338ac0d1a44584d99b321857ab1506bbe2d3b455ded339", + "bytes": 9032 + }, + { + "path": "desktop/pyproject.toml", + "mode": "100644", + "git_blob": "dada23f8692dfda4c7c07fc012608844c7f41ab9", + "sha256": "3646f83dcc0764b3c8cb198b98b03201dc47808bb80bfec4837e329e47bd012f", + "bytes": 552 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/__init__.py", + "mode": "100644", + "git_blob": "67a4fb257b771af771edb4010e573ceeab86a51f", + "sha256": "14cfe6dccd33a0bda74fac3c9339e1a37a3538b2110a8ae6e307801b776eb43a", + "bytes": 497 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/discover.py", + "mode": "100644", + "git_blob": "d5c4fa7e06ac6e9139ebfc78fade90a3df5e451a", + "sha256": "344ee5d7cb0f5e95ac7524a0c1141b0a293bb9445e2bd4789c6736f39cfcb90d", + "bytes": 4023 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/eval/__init__.py", + "mode": "100644", + "git_blob": "140fcb2784c4b73ddf69d21ddccfdcc8191cc0aa", + "sha256": "54661df9ed7d7e0d4b1c2ab5941f107ceb608e4fdfaff810014ef5fad1431fe1", + "bytes": 154 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/eval/job.py", + "mode": "100644", + "git_blob": "95d40a6c28aabcdc311c18e3e195627f29ceb1a7", + "sha256": "a7f2a43c2fc3723c471e42a5532465dc5cfa44d4411c6cf581bba6910603fc57", + "bytes": 3984 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/features/__init__.py", + "mode": "100644", + "git_blob": "e52dc3839105744e19193f8fc8067b818389a20b", + "sha256": "3cdd6c626b6da12b8df56d8ddf35fca27c0a744865965ec01dd89d47da476fa1", + "bytes": 66 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/features/emg.py", + "mode": "100644", + "git_blob": "7f7536500a63ddc8b06774b8da65df8d56cd4f2b", + "sha256": "11f8f8350464b7c7c079353ca649b4c4aad2580ef8d355fe741c025c262b168e", + "bytes": 3072 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/features/imu.py", + "mode": "100644", + "git_blob": "0ee47b3d579e4c3732634958dda21ae724beca9e", + "sha256": "246bfd1cc3ce72afa0680537062b6795e22b8a06ba6301503d7489a4440c6849", + "bytes": 2605 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/features/io.py", + "mode": "100644", + "git_blob": "b998063a5036b73a67b773f70c193b1f9827c248", + "sha256": "c677d209292cca790ccdf1a64ba834f71a078ccce31ea57452e67ece358822ca", + "bytes": 1409 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/features/numeric_batch.py", + "mode": "100644", + "git_blob": "77f19ccb048c93c0f4fca460eef0502180b37717", + "sha256": "ecdeb88ca4dd093b973294a53954e9fa0e5d6b4b908225a52d097ef70c7d2154", + "bytes": 4030 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/features/radar_doppler.py", + "mode": "100644", + "git_blob": "ee20f7314cb1af4512901d6009f73e3dddf9025c", + "sha256": "cffc0ecbb8053fbc2244850c1927469366f4ae93b5439e4d194de2065877fa5c", + "bytes": 2289 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/features/radar_frame.py", + "mode": "100644", + "git_blob": "e798dee0fb72dd261b504a99ac76f815515dda9e", + "sha256": "f85c5fe5e2db68606f68e36a42a0c8f323086f0b1e7f233c0ddefa24cdccb443", + "bytes": 3323 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/features/video_qc.py", + "mode": "100644", + "git_blob": "fa73c80d39a0d699f80d7e877b37167cf8b48b6a", + "sha256": "0e25c50e01fc2da47bc7b510d68ba3e72aba33d3e1c79c57b727f5c55c723e27", + "bytes": 1766 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/grids.py", + "mode": "100644", + "git_blob": "2e03f79d9317d2d97b721321130a9a5e6212b111", + "sha256": "936c5404783145f7a2bc4c13df22d3b85612bcb227115bba74f0b78a11c0c483", + "bytes": 1007 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/jobs.py", + "mode": "100644", + "git_blob": "7badee5cdf5a4b30a283e0dcbb2c5d85fb787489", + "sha256": "e7e9dda44eb014d18192563f1e2c0ae78cece850fbc853b0be3919daaf5ee276", + "bytes": 19627 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/kinematics/__init__.py", + "mode": "100644", + "git_blob": "aaf360b8a0085f89b95cd976857f0933596098a7", + "sha256": "50a0f7fd39648abf269fc549d2c17eb48b1dc9add10ebdb76edc1935d6f80160", + "bytes": 178 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/kinematics/compute.py", + "mode": "100644", + "git_blob": "928751e9c861e2b0da298214269e57111f492865", + "sha256": "6e3ca19bfda0c02877f5d778f0c1191b5aebad605373732ef182bd714dd7f086", + "bytes": 6899 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/kinematics/job.py", + "mode": "100644", + "git_blob": "fb8be113d8699427072f6dbcdae222a37738ac18", + "sha256": "d676e84f54aa1ae2b0f998c2cb37c4e02541c1fd0e3464e38e9865c0049a7239", + "bytes": 4523 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/kinematics/registry.py", + "mode": "100644", + "git_blob": "a28cfd708c90552401fb0b3157c60f713a06e14f", + "sha256": "1e53fb9da4c6a2743bc1a3f0e687d94599cf995d33f2a2555e0ce5ebc3966d48", + "bytes": 1155 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/loaders/__init__.py", + "mode": "100644", + "git_blob": "eb6fae21d4bb79055f8d1af1528e846020f21459", + "sha256": "2d51c509baf3c0b5c33360637d12e5ce3c7507a859e4f37030f2c3d711ef0b3d", + "bytes": 361 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/loaders/base.py", + "mode": "100644", + "git_blob": "941a6aa3cea6777f90534ea634cccf8fdd319a3f", + "sha256": "696093b31f22d2bef32fc2962c7a11249a590a0b4d776c40cef4edcbc1e48a97", + "bytes": 2461 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/loaders/emg.py", + "mode": "100644", + "git_blob": "c35d22af7bdeea570e6ae45a713428627e90894c", + "sha256": "86eb7114be689cdbd2edd76affa2994e7278714916692a35381abd02ba9d599a", + "bytes": 3089 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/loaders/imu.py", + "mode": "100644", + "git_blob": "8823f04bd089789ca4cbff6602154bf066d4161d", + "sha256": "5ea4747145bf5588974dfd72c834766436c5a2bc0d58d34ace0f8ef403b310d6", + "bytes": 2773 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/loaders/mcap_iter.py", + "mode": "100644", + "git_blob": "b61ca0a914e4d3909790839774327aa5824c1b71", + "sha256": "03a418e7689840e378665aac92c42769dd14ba2c88a821a5cbf0cee80766540c", + "bytes": 1196 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/loaders/numeric_batch.py", + "mode": "100644", + "git_blob": "668e5397d6a603d8665fe639b3218128bbda72c2", + "sha256": "7c84c0425c1b9b821df711f4c40ea89ac13f267dbe6472922eb41a9263e4835c", + "bytes": 7139 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/loaders/radar_doppler.py", + "mode": "100644", + "git_blob": "fc87bfb7fbbeb98ad8d5d11b3438b2d04882de6c", + "sha256": "4942d08eb47229839e339ce7f2f8a64aee7e5fab44bac77029fcd7a3e3e490c1", + "bytes": 1539 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/loaders/radar_frame.py", + "mode": "100644", + "git_blob": "a44af5392ba2b5b8b64de685f42772b141f1b8b1", + "sha256": "d071f9d95b371798974698fd0caa1fc4c865a85fb772232fd43e7227b15fad2b", + "bytes": 1828 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/loaders/video.py", + "mode": "100644", + "git_blob": "6a192cd5999b45df08c666b9dad21dc29cf91824", + "sha256": "3c3e873ab641904a39ca649dac39072f11948031d068cc21ee459e996d1fc185", + "bytes": 2200 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/ml_bundle/__init__.py", + "mode": "100644", + "git_blob": "619d634ebf6fcc82a7871ad9c463660a24fd65ae", + "sha256": "e785a2e3bf65852018d811b38ecbaf6ff9c479648025789145218809dd50d8a1", + "bytes": 179 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/ml_bundle/job.py", + "mode": "100644", + "git_blob": "59c2e4df46aa041e48aaf7184a3dd0ba345aff6d", + "sha256": "c14c74760e20c818ce5e2428d0b03a8a949899b0bba6c46e37fa8fd797631c75", + "bytes": 9419 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/pipeline.py", + "mode": "100644", + "git_blob": "8113ab4cb51678a122bbb702a23f2200c9333233", + "sha256": "e8c0152040ba5b5f3f37ac53fb5188bac9dd9aaf0d5816d6a718be505c20898c", + "bytes": 5262 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/plots/modality.py", + "mode": "100644", + "git_blob": "1de343cc2e11e663501ba190441325d5637d1492", + "sha256": "bc3aa15ee79d50280a6c9d6aa144fe0519f85dd2c74a0cfa99323f7d57ecd28d", + "bytes": 2419 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/plots/style.py", + "mode": "100644", + "git_blob": "3725e840e5eb046accea79d4b6376f902392dac8", + "sha256": "231e7b1c998f4349d5859295007235ffd41848f12fbb7819193bec9630cd3942", + "bytes": 1249 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/plots/sync_dashboard.py", + "mode": "100644", + "git_blob": "828204e998a46b9571b3a2b3ba08acd9fc6caa31", + "sha256": "6f9e0c64193688eb841565729b9d1e9a64136779e892419acabdc81591afd3d5", + "bytes": 1149 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/plugins/__init__.py", + "mode": "100644", + "git_blob": "39c9c93eab1f5abf65ea73299c34b05ec184dd63", + "sha256": "c511d4b9cd1cda042b781b06fbb02d2d99004de214735d6daeb459d6e41381fe", + "bytes": 225 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/plugins/dummy.py", + "mode": "100644", + "git_blob": "0152651c271234bf38252bed51efda3a3fc19c0f", + "sha256": "facf059d247bca44f2697383e12cc1296b1d1d12bede1196f4a52a1352d60495", + "bytes": 1618 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/plugins/handlers.py", + "mode": "100644", + "git_blob": "03c8589064dfc4c6cfec6e4d00b7f46b10014414", + "sha256": "9be2e1820529b94e54d06790d53aa94cf658f982efb4063c6b64f9d07acc4b2e", + "bytes": 10646 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/plugins/manifest.yaml", + "mode": "100644", + "git_blob": "0628968ee3965170b486306f974c81dd4eb84a53", + "sha256": "1efe3ee2d9eeeeac03c2c03c582edf0119c9abd6d214dfdca3d827fa10a5c048", + "bytes": 3876 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/plugins/numeric.py", + "mode": "100644", + "git_blob": "d8adbc1d90dbfdeac0cd9179c95f027532c1a5d4", + "sha256": "75b55cb453095ad5470ce2532b65d3dce771e6a2f8ad1e46a538b4291fa4cf93", + "bytes": 3390 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/plugins/registry.py", + "mode": "100644", + "git_blob": "3c582e1ab0de2b22956ac47fb628227eacdd1faf", + "sha256": "33a4d07600db8b116fbd46b67492f62129df513df5b66a2c455dced0b2a9dc69", + "bytes": 5389 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/pose/__init__.py", + "mode": "100644", + "git_blob": "108be2956adfed6328f397d88a3b61ebada0ac48", + "sha256": "d58a03cae86259b2cb0ecd0a5ce2347c6824f14cfea6871c94d76acc3541a380", + "bytes": 156 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/pose/job.py", + "mode": "100644", + "git_blob": "1a1a3f2436b0ac8decc551f84e76fa6c4c6e602d", + "sha256": "1f4c44f443c07e22e8c9ca877232c6780c4b1da7834d5565b82cf547b2f4c439", + "bytes": 6262 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/qc.py", + "mode": "100644", + "git_blob": "530b86af1247599c127e2d0c3fa5e4d7d12169f6", + "sha256": "f24e0593a3723311d41054aef40b56c4bb46d4f3ba5ef4b01afcae3a6cc4440a", + "bytes": 9187 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/report_html.py", + "mode": "100644", + "git_blob": "bb8032024cfce30c6fe9a2bd2c13b0d2cbc2d102", + "sha256": "f2c89c7faf6e4edc265540140272396b4195eb5aed9edf05c4912aac74286f03", + "bytes": 4716 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/types.py", + "mode": "100644", + "git_blob": "2adf26816e0ef9e84e6763cf8bbff69d64697949", + "sha256": "e7996d02483f69265a2ef2ec0b28078c86f4f479daa53e38faf8b4a62645d02c", + "bytes": 3428 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/version.py", + "mode": "100644", + "git_blob": "d04b8cc1dd9271ca3ccf836d97436d9a961417c6", + "sha256": "9e25143344b110699f68b6acdbef49576fc91c2cbda34956d7e2cb85bbbc4ae3", + "bytes": 62 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/windows.py", + "mode": "100644", + "git_blob": "80bea6bd69365a48c5b204c26d054b8ae179437a", + "sha256": "af40235d55341d2a6b11d7f67a0195779676301fa822b2bd05240d138ee28c50", + "bytes": 5618 + }, + { + "path": "libs/python/capture_analysis/pyproject.toml", + "mode": "100644", + "git_blob": "6db8b1158b14da660128d7ac0ceacb45b8eb9924", + "sha256": "84cd96465e48439bdd81f5fa126fea5da11ee7587b488bfaaa67a4cd8f760c75", + "bytes": 677 + }, + { + "path": "libs/python/capture_protocol/LICENSE", + "mode": "100644", + "git_blob": "d645695673349e3947e8e5ae42332d0ac3164cd7", + "sha256": "cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30", + "bytes": 11358 + }, + { + "path": "libs/python/capture_protocol/NOTICE", + "mode": "100644", + "git_blob": "7f9ac0678aa56452f06e6e5f3badc9a873e2008a", + "sha256": "3efb470f58c900a58deaef889527e074206274b0fd5fb0e2e62613c093064307", + "bytes": 124 + }, + { + "path": "libs/python/capture_protocol/capture_protocol/__init__.py", + "mode": "100644", + "git_blob": "0e7ab2cf8689d3adbc689c283e8a23d12607b2d0", + "sha256": "556f474a3d740adc03c40426acde432ab7a394b947f8268bd90eecc7832dff8a", + "bytes": 698 + }, + { + "path": "libs/python/capture_protocol/capture_protocol/codec.py", + "mode": "100644", + "git_blob": "3034065efca2c52e34c3e67e147bdda526d2c8db", + "sha256": "f6c09246a7b165358835e51b99b1508e68d840f4bdbd54b5fb72db33d4912712", + "bytes": 7011 + }, + { + "path": "libs/python/capture_protocol/capture_protocol/config_schema.py", + "mode": "100644", + "git_blob": "c9b4a694e620e5597d338230fcb0f25ea3a757f6", + "sha256": "00d855895faec7d674cdb8e4da1ddc687888c9e9863f91d4950d24d9fb815e6e", + "bytes": 8444 + }, + { + "path": "libs/python/capture_protocol/capture_protocol/constants.py", + "mode": "100644", + "git_blob": "2542cda6bdb6a83d4334336f34d92f80040bc4a0", + "sha256": "7f187edf873cd13f55bc09ff7972785797eb488d74dd5befcb395fc928a71d72", + "bytes": 486 + }, + { + "path": "libs/python/capture_protocol/capture_protocol/control_client.py", + "mode": "100644", + "git_blob": "45e1c4b535ece8d7178cd6b32ab1affcc9e73e92", + "sha256": "68de412465b2eaa04886a2bb4566aa0595c898df7d7e782b3031b8ba919db7fa", + "bytes": 20823 + }, + { + "path": "libs/python/capture_protocol/capture_protocol/framing.py", + "mode": "100644", + "git_blob": "9dd5021b815b31ab02eaaa814210525ebb543862", + "sha256": "3ff7c7284d9907a2ad516c83fab383a4151996da3f2d5a1d27e24d7c7575d92e", + "bytes": 2884 + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/__init__.py", + "mode": "100644", + "git_blob": "16ae7d90a122b4973139c563ac0f72efa061b1de", + "sha256": "1fac8216894ce1a1b5362de3b59398fbd78f005a59636aea9f074951bed5c1d7", + "bytes": 90 + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/__init__.py", + "mode": "100644", + "git_blob": "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", + "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "bytes": 0 + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/__init__.py", + "mode": "100644", + "git_blob": "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", + "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "bytes": 0 + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/arrays_pb2.py", + "mode": "100644", + "git_blob": "a29ed506c4dd33f697ba74d13b6e8a9c945c6b6d", + "sha256": "6355750076724275e49f9a5faec383b2be92c0336ed58805a88954964bd13b86", + "bytes": 2876 + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/common_pb2.py", + "mode": "100644", + "git_blob": "66031212a0da44800dcc671b0d4bf0cd39e71f06", + "sha256": "6736e3b86b3c8749d34065794da1c880772ce69e2f248fdd2febd003f083bbd3", + "bytes": 9746 + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/control_pb2.py", + "mode": "100644", + "git_blob": "0597489cf8609a76e2094270965039da9b739ca3", + "sha256": "f2eea386aebf830ec47fa7379e6fb0493e0a199efecc7b90974bc8bb8c8b96b6", + "bytes": 20028 + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/data/__init__.py", + "mode": "100644", + "git_blob": "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", + "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "bytes": 0 + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/data/emg_batch_pb2.py", + "mode": "100644", + "git_blob": "d8495ebeb8ab140824eaa5412be0779cf929ec6a", + "sha256": "1db5ef51143a546072e34cc7be7b263db996fa5f4d0d71606b230cb75b531a14", + "bytes": 1624 + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/data/imu_frame_pb2.py", + "mode": "100644", + "git_blob": "54bbf93dc638cdab95f49744ea7e0b43fefad374", + "sha256": "4a2048d2a737362bf26b99166e95c457d1492fcfba8848c894fe4d2748ff9f51", + "bytes": 2222 + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/data/numeric_batch_pb2.py", + "mode": "100644", + "git_blob": "beedaaae054bfb083af3642c96ca7c64af14cc8d", + "sha256": "a087cc019b9849f4ef47bcdf4c789a7da90d443240b7bef97c832bb23c1d4e24", + "bytes": 1454 + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/data/radar_doppler_pb2.py", + "mode": "100644", + "git_blob": "ad8fe84317d2f4049682f70bead19f90c6932457", + "sha256": "d1b85358aba0c2f4fc1745218463e9951224322604b18b068a2195359dcf790e", + "bytes": 1773 + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/data/radar_frame_pb2.py", + "mode": "100644", + "git_blob": "cef636d7b030b037b23331eec9a86f3b152bc358", + "sha256": "995ddbbb0aa614afb15088cf039c741421c33ea3e3e963ef1a7361b24754b862", + "bytes": 1729 + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/data/video_timing_pb2.py", + "mode": "100644", + "git_blob": "17937a141a9a2d81858cf52d74bc4705afc940b7", + "sha256": "002a79858ccd2d7763769a1fe1be6a16a7f6b8727d15f952d191bcd2240ba5ef", + "bytes": 1722 + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/events_pb2.py", + "mode": "100644", + "git_blob": "030bd4a90be609403e7709605607d8d5b993776e", + "sha256": "72951a468b0480e7fefc4fd3f9b4caac5fda0abdadf4ffcca92d4f19286429ce", + "bytes": 5480 + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/health_pb2.py", + "mode": "100644", + "git_blob": "b27bd32ec488168871ca2342062eb576d56a9e8e", + "sha256": "e1e0baa7073a9886e4d982d4f00020b490bfd46c32b1b4df129fd0477c1f5e61", + "bytes": 5898 + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/presets_pb2.py", + "mode": "100644", + "git_blob": "d20925410185e5cf52bbc56e438534c1c5ff1102", + "sha256": "d27336594b548f2e6e7ae212fe6de198e6e699c62a5f27752f691d7928ccb27b", + "bytes": 2066 + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/preview_pb2.py", + "mode": "100644", + "git_blob": "cb04387df1614a8b9d9755a702129bbbb8d6374e", + "sha256": "c992e91b9aef0aa0ec8d595eba2f7079889264d9e4de120b623afd1d8702c695", + "bytes": 5333 + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/project_pb2.py", + "mode": "100644", + "git_blob": "a8e71f0a426858cc679cb87ce31d1379e70a2817", + "sha256": "983bc5715147297cdcecca343b9a450f2095fcc1e895859cc3c52a3213d933f5", + "bytes": 3355 + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/source_pb2.py", + "mode": "100644", + "git_blob": "b72752efedc743d236713e51283dce923a526f55", + "sha256": "d15b443f27c910c0e809af19fed81d9c1a75f7112501df85877bf4bf9bc4f7a8", + "bytes": 8053 + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/storage_pb2.py", + "mode": "100644", + "git_blob": "4dd1b48ab16900c5c3e88d9788cebf83ee93cc5a", + "sha256": "f7a7b8903af9bfc2d2a419622c86cc057aed2a898949e4261475a7ac61222474", + "bytes": 5487 + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/worker_pb2.py", + "mode": "100644", + "git_blob": "7f3a4fc372384523638853f4bd458f49b664ba70", + "sha256": "112e832172913024c6fad128a9a9559bbcd14b18de06b1f2a3161ac380258dc0", + "bytes": 11165 + }, + { + "path": "libs/python/capture_protocol/capture_protocol/handshake.py", + "mode": "100644", + "git_blob": "9386e73b3c1eecb683d9d0ca98ad415268e307af", + "sha256": "63f740c992edf8812f666b79f9cd866d9ea33e65e5b310a5ebda2f5ef98ac115", + "bytes": 4763 + }, + { + "path": "libs/python/capture_protocol/capture_protocol/structured_log.py", + "mode": "100644", + "git_blob": "fc9c97b288280f4473c6b3c5b5e6ff07332fad49", + "sha256": "3d7883833286ecc004248294badcc0c66e44a57ecb7844ef281828d797b3c4fc", + "bytes": 4657 + }, + { + "path": "libs/python/capture_protocol/pyproject.toml", + "mode": "100644", + "git_blob": "fa71ca45874d34076208507180c69c7a0e38fa76", + "sha256": "61b2e33b2de2a153fb994144f532402c1b6b8ed02afb627ba0a15239e726ca71", + "bytes": 355 + }, + { + "path": "libs/python/capture_session/capture_session/__init__.py", + "mode": "100644", + "git_blob": "894e3c152a98b6e804de90122572afbcd929b3da", + "sha256": "da530f86c0d1d584862868ddba9f7087ccf5dfbddd64dd1e577337ecfd776419", + "bytes": 2412 + }, + { + "path": "libs/python/capture_session/capture_session/app_paths.py", + "mode": "100644", + "git_blob": "46332cea7c62dd44247b219937ae6c8fbc747017", + "sha256": "363e4522240e2356cac7492589cb207a798bc1af6031139bd1fa94890f1c4bfd", + "bytes": 561 + }, + { + "path": "libs/python/capture_session/capture_session/package_reader.py", + "mode": "100644", + "git_blob": "91fbf913c5af8489968425d7ceac51c04233d3e0", + "sha256": "9a1d9e6e7d24341a083cee602af9538413e948f3369b22660e484356e3d34eb1", + "bytes": 6331 + }, + { + "path": "libs/python/capture_session/capture_session/registry.py", + "mode": "100644", + "git_blob": "c1d7799e1d2099424221b2f4af216a43a972c67a", + "sha256": "809b26ce8d8efc0559a3854cf85ea74b4e486fcd77d253ebfa76bade64b0a8d1", + "bytes": 13989 + }, + { + "path": "libs/python/capture_session/capture_session/settings_store.py", + "mode": "100644", + "git_blob": "41b99cdaa78011d3d9b753c3131f32c72af9699f", + "sha256": "7719524a1f106cc54befcd21088810f9ec28f0160c8e88f60c374e1545fdb98d", + "bytes": 4622 + }, + { + "path": "libs/python/capture_session/pyproject.toml", + "mode": "100644", + "git_blob": "c83450d780e97e5bd90feb48cef140917b6e47ff", + "sha256": "3484887da96d4a2f32de8471b537d849f077b195c729ff0cc29307681e8d4895", + "bytes": 389 + }, + { + "path": "libs/python/capture_worker/LICENSE", + "mode": "100644", + "git_blob": "d645695673349e3947e8e5ae42332d0ac3164cd7", + "sha256": "cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30", + "bytes": 11358 + }, + { + "path": "libs/python/capture_worker/NOTICE", + "mode": "100644", + "git_blob": "d74f1cbf89d4c89f70b3e75ab71cfadea8b7128f", + "sha256": "2a7e69c4c7cd4e93a5cc9e9f984873a2d1276f465b91b10c71b951ebcfb2c588", + "bytes": 142 + }, + { + "path": "libs/python/capture_worker/capture_worker/__init__.py", + "mode": "100644", + "git_blob": "4bf1fc6b13bc4f5daab79d937ea89cf6c120cce3", + "sha256": "c7ba88e956df8460002637eb3d8678a4c7217e680a388f833a22f073dc80f8fd", + "bytes": 503 + }, + { + "path": "libs/python/capture_worker/capture_worker/__main__.py", + "mode": "100644", + "git_blob": "a1047121f4173802074eeb66e5dcaf6c542c29c1", + "sha256": "216422b76731bc985daa5fb0efe55a9d5ce600aa7e6081fa3df0c03afb6a893e", + "bytes": 150 + }, + { + "path": "libs/python/capture_worker/capture_worker/cli.py", + "mode": "100644", + "git_blob": "eb2d869f951f0205085b074d067282990657b5a0", + "sha256": "8a16c4cae0ffd11d4f9cd5d168f6abf1c6f9a4b5100e8edd18a29ce7d44d3f03", + "bytes": 1818 + }, + { + "path": "libs/python/capture_worker/capture_worker/preview.py", + "mode": "100644", + "git_blob": "c47abe8a118ea022931843bde802132548194eef", + "sha256": "38b483dc06c9215b73e4c56c222fe563957180a5be58761a2c6dd4ea200b8e31", + "bytes": 3202 + }, + { + "path": "libs/python/capture_worker/capture_worker/transport.py", + "mode": "100644", + "git_blob": "2e5e159bee3a0b5aa69bf90f62906feeffe23c8c", + "sha256": "020414c74bd08ec510e88da8c2f8b9ec5091a19cb585b4c54d2656b4bf300d35", + "bytes": 5033 + }, + { + "path": "libs/python/capture_worker/capture_worker/worker.py", + "mode": "100644", + "git_blob": "d5ed2999fbb958116d73a8fa6319356d8b7d751a", + "sha256": "19a0dfd16a65479de884d4359a3d65f1bc127d8a6d4b44b93c6251757510de68", + "bytes": 23439 + }, + { + "path": "libs/python/capture_worker/capture_worker/writer.py", + "mode": "100644", + "git_blob": "b3d194cc71dfa0d21884936a6ed5f7bdc95b3eb4", + "sha256": "b9e3b21ac26f2160da582a3f566a278dc4088c5a8b121d9b4e74f8d8c16cf96f", + "bytes": 6196 + }, + { + "path": "libs/python/capture_worker/pyproject.toml", + "mode": "100644", + "git_blob": "5d79642edc9c1809fda636d5dcd78ad33e67abcc", + "sha256": "0cba218b59a756185fedf72fb3a3307d1d9cb9218b6189ea92972d3cec139a46", + "bytes": 487 + }, + { + "path": "pyproject.toml", + "mode": "100644", + "git_blob": "52491c6beebc4b17983fc66bb8765154c33cf6d8", + "sha256": "0cb8de1ab3dfbfed84ff16b35f3c89c6440180183ee5851d5d80da83622e53d0", + "bytes": 1233 + }, + { + "path": "tests/analysis/test_numeric_batch_pipeline.py", + "mode": "100644", + "git_blob": "9485adb27d02ab88e65d87576a06b86869a0360b", + "sha256": "43369bd0fea48d2c8b7dee1d8128b3bb131b508b7b0a14512fc457fcfdb0ba3c", + "bytes": 19230 + }, + { + "path": "tests/conftest.py", + "mode": "100644", + "git_blob": "ad9b61fd8e9c1c3d74f91710d4e82dd7d899e6b4", + "sha256": "f669618fad17e906c91df7a1e9393fc7a54f458c6d62a4385436ba2622beca0e", + "bytes": 1773 + }, + { + "path": "tests/fixtures/mini_session/events/annotations.json", + "mode": "100644", + "git_blob": "fe51488c7066f6687ef680d6bfaa4f7768ef205c", + "sha256": "37517e5f3dc66819f61f5a7bb8ace1921282415f10551d2defa5c3eb0985b570", + "bytes": 3 + }, + { + "path": "tests/fixtures/mini_session/events/checkpoints.json", + "mode": "100644", + "git_blob": "fe51488c7066f6687ef680d6bfaa4f7768ef205c", + "sha256": "37517e5f3dc66819f61f5a7bb8ace1921282415f10551d2defa5c3eb0985b570", + "bytes": 3 + }, + { + "path": "tests/fixtures/mini_session/events/sync_anchors.json", + "mode": "100644", + "git_blob": "fe51488c7066f6687ef680d6bfaa4f7768ef205c", + "sha256": "37517e5f3dc66819f61f5a7bb8ace1921282415f10551d2defa5c3eb0985b570", + "bytes": 3 + }, + { + "path": "tests/fixtures/mini_session/integrity.json", + "mode": "100644", + "git_blob": "d10093b866427fcaed78a85e60e600d8657a86a7", + "sha256": "af5d9bacd3eace7e831d48dee83eb5d9f578f4f4819d92218c4b55b0cb3ed556", + "bytes": 227 + }, + { + "path": "tests/fixtures/mini_session/manifest.json", + "mode": "100644", + "git_blob": "800dab5b41774bc043ebdee4714195770e75229b", + "sha256": "c5254d3e4c0bc6a0ecaef124dc12d88117d647928a8e1725b71429097438d380", + "bytes": 235 + }, + { + "path": "tests/fixtures/mini_session/processing/.gitkeep", + "mode": "100644", + "git_blob": "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", + "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "bytes": 0 + }, + { + "path": "tests/fixtures/mini_session/sources/sim.emg.main/health/gaps.jsonl", + "mode": "100644", + "git_blob": "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", + "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "bytes": 0 + }, + { + "path": "tests/fixtures/mini_session/sources/sim.emg.main/source.json", + "mode": "100644", + "git_blob": "9528c95289b4b1b49d11d412b5ab2e3d019b4066", + "sha256": "4e7626e51bfb804c27f83bf98ee186a47ec9f36fec0cbd7863ea8ecb1ecfbd10", + "bytes": 112 + }, + { + "path": "tests/fixtures/mini_session/sources/sim.emg.main/streams/sim.emg.main.batch/segments/000000.mcap", + "mode": "100644", + "git_blob": "320ce3607fadf57d05cf506987d045cf5b62ad9f", + "sha256": "3c4d91b3bf5d48dcf54a598fff5b1b4ee42260b756d6f5df3986da496c6a9649", + "bytes": 28 + }, + { + "path": "tests/fixtures/mini_session/sources/sim.emg.main/streams/sim.emg.main.batch/stream.json", + "mode": "100644", + "git_blob": "12c4db8831572fc4ab3db9ba5f784fa236078e5f", + "sha256": "8f8c02b89fd93e55643151e5222488e1174dd97a6b7a74f3ae5da8215b4d68e1", + "bytes": 216 + }, + { + "path": "tests/fixtures/mini_session/sources/sim.imu.upper/source.json", + "mode": "100644", + "git_blob": "fcc248c52b8319f5e7fd0067763b74640f0040dd", + "sha256": "a6198f509edc557c1e1d8583a767a540962977751c80a1b6491e3d594b60c7a8", + "bytes": 118 + }, + { + "path": "tests/fixtures/mini_session/sources/sim.imu.upper/streams/sim.imu.upper.frames/segments/000000.mcap", + "mode": "100644", + "git_blob": "320ce3607fadf57d05cf506987d045cf5b62ad9f", + "sha256": "3c4d91b3bf5d48dcf54a598fff5b1b4ee42260b756d6f5df3986da496c6a9649", + "bytes": 28 + }, + { + "path": "tests/fixtures/mini_session/sources/sim.imu.upper/streams/sim.imu.upper.frames/stream.json", + "mode": "100644", + "git_blob": "9c634d4af594372063fcc612331ba338ae95f8c9", + "sha256": "ec39026bed1b833d4decb0ef7b0efb94c5557a5647bc50addc060bef3a30d50d", + "bytes": 219 + }, + { + "path": "tests/ui/test_analysis_history.py", + "mode": "100644", + "git_blob": "f013473f750b515a8305e2f7f8426b6520e26a65", + "sha256": "48175547922125c308fa49bbb84149e3dac8903902e7cc64fa7c15b4ca40eccd", + "bytes": 10465 + }, + { + "path": "workers/python_host/capture_sim/__init__.py", + "mode": "100644", + "git_blob": "2646a1792544ac97cba76fd7d7246c313604351e", + "sha256": "a3c8506a26d20b0b10cd55f00b019b7ddc1e2d4cb5cffd5c155d70ef338d21ae", + "bytes": 259 + }, + { + "path": "workers/python_host/capture_sim/advertise.py", + "mode": "100644", + "git_blob": "c93044ce53b7a38d2e7db9fcbad83174b394ffd2", + "sha256": "6a41dafed67d08d4e3829c053dc5a2767ae28293d63733b4b4ae187a8d4a94b9", + "bytes": 15205 + } + ] +} diff --git a/docs/evidence/analysis-history-401c5d17da79/current-qc/README.md b/docs/evidence/analysis-history-401c5d17da79/current-qc/README.md new file mode 100644 index 00000000..014afddc --- /dev/null +++ b/docs/evidence/analysis-history-401c5d17da79/current-qc/README.md @@ -0,0 +1,70 @@ +# Current QC output and saved-history receiving + +The author's runtime `37443f0d4d5ffa684b5423d58501856cadbe0655` +was qualified on canonical `72c15d6b623e217291a824e4e4808a385df896a9`. +Current main `e43da3b855475c8aacf815c201fa03eddaeec0f1` changes no +desktop or session-reader source, but its accepted QC producer now writes +`capture.analysis_qc/2` and HTML with recorded gap rows. This packet closes that +specific changed-input boundary. + +Git's actual three-way merge, using the observed canonical base, produced +runtime tree `ba5b4b925b00ecb17895a8c8ad29410e787f97dc`. It changes only +the three history/runtime files and one focused test relative to current main; +779 unrelated current leaves and their modes remain exact. The publication +adds documentation and evidence after this runtime tree without changing its +Python or fixture bytes. + +## Result + +One real `QApplication.exec` event-loop scenario passed 14 assertions, exit 0, +in 3.471 seconds using the existing Python/PySide6 environment. A private copy +of the existing mini-session fixture receives one authored recorded gap, +then the unchanged current producer creates the retained QC result. + +The receiver confirms the QC/2 schema, exact gap duration of 1,000,000,002 ns +and reported loss count of 3, plus the current HTML gap row. It opens that job +through the actual history controls, existing inspector and read-only Details +dialog; the existing report action is available and no computation thread is +started. All 18 retained package/job files and all 139 frozen source/fixture +files remain unchanged while browsing. + +`current.stderr.log` retains Qt's standard offscreen +`This plugin does not support propagateSizeHints()` message. It contains no +other diagnostic. This is one current-dependency receiving scenario, separate +from the author's 14 tests and the independent receiver's 19 native checks. +It is not a full Windows, daemon, hardware or installed-release qualification. + +## Exact receipts + +| File | SHA-256 | +| --- | --- | +| `check_current_qc_history.py` | `469b3e3fd0403e420c847e1e4c11525b968055447aa2ecdd1024714e2c12039e` | +| `source-inputs.json` | `c41b5857ca1cca774d85298827c8f63a85dada025e2e326b51ce96de08e0ab0e` | +| `current-run/receipt.json` | `e12a6c87e4786a87b2adf5a295e1184d12e4a3ecebad6e4ca6e3b24beb1bd4ec` | +| `current.stdout.log` | `34b2748419db7460c2abff30184db5e7f12b075c1808667abcb065177dfd5025` | +| `current.stderr.log` | `caeb11f6473c6c7125dd27478e588b85ffd6b31784e9adb1371a60f1661eb00f` | + +`process.json` retains the exact command, duration and process result. The +source manifest lists every input's Git blob, mode, byte length and SHA-256. +The fixture mutations are confined to the receiver's newly created directory; +the authored and canonical checkouts are never used as output directories. + +## Replay + +Use an existing Python 3.12 environment with CaptureSuite's dependencies. From +the composed checkout, materialize exactly the files listed by +`source-inputs.json` into a new source projection and verify their hashes. +Preserve their relative paths. Keep output outside that source and choose a +path that does not exist: + +```sh +python -B check_current_qc_history.py \ + --source /absolute/path/to/verified-source-projection \ + --inputs /absolute/path/to/source-inputs.json \ + --output /absolute/path/to/new-private-output +``` + +The companion performs no dependency installation, uses private application +state directories and rejects changed or extra projected source files before +opening a widget. It uses the existing mini-session fixture and current +producer. diff --git a/docs/evidence/analysis-history-401c5d17da79/current-qc/check_current_qc_history.py b/docs/evidence/analysis-history-401c5d17da79/current-qc/check_current_qc_history.py new file mode 100644 index 00000000..7813a9a1 --- /dev/null +++ b/docs/evidence/analysis-history-401c5d17da79/current-qc/check_current_qc_history.py @@ -0,0 +1,159 @@ +# SPDX-License-Identifier: GPL-3.0-only +"""Receive one current QC/2 artifact through the saved native result workflow.""" +from __future__ import annotations + +import argparse +import hashlib +import json +import os +import platform +import shutil +import sys +import traceback +from pathlib import Path + + +def hashes(root: Path) -> dict[str, str]: + return {p.relative_to(root).as_posix(): hashlib.sha256(p.read_bytes()).hexdigest() + for p in sorted(root.rglob('*')) if p.is_file()} + + +def main() -> int: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('--source', type=Path, required=True) + parser.add_argument('--inputs', type=Path, required=True) + parser.add_argument('--output', type=Path, required=True) + args = parser.parse_args() + source, output = args.source.resolve(), args.output.resolve() + if output == source or source in output.parents or output.exists(): + raise ValueError('Output must be a new private directory outside the source.') + manifest = json.loads(args.inputs.read_text()) + expected = {x['path']: x['sha256'] for x in manifest['files']} + assert hashes(source) == expected, 'Input projection must match all frozen files.' + output.mkdir(parents=True, exist_ok=False) + for key, name in [('LOCALAPPDATA', 'local'), ('APPDATA', 'roaming'), + ('XDG_CONFIG_HOME', 'config'), ('XDG_DATA_HOME', 'data'), + ('XDG_CACHE_HOME', 'cache'), ('MPLCONFIGDIR', 'matplotlib')]: + folder = output / 'private-state' / name + folder.mkdir(parents=True) + os.environ[key] = str(folder) + os.environ['QT_QPA_PLATFORM'] = 'offscreen' + os.environ['PYTHONDONTWRITEBYTECODE'] = '1' + sys.dont_write_bytecode = True + for relative in reversed(['desktop', 'libs/python/capture_analysis', + 'libs/python/capture_session', 'libs/python/capture_protocol', + 'libs/python/capture_protocol/capture_protocol/generated', + 'libs/python/capture_worker', 'workers/python_host']): + sys.path.insert(0, str(source / relative)) + + report = {'canonical_main': manifest['canonical_parent'], + 'author_source': manifest['author_source'], + 'composition_tree': manifest['composition_tree'], + 'source_inputs_sha256': hashlib.sha256(args.inputs.read_bytes()).hexdigest(), + 'runner_sha256': hashlib.sha256(Path(__file__).read_bytes()).hexdigest(), + 'python': sys.version, 'platform': platform.platform(), + 'checks': [], 'scope': 'One current-QC/2 to saved-history reader boundary; no worker-thread, Windows, daemon or hardware acceptance.'} + + def check(name: str, value: bool) -> None: + report['checks'].append({'name': name, 'passed': bool(value)}) + assert value, name + + status = 1 + try: + import PySide6 + from PySide6.QtCore import QCoreApplication, QEvent, QTimer + from PySide6.QtWidgets import QApplication, QPlainTextEdit + import capture_analysis.qc as qc_module + import capture_analysis.report_html as html_module + from capture_analysis import JobParams, run + from capture_desktop import theme + from capture_desktop.screen_analysis import AnalysisScreen + from capture_desktop.state import CaptureState + + report['pyside6'] = PySide6.__version__ + check('current QC producer loaded from pinned source', + Path(qc_module.__file__).resolve() == source / 'libs/python/capture_analysis/capture_analysis/qc.py') + check('current HTML producer loaded from pinned source', + Path(html_module.__file__).resolve() == source / 'libs/python/capture_analysis/capture_analysis/report_html.py') + package = output / 'current QC saved.mmsession' + shutil.copytree(source / 'tests/fixtures/mini_session', package) + gap_dir = package / 'sources/sim.emg.main/health' + gap_dir.mkdir(parents=True, exist_ok=True) + (gap_dir / 'gaps.jsonl').write_text(json.dumps({ + 'sourceId': 'sim.emg.main', 'streamId': 'sim.emg.main.batch', + 'cause': 'transport_loss', 'startSessionTimeNs': '1000000001', + 'endSessionTimeNs': '2000000003', 'closed': True, 'estimatedLostCount': '3' + }) + '\n', encoding='utf-8') + result = run(package, JobParams(command='qc', overwrite_job_id='current-qc')) + qc_path = result.job_dir / 'reports/qc.json' + html_path = result.job_dir / 'reports/qc.html' + qc = json.loads(qc_path.read_text()) + check('current producer emits capture.analysis_qc/2', qc['schemaId'] == 'capture.analysis_qc/2') + check('native gap precision retained in generated result', + len(qc['gaps']) == 1 and qc['gaps'][0]['durationNs'] == '1000000002' + and qc['gaps'][0]['estimatedLostCount'] == '3') + check('current generated report includes the recorded gap', + 'Recorded gaps' in html_path.read_text() and 'transport_loss' in html_path.read_text()) + before = hashes(package) + app = QApplication([]) + theme.apply_theme(app, setting='dark') + screen = AnalysisScreen(CaptureState()) + callback_status = [1] + + def receive() -> None: + try: + screen.set_package(str(package)) + check('package selection offers saved result without opening it', + screen._history._jobs.count() == 1 and not screen._last_job_dir) + screen._history._open.click() + check('explicit native Open selects the current result', + screen._last_job_dir == str(result.job_dir) + and screen._history.loaded_job_id == 'current-qc') + check('existing inspector receives current result provenance', + 'job_id=current-qc' in screen._inspector._meta.text()) + check('existing report action is available for the retained current report', + screen._btn_open_report.isEnabled()) + screen._history._details.click() + dialog = screen._history._dialog + check('native result details dialog opens', dialog is not None and dialog.isVisible()) + editors = {w.objectName(): w for w in dialog.findChildren(QPlainTextEdit)} + check('saved parameters and provenance remain read-only', + all(w.isReadOnly() for w in editors.values()) + and json.loads(editors['analysisHistoryParameters'].toPlainText())['command'] == 'qc' + and json.loads(editors['analysisHistoryManifest'].toPlainText())['jobId'] == 'current-qc') + check('browsing starts no computation thread', screen._thread is None) + check('all generated package and job bytes stay unchanged while browsing', hashes(package) == before) + dialog.close() + callback_status[0] = 0 + except BaseException: + report['error'] = traceback.format_exc() + finally: + screen.close() + app.exit(callback_status[0]) + + QTimer.singleShot(0, receive) + loop_status = app.exec() + check('actual QApplication event loop returned successfully', loop_status == 0) + screen.deleteLater() + QCoreApplication.sendPostedEvents(None, QEvent.Type.DeferredDelete) + app.processEvents() + report['package_hashes'] = before + report['artifact_schema'] = qc['schemaId'] + report['artifact_gap'] = qc['gaps'][0] + status = callback_status[0] + except BaseException: + report.setdefault('error', traceback.format_exc()) + finally: + report['source_unchanged'] = hashes(source) == expected + if not report['source_unchanged']: + status = 1 + report['exit_code'] = status + report['passed'] = sum(x['passed'] for x in report['checks']) + report['failed'] = sum(not x['passed'] for x in report['checks']) + (output / 'receipt.json').write_text(json.dumps(report, indent=2) + '\n') + print(json.dumps({k: report[k] for k in ['passed', 'failed', 'exit_code', 'source_unchanged']})) + return status + + +if __name__ == '__main__': + raise SystemExit(main()) diff --git a/docs/evidence/analysis-history-401c5d17da79/current-qc/current-run/artifacts/qc.html b/docs/evidence/analysis-history-401c5d17da79/current-qc/current-run/artifacts/qc.html new file mode 100644 index 00000000..3b390046 --- /dev/null +++ b/docs/evidence/analysis-history-401c5d17da79/current-qc/current-run/artifacts/qc.html @@ -0,0 +1,60 @@ + + + + +QC — mini-analysis-fixture + + + +

Analysis QC

+

+session mini-analysis-fixture · +state finalized · +streams 2 · +gaps open/closed 0/1 · +checkpoints 0 +

+

package: /dev/shm/hamon-401c5d17da79-capture-history-pr/current-boundary/current-run/current QC saved.mmsession

+

manifest sha256: c5254d3e4c0bc6a0ecaef124dc12d88117d647928a8e1725b71429097438d380

+ +

Sources

+ + + +
sourcelight
sim.emg.mainwarn
sim.imu.upperok
+ +

Recorded gaps

+

Times are seconds relative to session T0, with nanosecond precision. +Each row is one reported gap. Loss counts are reported estimates in source-defined units.

+
+ + + + + +
sourcestreamcausestatestart (session s)end (session s)duration (s)estimated lost count
sim.emg.mainsim.emg.main.batchtransport_lossclosed1.0000000012.0000000031.0000000023
+
+ +

Streams

+ + + + +
sourcestreammodalityschemarate Hzunitsmcap/mkv
sim.emg.mainsim.emg.main.batchemgemg.batch/12000.0mV1/0
sim.imu.uppersim.imu.upper.framesimuimu.frame/160.0a.u.1/0
+ +

Warnings

+
  • sim.emg.main: 1 recorded gap(s); see gap details
+ + diff --git a/docs/evidence/analysis-history-401c5d17da79/current-qc/current-run/artifacts/qc.json b/docs/evidence/analysis-history-401c5d17da79/current-qc/current-run/artifacts/qc.json new file mode 100644 index 00000000..b10bccd9 --- /dev/null +++ b/docs/evidence/analysis-history-401c5d17da79/current-qc/current-run/artifacts/qc.json @@ -0,0 +1,65 @@ +{ + "annotationCount": 0, + "checkpointCount": 0, + "closedGapCount": 1, + "durationNs": 10000000000, + "gaps": [ + { + "cause": "transport_loss", + "closed": true, + "durationNs": "1000000002", + "durationStatus": "known", + "endSessionTimeNs": "2000000003", + "estimatedLostCount": "3", + "sourceId": "sim.emg.main", + "startSessionTimeNs": "1000000001", + "streamId": "sim.emg.main.batch" + } + ], + "integrityFileCount": 1, + "manifestSha256": "c5254d3e4c0bc6a0ecaef124dc12d88117d647928a8e1725b71429097438d380", + "openGapCount": 0, + "packagePath": "/dev/shm/hamon-401c5d17da79-capture-history-pr/current-boundary/current-run/current QC saved.mmsession", + "packageState": "finalized", + "recoveryReports": [], + "schemaId": "capture.analysis_qc/2", + "sessionId": "mini-analysis-fixture", + "sourceCount": 2, + "streamCount": 2, + "streams": [ + { + "dataSchemaId": "emg.batch/1", + "mcapSegments": 1, + "mkvSegments": 0, + "modality": "emg", + "nominalRateHz": 2000.0, + "rateOk": true, + "sourceId": "sim.emg.main", + "streamId": "sim.emg.main.batch", + "timingSegments": 0, + "units": "mV", + "warnings": [] + }, + { + "dataSchemaId": "imu.frame/1", + "mcapSegments": 1, + "mkvSegments": 0, + "modality": "imu", + "nominalRateHz": 60.0, + "rateOk": true, + "sourceId": "sim.imu.upper", + "streamId": "sim.imu.upper.frames", + "timingSegments": 0, + "units": "a.u.", + "warnings": [] + } + ], + "syncAnchorCount": 0, + "trafficLights": { + "sim.emg.main": "warn", + "sim.imu.upper": "ok" + }, + "warnings": [ + "sim.emg.main: 1 recorded gap(s); see gap details" + ] +} \ No newline at end of file diff --git a/docs/evidence/analysis-history-401c5d17da79/current-qc/current-run/receipt.json b/docs/evidence/analysis-history-401c5d17da79/current-qc/current-run/receipt.json new file mode 100644 index 00000000..5a0294c5 --- /dev/null +++ b/docs/evidence/analysis-history-401c5d17da79/current-qc/current-run/receipt.json @@ -0,0 +1,105 @@ +{ + "canonical_main": "e43da3b855475c8aacf815c201fa03eddaeec0f1", + "author_source": "37443f0d4d5ffa684b5423d58501856cadbe0655", + "composition_tree": "ba5b4b925b00ecb17895a8c8ad29410e787f97dc", + "source_inputs_sha256": "c41b5857ca1cca774d85298827c8f63a85dada025e2e326b51ce96de08e0ab0e", + "runner_sha256": "469b3e3fd0403e420c847e1e4c11525b968055447aa2ecdd1024714e2c12039e", + "python": "3.12.14 (main, Aug 25 2026, 14:00:49) [Clang 22.1.3 ]", + "platform": "Linux-6.18.44-x86_64-with-glibc2.39", + "checks": [ + { + "name": "current QC producer loaded from pinned source", + "passed": true + }, + { + "name": "current HTML producer loaded from pinned source", + "passed": true + }, + { + "name": "current producer emits capture.analysis_qc/2", + "passed": true + }, + { + "name": "native gap precision retained in generated result", + "passed": true + }, + { + "name": "current generated report includes the recorded gap", + "passed": true + }, + { + "name": "package selection offers saved result without opening it", + "passed": true + }, + { + "name": "explicit native Open selects the current result", + "passed": true + }, + { + "name": "existing inspector receives current result provenance", + "passed": true + }, + { + "name": "existing report action is available for the retained current report", + "passed": true + }, + { + "name": "native result details dialog opens", + "passed": true + }, + { + "name": "saved parameters and provenance remain read-only", + "passed": true + }, + { + "name": "browsing starts no computation thread", + "passed": true + }, + { + "name": "all generated package and job bytes stay unchanged while browsing", + "passed": true + }, + { + "name": "actual QApplication event loop returned successfully", + "passed": true + } + ], + "scope": "One current-QC/2 to saved-history reader boundary; no worker-thread, Windows, daemon or hardware acceptance.", + "pyside6": "6.11.2", + "package_hashes": { + "events/annotations.json": "37517e5f3dc66819f61f5a7bb8ace1921282415f10551d2defa5c3eb0985b570", + "events/checkpoints.json": "37517e5f3dc66819f61f5a7bb8ace1921282415f10551d2defa5c3eb0985b570", + "events/sync_anchors.json": "37517e5f3dc66819f61f5a7bb8ace1921282415f10551d2defa5c3eb0985b570", + "integrity.json": "af5d9bacd3eace7e831d48dee83eb5d9f578f4f4819d92218c4b55b0cb3ed556", + "manifest.json": "c5254d3e4c0bc6a0ecaef124dc12d88117d647928a8e1725b71429097438d380", + "processing/.gitkeep": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "processing/jobs/current-qc/job_manifest.json": "7c0164de00779c92c16a5b2c31426d94e22abefcced4d16b365967c17be33486", + "processing/jobs/current-qc/logs/job.log": "d23058fcc8ab19137ea84b2c90a830a43f2017e969eb953ca38e210f2fec02b8", + "processing/jobs/current-qc/params.json": "6b1de8a12a547c74d1477f29c2c67df457f1ad54ab7f7865d39ad17199791f35", + "processing/jobs/current-qc/reports/qc.html": "eb41423403c4ea2049d50278c69fced1d37dde4b85aa76482fbe82ffdc7c75e9", + "processing/jobs/current-qc/reports/qc.json": "4bbe314029c3387541b5ad25fdc12268780fc0b31c1e343d5b8690a5e98560d9", + "sources/sim.emg.main/health/gaps.jsonl": "95cece59eed92129190c27703443c363d3b5ec0ff407b406678708dec899e090", + "sources/sim.emg.main/source.json": "4e7626e51bfb804c27f83bf98ee186a47ec9f36fec0cbd7863ea8ecb1ecfbd10", + "sources/sim.emg.main/streams/sim.emg.main.batch/segments/000000.mcap": "3c4d91b3bf5d48dcf54a598fff5b1b4ee42260b756d6f5df3986da496c6a9649", + "sources/sim.emg.main/streams/sim.emg.main.batch/stream.json": "8f8c02b89fd93e55643151e5222488e1174dd97a6b7a74f3ae5da8215b4d68e1", + "sources/sim.imu.upper/source.json": "a6198f509edc557c1e1d8583a767a540962977751c80a1b6491e3d594b60c7a8", + "sources/sim.imu.upper/streams/sim.imu.upper.frames/segments/000000.mcap": "3c4d91b3bf5d48dcf54a598fff5b1b4ee42260b756d6f5df3986da496c6a9649", + "sources/sim.imu.upper/streams/sim.imu.upper.frames/stream.json": "ec39026bed1b833d4decb0ef7b0efb94c5557a5647bc50addc060bef3a30d50d" + }, + "artifact_schema": "capture.analysis_qc/2", + "artifact_gap": { + "cause": "transport_loss", + "closed": true, + "durationNs": "1000000002", + "durationStatus": "known", + "endSessionTimeNs": "2000000003", + "estimatedLostCount": "3", + "sourceId": "sim.emg.main", + "startSessionTimeNs": "1000000001", + "streamId": "sim.emg.main.batch" + }, + "source_unchanged": true, + "exit_code": 0, + "passed": 14, + "failed": 0 +} diff --git a/docs/evidence/analysis-history-401c5d17da79/current-qc/current.stderr.log b/docs/evidence/analysis-history-401c5d17da79/current-qc/current.stderr.log new file mode 100644 index 00000000..09ad4161 --- /dev/null +++ b/docs/evidence/analysis-history-401c5d17da79/current-qc/current.stderr.log @@ -0,0 +1 @@ +This plugin does not support propagateSizeHints() diff --git a/docs/evidence/analysis-history-401c5d17da79/current-qc/current.stdout.log b/docs/evidence/analysis-history-401c5d17da79/current-qc/current.stdout.log new file mode 100644 index 00000000..827c4191 --- /dev/null +++ b/docs/evidence/analysis-history-401c5d17da79/current-qc/current.stdout.log @@ -0,0 +1 @@ +{"passed": 14, "failed": 0, "exit_code": 0, "source_unchanged": true} diff --git a/docs/evidence/analysis-history-401c5d17da79/current-qc/process.json b/docs/evidence/analysis-history-401c5d17da79/current-qc/process.json new file mode 100644 index 00000000..ed07a960 --- /dev/null +++ b/docs/evidence/analysis-history-401c5d17da79/current-qc/process.json @@ -0,0 +1,18 @@ +{ + "command": [ + "/workspace/scratch/234cae4aee53/capturesuite-venv/bin/python", + "-B", + "/dev/shm/hamon-401c5d17da79-capture-history-pr/current-boundary/check_current_qc_history.py", + "--source", + "/dev/shm/hamon-401c5d17da79-capture-history-pr/current-boundary/source", + "--inputs", + "/dev/shm/hamon-401c5d17da79-capture-history-pr/current-boundary/source-inputs.json", + "--output", + "/dev/shm/hamon-401c5d17da79-capture-history-pr/current-boundary/current-run" + ], + "exit_code": 0, + "elapsed_seconds": 3.471, + "stdout_sha256": "34b2748419db7460c2abff30184db5e7f12b075c1808667abcb065177dfd5025", + "stderr_sha256": "caeb11f6473c6c7125dd27478e588b85ffd6b31784e9adb1371a60f1661eb00f", + "runner_sha256": "469b3e3fd0403e420c847e1e4c11525b968055447aa2ecdd1024714e2c12039e" +} diff --git a/docs/evidence/analysis-history-401c5d17da79/current-qc/source-inputs.json b/docs/evidence/analysis-history-401c5d17da79/current-qc/source-inputs.json new file mode 100644 index 00000000..e63df5c7 --- /dev/null +++ b/docs/evidence/analysis-history-401c5d17da79/current-qc/source-inputs.json @@ -0,0 +1,981 @@ +{ + "canonical_parent": "e43da3b855475c8aacf815c201fa03eddaeec0f1", + "author_source": "37443f0d4d5ffa684b5423d58501856cadbe0655", + "composition_tree": "ba5b4b925b00ecb17895a8c8ad29410e787f97dc", + "scope": "Exact tracked Python runtime and one existing fixture/test; no native build or full repository acceptance is implied.", + "files": [ + { + "path": "desktop/capture_desktop/__init__.py", + "mode": "100644", + "git_blob": "48777bd04b62e3b3b877e12311f7257819ab3a07", + "sha256": "8426c94323c4cca0879b8612345e3577d0a75f6239237a28d79d94a42004c3b5", + "bytes": 119 + }, + { + "path": "desktop/capture_desktop/__main__.py", + "mode": "100644", + "git_blob": "f78ccce984b725bf7263407d5b4b2d4c56131433", + "sha256": "8dbad73a7373565a3513ccbb613f11bffdd13a05861c3e8e07392b8d51008aa2", + "bytes": 723 + }, + { + "path": "desktop/capture_desktop/analysis_history.py", + "mode": "100644", + "git_blob": "1b8fd23aee632cc3af19990b9d7685c6a3ed1b5e", + "sha256": "2e0db8cee59ef268d3c91ea0beac7d761d83a3003862841cc9d7f1782fd3543c", + "bytes": 6375 + }, + { + "path": "desktop/capture_desktop/app.py", + "mode": "100644", + "git_blob": "3e6f0d9f31032eb51ddd0ac7deedc3d00d0d386e", + "sha256": "52a6b8d9844d8e0f9f9f1e07f516bf234cf104fdeb85dd5ea5acaa69970235f2", + "bytes": 46414 + }, + { + "path": "desktop/capture_desktop/daemon_link.py", + "mode": "100644", + "git_blob": "620e5a753fbd8448c3a57fcfa6a8b8540ac0bcd0", + "sha256": "ab76628bbe0231c7e5e4d570f2abed01100dddd6a24bb62020b670a6b62427dd", + "bytes": 10899 + }, + { + "path": "desktop/capture_desktop/export_wizard.py", + "mode": "100644", + "git_blob": "b22d0098eb9af3860c654591e411dbab68a0f05d", + "sha256": "fb957ff184109bcb4e379dde30414048e855c93ec390f9b50c7ab603c3cd4e30", + "bytes": 6734 + }, + { + "path": "desktop/capture_desktop/main.py", + "mode": "100644", + "git_blob": "90ad2adebae1f52ffabb889efe43a31dca1b6454", + "sha256": "e61c29a1925f8d85b24438f087dec360a4481a32e0dc2bd8ed8feb6629026e84", + "bytes": 1059 + }, + { + "path": "desktop/capture_desktop/persistence.py", + "mode": "100644", + "git_blob": "2f2da2bfda654009baa0e723465c82c1690a0676", + "sha256": "cdb1fa0094fec72543d5051435850e51d78d79d4bde8d5c83520fa072a2c74c4", + "bytes": 3379 + }, + { + "path": "desktop/capture_desktop/schema_form.py", + "mode": "100644", + "git_blob": "2d5fa62b1448e168e639e3e8879989a3461e1053", + "sha256": "7d825b5dc7566d630f31775df6fcc9def1e916eaff5be17a552bf89f28b3418b", + "bytes": 12206 + }, + { + "path": "desktop/capture_desktop/screen_analysis.py", + "mode": "100644", + "git_blob": "966f89f8cfad679a4a461900569365c50476581b", + "sha256": "98a704e31b14497e012fe5618ad47cc8a772bd2d59775826d71a5bdf41533211", + "bytes": 16407 + }, + { + "path": "desktop/capture_desktop/screen_capture.py", + "mode": "100644", + "git_blob": "b2d3cf05d57484f5efdbb0df85e5f0a065dab3d9", + "sha256": "4e101ddeeaed7f7f2b4ec2ab2e4b1f4f55ebb86f73b394d25cfd2b904cd2572e", + "bytes": 34181 + }, + { + "path": "desktop/capture_desktop/screen_presets.py", + "mode": "100644", + "git_blob": "c143fb87629fb90f656a7a3b4b9f3c136b03f596", + "sha256": "b62d6f4bef6c1f0fc04b9eaf6a8afd1b2eeb17f6ce14946a06b0495ba33d402c", + "bytes": 5230 + }, + { + "path": "desktop/capture_desktop/screen_review.py", + "mode": "100644", + "git_blob": "88a902ca7699faa2964f3fc22ec3348a339905a4", + "sha256": "e5aff59de4b194123ca4c4518b34e7b6103326fbd6b0280e2122d984d01072ec", + "bytes": 7003 + }, + { + "path": "desktop/capture_desktop/screen_settings.py", + "mode": "100644", + "git_blob": "fe6d1e8884b7300e4cb5039b8e86679339e43b4d", + "sha256": "519436946827fac53d0be68270c2929bd1ce615a58b2372e9e3fc10619a7ba6e", + "bytes": 4581 + }, + { + "path": "desktop/capture_desktop/screen_setup.py", + "mode": "100644", + "git_blob": "1df45aac30d63d6ab2e8ddc7efe0db394c513ab1", + "sha256": "01eb01ffffe835fcf5d26120d508800cc3cdac1e91ffaa3d0d2fa669c6326182", + "bytes": 11452 + }, + { + "path": "desktop/capture_desktop/state.py", + "mode": "100644", + "git_blob": "95046ba5ef7f7bbf5685a54b7ae8fd400814148c", + "sha256": "97fc98498f4553fc7f052d0dc4db992cf2fc136ba7c4405cd275bd156c74e314", + "bytes": 17906 + }, + { + "path": "desktop/capture_desktop/theme.py", + "mode": "100644", + "git_blob": "e309ce92bf66f65ca7c111698e1f536f05e4dca9", + "sha256": "c77f24e1afeb06400385bd0d535800f13dc15d972891e1ff8af504cbe5c818f3", + "bytes": 12072 + }, + { + "path": "desktop/capture_desktop/widgets_analysis_history.py", + "mode": "100644", + "git_blob": "8798627cd7d694c5a09c3c402a739a4ec45b6574", + "sha256": "a3b77c87483c1412b50de7ddde1498f6bfd3968002fc3ac3bfa474a2477d9bc4", + "bytes": 8458 + }, + { + "path": "desktop/capture_desktop/widgets_analysis_jobs.py", + "mode": "100644", + "git_blob": "c4d2f4513032d744f1f8066f0c887cda71d9b911", + "sha256": "5cdea6045456e61a58b5525dd224a22a140962d31d2adc5b0102168444468f98", + "bytes": 6304 + }, + { + "path": "desktop/capture_desktop/widgets_analysis_plots.py", + "mode": "100644", + "git_blob": "bb6c3033b5e4ed96a2e08857d38715b836926bf5", + "sha256": "85c73f881ee7d60ef2f868f7ff73fc57c0a4ef99a717f7f5015534db23e1ab86", + "bytes": 9382 + }, + { + "path": "desktop/capture_desktop/widgets_mappings.py", + "mode": "100644", + "git_blob": "62dd1b137ffc54a05aa81f37eb8627dd12e0032a", + "sha256": "89808d37cb0fce476665a24766963c7a509f5b1802d05dedbf9ca44351081f4b", + "bytes": 3658 + }, + { + "path": "desktop/capture_desktop/widgets_modality_expanded.py", + "mode": "100644", + "git_blob": "70d67f7405730707ad67d1da0e71a7e87bf8b68e", + "sha256": "12db25b37e8b2724e5eaabdcb1810aa979633885097b6ec11c33d98a46a83a70", + "bytes": 8566 + }, + { + "path": "desktop/capture_desktop/widgets_preview.py", + "mode": "100644", + "git_blob": "d0a760164a413616ab406a54d81c7b3f9b30d638", + "sha256": "78d79c9af67f7e0cbcee3a3a693a22e72753256ca465bab7edb9c2037822dec4", + "bytes": 27254 + }, + { + "path": "desktop/capture_desktop/widgets_radar_array.py", + "mode": "100644", + "git_blob": "d270e7aa8b36a9a6376cfbd76a46ec6448bb9ae4", + "sha256": "be08874ade0b4d9197ea85cb6ae3b30db75273ddd3c426faaaf28b4f796653a8", + "bytes": 2965 + }, + { + "path": "desktop/capture_desktop/widgets_session_header.py", + "mode": "100644", + "git_blob": "7f3c6e4e78728831fa29c6879cf461ebea5b38ef", + "sha256": "897ad1b241ea6b0582280391c861ae13a5aabe245eb8007283a6f4d5e1fedf27", + "bytes": 3433 + }, + { + "path": "desktop/capture_desktop/widgets_session_timeline.py", + "mode": "100644", + "git_blob": "d85f3c4ea492d587af49ca35c43aa5582806719c", + "sha256": "e7c1c2c679b4d0b0fa338ac0d1a44584d99b321857ab1506bbe2d3b455ded339", + "bytes": 9032 + }, + { + "path": "desktop/pyproject.toml", + "mode": "100644", + "git_blob": "dada23f8692dfda4c7c07fc012608844c7f41ab9", + "sha256": "3646f83dcc0764b3c8cb198b98b03201dc47808bb80bfec4837e329e47bd012f", + "bytes": 552 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/__init__.py", + "mode": "100644", + "git_blob": "67a4fb257b771af771edb4010e573ceeab86a51f", + "sha256": "14cfe6dccd33a0bda74fac3c9339e1a37a3538b2110a8ae6e307801b776eb43a", + "bytes": 497 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/discover.py", + "mode": "100644", + "git_blob": "d5c4fa7e06ac6e9139ebfc78fade90a3df5e451a", + "sha256": "344ee5d7cb0f5e95ac7524a0c1141b0a293bb9445e2bd4789c6736f39cfcb90d", + "bytes": 4023 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/eval/__init__.py", + "mode": "100644", + "git_blob": "140fcb2784c4b73ddf69d21ddccfdcc8191cc0aa", + "sha256": "54661df9ed7d7e0d4b1c2ab5941f107ceb608e4fdfaff810014ef5fad1431fe1", + "bytes": 154 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/eval/job.py", + "mode": "100644", + "git_blob": "95d40a6c28aabcdc311c18e3e195627f29ceb1a7", + "sha256": "a7f2a43c2fc3723c471e42a5532465dc5cfa44d4411c6cf581bba6910603fc57", + "bytes": 3984 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/features/__init__.py", + "mode": "100644", + "git_blob": "e52dc3839105744e19193f8fc8067b818389a20b", + "sha256": "3cdd6c626b6da12b8df56d8ddf35fca27c0a744865965ec01dd89d47da476fa1", + "bytes": 66 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/features/emg.py", + "mode": "100644", + "git_blob": "7f7536500a63ddc8b06774b8da65df8d56cd4f2b", + "sha256": "11f8f8350464b7c7c079353ca649b4c4aad2580ef8d355fe741c025c262b168e", + "bytes": 3072 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/features/imu.py", + "mode": "100644", + "git_blob": "0ee47b3d579e4c3732634958dda21ae724beca9e", + "sha256": "246bfd1cc3ce72afa0680537062b6795e22b8a06ba6301503d7489a4440c6849", + "bytes": 2605 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/features/io.py", + "mode": "100644", + "git_blob": "b998063a5036b73a67b773f70c193b1f9827c248", + "sha256": "c677d209292cca790ccdf1a64ba834f71a078ccce31ea57452e67ece358822ca", + "bytes": 1409 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/features/numeric_batch.py", + "mode": "100644", + "git_blob": "a9a667633f886adf4fe89cfd35eb94eeabad399f", + "sha256": "df48baa8eac38e1bcdb38411758b7f803507ab27b4a97fba18c86042cfd33c76", + "bytes": 2104 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/features/radar_doppler.py", + "mode": "100644", + "git_blob": "ee20f7314cb1af4512901d6009f73e3dddf9025c", + "sha256": "cffc0ecbb8053fbc2244850c1927469366f4ae93b5439e4d194de2065877fa5c", + "bytes": 2289 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/features/radar_frame.py", + "mode": "100644", + "git_blob": "e798dee0fb72dd261b504a99ac76f815515dda9e", + "sha256": "f85c5fe5e2db68606f68e36a42a0c8f323086f0b1e7f233c0ddefa24cdccb443", + "bytes": 3323 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/features/video_qc.py", + "mode": "100644", + "git_blob": "fa73c80d39a0d699f80d7e877b37167cf8b48b6a", + "sha256": "0e25c50e01fc2da47bc7b510d68ba3e72aba33d3e1c79c57b727f5c55c723e27", + "bytes": 1766 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/grids.py", + "mode": "100644", + "git_blob": "2e03f79d9317d2d97b721321130a9a5e6212b111", + "sha256": "936c5404783145f7a2bc4c13df22d3b85612bcb227115bba74f0b78a11c0c483", + "bytes": 1007 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/jobs.py", + "mode": "100644", + "git_blob": "7badee5cdf5a4b30a283e0dcbb2c5d85fb787489", + "sha256": "e7e9dda44eb014d18192563f1e2c0ae78cece850fbc853b0be3919daaf5ee276", + "bytes": 19627 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/kinematics/__init__.py", + "mode": "100644", + "git_blob": "aaf360b8a0085f89b95cd976857f0933596098a7", + "sha256": "50a0f7fd39648abf269fc549d2c17eb48b1dc9add10ebdb76edc1935d6f80160", + "bytes": 178 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/kinematics/compute.py", + "mode": "100644", + "git_blob": "928751e9c861e2b0da298214269e57111f492865", + "sha256": "6e3ca19bfda0c02877f5d778f0c1191b5aebad605373732ef182bd714dd7f086", + "bytes": 6899 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/kinematics/job.py", + "mode": "100644", + "git_blob": "fb8be113d8699427072f6dbcdae222a37738ac18", + "sha256": "d676e84f54aa1ae2b0f998c2cb37c4e02541c1fd0e3464e38e9865c0049a7239", + "bytes": 4523 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/kinematics/registry.py", + "mode": "100644", + "git_blob": "a28cfd708c90552401fb0b3157c60f713a06e14f", + "sha256": "1e53fb9da4c6a2743bc1a3f0e687d94599cf995d33f2a2555e0ce5ebc3966d48", + "bytes": 1155 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/loaders/__init__.py", + "mode": "100644", + "git_blob": "eb6fae21d4bb79055f8d1af1528e846020f21459", + "sha256": "2d51c509baf3c0b5c33360637d12e5ce3c7507a859e4f37030f2c3d711ef0b3d", + "bytes": 361 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/loaders/base.py", + "mode": "100644", + "git_blob": "941a6aa3cea6777f90534ea634cccf8fdd319a3f", + "sha256": "696093b31f22d2bef32fc2962c7a11249a590a0b4d776c40cef4edcbc1e48a97", + "bytes": 2461 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/loaders/emg.py", + "mode": "100644", + "git_blob": "c35d22af7bdeea570e6ae45a713428627e90894c", + "sha256": "86eb7114be689cdbd2edd76affa2994e7278714916692a35381abd02ba9d599a", + "bytes": 3089 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/loaders/imu.py", + "mode": "100644", + "git_blob": "8823f04bd089789ca4cbff6602154bf066d4161d", + "sha256": "5ea4747145bf5588974dfd72c834766436c5a2bc0d58d34ace0f8ef403b310d6", + "bytes": 2773 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/loaders/mcap_iter.py", + "mode": "100644", + "git_blob": "b61ca0a914e4d3909790839774327aa5824c1b71", + "sha256": "03a418e7689840e378665aac92c42769dd14ba2c88a821a5cbf0cee80766540c", + "bytes": 1196 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/loaders/numeric_batch.py", + "mode": "100644", + "git_blob": "f361d6e1afce8c836a13f2211b8fe8cb7442e30d", + "sha256": "0b6c78bf936e3bade378c6b0061aa94a8f11f536ade52b1d687f156d13780296", + "bytes": 3473 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/loaders/radar_doppler.py", + "mode": "100644", + "git_blob": "fc87bfb7fbbeb98ad8d5d11b3438b2d04882de6c", + "sha256": "4942d08eb47229839e339ce7f2f8a64aee7e5fab44bac77029fcd7a3e3e490c1", + "bytes": 1539 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/loaders/radar_frame.py", + "mode": "100644", + "git_blob": "a44af5392ba2b5b8b64de685f42772b141f1b8b1", + "sha256": "d071f9d95b371798974698fd0caa1fc4c865a85fb772232fd43e7227b15fad2b", + "bytes": 1828 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/loaders/video.py", + "mode": "100644", + "git_blob": "6a192cd5999b45df08c666b9dad21dc29cf91824", + "sha256": "3c3e873ab641904a39ca649dac39072f11948031d068cc21ee459e996d1fc185", + "bytes": 2200 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/ml_bundle/__init__.py", + "mode": "100644", + "git_blob": "619d634ebf6fcc82a7871ad9c463660a24fd65ae", + "sha256": "e785a2e3bf65852018d811b38ecbaf6ff9c479648025789145218809dd50d8a1", + "bytes": 179 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/ml_bundle/job.py", + "mode": "100644", + "git_blob": "59c2e4df46aa041e48aaf7184a3dd0ba345aff6d", + "sha256": "c14c74760e20c818ce5e2428d0b03a8a949899b0bba6c46e37fa8fd797631c75", + "bytes": 9419 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/pipeline.py", + "mode": "100644", + "git_blob": "8113ab4cb51678a122bbb702a23f2200c9333233", + "sha256": "e8c0152040ba5b5f3f37ac53fb5188bac9dd9aaf0d5816d6a718be505c20898c", + "bytes": 5262 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/plots/modality.py", + "mode": "100644", + "git_blob": "85073e330e6aaf617864a0730011e689251ecea9", + "sha256": "c9b1159ce1535fbddb4895d1acdf0115f88919aa3cc51ad964e5771d975995dd", + "bytes": 2393 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/plots/style.py", + "mode": "100644", + "git_blob": "3725e840e5eb046accea79d4b6376f902392dac8", + "sha256": "231e7b1c998f4349d5859295007235ffd41848f12fbb7819193bec9630cd3942", + "bytes": 1249 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/plots/sync_dashboard.py", + "mode": "100644", + "git_blob": "828204e998a46b9571b3a2b3ba08acd9fc6caa31", + "sha256": "6f9e0c64193688eb841565729b9d1e9a64136779e892419acabdc81591afd3d5", + "bytes": 1149 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/plugins/__init__.py", + "mode": "100644", + "git_blob": "39c9c93eab1f5abf65ea73299c34b05ec184dd63", + "sha256": "c511d4b9cd1cda042b781b06fbb02d2d99004de214735d6daeb459d6e41381fe", + "bytes": 225 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/plugins/dummy.py", + "mode": "100644", + "git_blob": "0152651c271234bf38252bed51efda3a3fc19c0f", + "sha256": "facf059d247bca44f2697383e12cc1296b1d1d12bede1196f4a52a1352d60495", + "bytes": 1618 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/plugins/handlers.py", + "mode": "100644", + "git_blob": "03c8589064dfc4c6cfec6e4d00b7f46b10014414", + "sha256": "9be2e1820529b94e54d06790d53aa94cf658f982efb4063c6b64f9d07acc4b2e", + "bytes": 10646 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/plugins/manifest.yaml", + "mode": "100644", + "git_blob": "e4b1792b4cf9f2f8f5c63bb8375c4d80f6f58818", + "sha256": "365bce8a7193e1407a684d4c3ee5dc1690c296f1b8bcb625076076cd8bea2eb3", + "bytes": 3832 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/plugins/registry.py", + "mode": "100644", + "git_blob": "e7334bedfcba51052a7f039f66c74ff288840831", + "sha256": "5ba10f5b58c102a98943d2225903c1d9f874aa5921a50319e159f6bd4d537351", + "bytes": 4834 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/pose/__init__.py", + "mode": "100644", + "git_blob": "108be2956adfed6328f397d88a3b61ebada0ac48", + "sha256": "d58a03cae86259b2cb0ecd0a5ce2347c6824f14cfea6871c94d76acc3541a380", + "bytes": 156 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/pose/job.py", + "mode": "100644", + "git_blob": "1a1a3f2436b0ac8decc551f84e76fa6c4c6e602d", + "sha256": "1f4c44f443c07e22e8c9ca877232c6780c4b1da7834d5565b82cf547b2f4c439", + "bytes": 6262 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/qc.py", + "mode": "100644", + "git_blob": "530b86af1247599c127e2d0c3fa5e4d7d12169f6", + "sha256": "f24e0593a3723311d41054aef40b56c4bb46d4f3ba5ef4b01afcae3a6cc4440a", + "bytes": 9187 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/report_html.py", + "mode": "100644", + "git_blob": "bb8032024cfce30c6fe9a2bd2c13b0d2cbc2d102", + "sha256": "f2c89c7faf6e4edc265540140272396b4195eb5aed9edf05c4912aac74286f03", + "bytes": 4716 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/types.py", + "mode": "100644", + "git_blob": "2adf26816e0ef9e84e6763cf8bbff69d64697949", + "sha256": "e7996d02483f69265a2ef2ec0b28078c86f4f479daa53e38faf8b4a62645d02c", + "bytes": 3428 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/version.py", + "mode": "100644", + "git_blob": "d04b8cc1dd9271ca3ccf836d97436d9a961417c6", + "sha256": "9e25143344b110699f68b6acdbef49576fc91c2cbda34956d7e2cb85bbbc4ae3", + "bytes": 62 + }, + { + "path": "libs/python/capture_analysis/capture_analysis/windows.py", + "mode": "100644", + "git_blob": "80bea6bd69365a48c5b204c26d054b8ae179437a", + "sha256": "af40235d55341d2a6b11d7f67a0195779676301fa822b2bd05240d138ee28c50", + "bytes": 5618 + }, + { + "path": "libs/python/capture_analysis/pyproject.toml", + "mode": "100644", + "git_blob": "6db8b1158b14da660128d7ac0ceacb45b8eb9924", + "sha256": "84cd96465e48439bdd81f5fa126fea5da11ee7587b488bfaaa67a4cd8f760c75", + "bytes": 677 + }, + { + "path": "libs/python/capture_protocol/LICENSE", + "mode": "100644", + "git_blob": "d645695673349e3947e8e5ae42332d0ac3164cd7", + "sha256": "cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30", + "bytes": 11358 + }, + { + "path": "libs/python/capture_protocol/NOTICE", + "mode": "100644", + "git_blob": "7f9ac0678aa56452f06e6e5f3badc9a873e2008a", + "sha256": "3efb470f58c900a58deaef889527e074206274b0fd5fb0e2e62613c093064307", + "bytes": 124 + }, + { + "path": "libs/python/capture_protocol/capture_protocol/__init__.py", + "mode": "100644", + "git_blob": "0e7ab2cf8689d3adbc689c283e8a23d12607b2d0", + "sha256": "556f474a3d740adc03c40426acde432ab7a394b947f8268bd90eecc7832dff8a", + "bytes": 698 + }, + { + "path": "libs/python/capture_protocol/capture_protocol/codec.py", + "mode": "100644", + "git_blob": "3034065efca2c52e34c3e67e147bdda526d2c8db", + "sha256": "f6c09246a7b165358835e51b99b1508e68d840f4bdbd54b5fb72db33d4912712", + "bytes": 7011 + }, + { + "path": "libs/python/capture_protocol/capture_protocol/config_schema.py", + "mode": "100644", + "git_blob": "c9b4a694e620e5597d338230fcb0f25ea3a757f6", + "sha256": "00d855895faec7d674cdb8e4da1ddc687888c9e9863f91d4950d24d9fb815e6e", + "bytes": 8444 + }, + { + "path": "libs/python/capture_protocol/capture_protocol/constants.py", + "mode": "100644", + "git_blob": "2542cda6bdb6a83d4334336f34d92f80040bc4a0", + "sha256": "7f187edf873cd13f55bc09ff7972785797eb488d74dd5befcb395fc928a71d72", + "bytes": 486 + }, + { + "path": "libs/python/capture_protocol/capture_protocol/control_client.py", + "mode": "100644", + "git_blob": "45e1c4b535ece8d7178cd6b32ab1affcc9e73e92", + "sha256": "68de412465b2eaa04886a2bb4566aa0595c898df7d7e782b3031b8ba919db7fa", + "bytes": 20823 + }, + { + "path": "libs/python/capture_protocol/capture_protocol/framing.py", + "mode": "100644", + "git_blob": "9dd5021b815b31ab02eaaa814210525ebb543862", + "sha256": "3ff7c7284d9907a2ad516c83fab383a4151996da3f2d5a1d27e24d7c7575d92e", + "bytes": 2884 + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/__init__.py", + "mode": "100644", + "git_blob": "16ae7d90a122b4973139c563ac0f72efa061b1de", + "sha256": "1fac8216894ce1a1b5362de3b59398fbd78f005a59636aea9f074951bed5c1d7", + "bytes": 90 + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/__init__.py", + "mode": "100644", + "git_blob": "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", + "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "bytes": 0 + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/__init__.py", + "mode": "100644", + "git_blob": "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", + "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "bytes": 0 + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/arrays_pb2.py", + "mode": "100644", + "git_blob": "a29ed506c4dd33f697ba74d13b6e8a9c945c6b6d", + "sha256": "6355750076724275e49f9a5faec383b2be92c0336ed58805a88954964bd13b86", + "bytes": 2876 + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/common_pb2.py", + "mode": "100644", + "git_blob": "66031212a0da44800dcc671b0d4bf0cd39e71f06", + "sha256": "6736e3b86b3c8749d34065794da1c880772ce69e2f248fdd2febd003f083bbd3", + "bytes": 9746 + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/control_pb2.py", + "mode": "100644", + "git_blob": "0597489cf8609a76e2094270965039da9b739ca3", + "sha256": "f2eea386aebf830ec47fa7379e6fb0493e0a199efecc7b90974bc8bb8c8b96b6", + "bytes": 20028 + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/data/__init__.py", + "mode": "100644", + "git_blob": "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", + "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "bytes": 0 + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/data/emg_batch_pb2.py", + "mode": "100644", + "git_blob": "d8495ebeb8ab140824eaa5412be0779cf929ec6a", + "sha256": "1db5ef51143a546072e34cc7be7b263db996fa5f4d0d71606b230cb75b531a14", + "bytes": 1624 + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/data/imu_frame_pb2.py", + "mode": "100644", + "git_blob": "54bbf93dc638cdab95f49744ea7e0b43fefad374", + "sha256": "4a2048d2a737362bf26b99166e95c457d1492fcfba8848c894fe4d2748ff9f51", + "bytes": 2222 + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/data/numeric_batch_pb2.py", + "mode": "100644", + "git_blob": "beedaaae054bfb083af3642c96ca7c64af14cc8d", + "sha256": "a087cc019b9849f4ef47bcdf4c789a7da90d443240b7bef97c832bb23c1d4e24", + "bytes": 1454 + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/data/radar_doppler_pb2.py", + "mode": "100644", + "git_blob": "ad8fe84317d2f4049682f70bead19f90c6932457", + "sha256": "d1b85358aba0c2f4fc1745218463e9951224322604b18b068a2195359dcf790e", + "bytes": 1773 + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/data/radar_frame_pb2.py", + "mode": "100644", + "git_blob": "cef636d7b030b037b23331eec9a86f3b152bc358", + "sha256": "995ddbbb0aa614afb15088cf039c741421c33ea3e3e963ef1a7361b24754b862", + "bytes": 1729 + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/data/video_timing_pb2.py", + "mode": "100644", + "git_blob": "17937a141a9a2d81858cf52d74bc4705afc940b7", + "sha256": "002a79858ccd2d7763769a1fe1be6a16a7f6b8727d15f952d191bcd2240ba5ef", + "bytes": 1722 + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/events_pb2.py", + "mode": "100644", + "git_blob": "030bd4a90be609403e7709605607d8d5b993776e", + "sha256": "72951a468b0480e7fefc4fd3f9b4caac5fda0abdadf4ffcca92d4f19286429ce", + "bytes": 5480 + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/health_pb2.py", + "mode": "100644", + "git_blob": "b27bd32ec488168871ca2342062eb576d56a9e8e", + "sha256": "e1e0baa7073a9886e4d982d4f00020b490bfd46c32b1b4df129fd0477c1f5e61", + "bytes": 5898 + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/presets_pb2.py", + "mode": "100644", + "git_blob": "d20925410185e5cf52bbc56e438534c1c5ff1102", + "sha256": "d27336594b548f2e6e7ae212fe6de198e6e699c62a5f27752f691d7928ccb27b", + "bytes": 2066 + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/preview_pb2.py", + "mode": "100644", + "git_blob": "cb04387df1614a8b9d9755a702129bbbb8d6374e", + "sha256": "c992e91b9aef0aa0ec8d595eba2f7079889264d9e4de120b623afd1d8702c695", + "bytes": 5333 + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/project_pb2.py", + "mode": "100644", + "git_blob": "a8e71f0a426858cc679cb87ce31d1379e70a2817", + "sha256": "983bc5715147297cdcecca343b9a450f2095fcc1e895859cc3c52a3213d933f5", + "bytes": 3355 + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/source_pb2.py", + "mode": "100644", + "git_blob": "b72752efedc743d236713e51283dce923a526f55", + "sha256": "d15b443f27c910c0e809af19fed81d9c1a75f7112501df85877bf4bf9bc4f7a8", + "bytes": 8053 + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/storage_pb2.py", + "mode": "100644", + "git_blob": "4dd1b48ab16900c5c3e88d9788cebf83ee93cc5a", + "sha256": "f7a7b8903af9bfc2d2a419622c86cc057aed2a898949e4261475a7ac61222474", + "bytes": 5487 + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/worker_pb2.py", + "mode": "100644", + "git_blob": "7f3a4fc372384523638853f4bd458f49b664ba70", + "sha256": "112e832172913024c6fad128a9a9559bbcd14b18de06b1f2a3161ac380258dc0", + "bytes": 11165 + }, + { + "path": "libs/python/capture_protocol/capture_protocol/handshake.py", + "mode": "100644", + "git_blob": "9386e73b3c1eecb683d9d0ca98ad415268e307af", + "sha256": "63f740c992edf8812f666b79f9cd866d9ea33e65e5b310a5ebda2f5ef98ac115", + "bytes": 4763 + }, + { + "path": "libs/python/capture_protocol/capture_protocol/structured_log.py", + "mode": "100644", + "git_blob": "fc9c97b288280f4473c6b3c5b5e6ff07332fad49", + "sha256": "3d7883833286ecc004248294badcc0c66e44a57ecb7844ef281828d797b3c4fc", + "bytes": 4657 + }, + { + "path": "libs/python/capture_protocol/pyproject.toml", + "mode": "100644", + "git_blob": "fa71ca45874d34076208507180c69c7a0e38fa76", + "sha256": "61b2e33b2de2a153fb994144f532402c1b6b8ed02afb627ba0a15239e726ca71", + "bytes": 355 + }, + { + "path": "libs/python/capture_session/capture_session/__init__.py", + "mode": "100644", + "git_blob": "894e3c152a98b6e804de90122572afbcd929b3da", + "sha256": "da530f86c0d1d584862868ddba9f7087ccf5dfbddd64dd1e577337ecfd776419", + "bytes": 2412 + }, + { + "path": "libs/python/capture_session/capture_session/app_paths.py", + "mode": "100644", + "git_blob": "46332cea7c62dd44247b219937ae6c8fbc747017", + "sha256": "363e4522240e2356cac7492589cb207a798bc1af6031139bd1fa94890f1c4bfd", + "bytes": 561 + }, + { + "path": "libs/python/capture_session/capture_session/package_reader.py", + "mode": "100644", + "git_blob": "91fbf913c5af8489968425d7ceac51c04233d3e0", + "sha256": "9a1d9e6e7d24341a083cee602af9538413e948f3369b22660e484356e3d34eb1", + "bytes": 6331 + }, + { + "path": "libs/python/capture_session/capture_session/registry.py", + "mode": "100644", + "git_blob": "c1d7799e1d2099424221b2f4af216a43a972c67a", + "sha256": "809b26ce8d8efc0559a3854cf85ea74b4e486fcd77d253ebfa76bade64b0a8d1", + "bytes": 13989 + }, + { + "path": "libs/python/capture_session/capture_session/settings_store.py", + "mode": "100644", + "git_blob": "41b99cdaa78011d3d9b753c3131f32c72af9699f", + "sha256": "7719524a1f106cc54befcd21088810f9ec28f0160c8e88f60c374e1545fdb98d", + "bytes": 4622 + }, + { + "path": "libs/python/capture_session/pyproject.toml", + "mode": "100644", + "git_blob": "c83450d780e97e5bd90feb48cef140917b6e47ff", + "sha256": "3484887da96d4a2f32de8471b537d849f077b195c729ff0cc29307681e8d4895", + "bytes": 389 + }, + { + "path": "libs/python/capture_worker/LICENSE", + "mode": "100644", + "git_blob": "d645695673349e3947e8e5ae42332d0ac3164cd7", + "sha256": "cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30", + "bytes": 11358 + }, + { + "path": "libs/python/capture_worker/NOTICE", + "mode": "100644", + "git_blob": "d74f1cbf89d4c89f70b3e75ab71cfadea8b7128f", + "sha256": "2a7e69c4c7cd4e93a5cc9e9f984873a2d1276f465b91b10c71b951ebcfb2c588", + "bytes": 142 + }, + { + "path": "libs/python/capture_worker/capture_worker/__init__.py", + "mode": "100644", + "git_blob": "4bf1fc6b13bc4f5daab79d937ea89cf6c120cce3", + "sha256": "c7ba88e956df8460002637eb3d8678a4c7217e680a388f833a22f073dc80f8fd", + "bytes": 503 + }, + { + "path": "libs/python/capture_worker/capture_worker/__main__.py", + "mode": "100644", + "git_blob": "a1047121f4173802074eeb66e5dcaf6c542c29c1", + "sha256": "216422b76731bc985daa5fb0efe55a9d5ce600aa7e6081fa3df0c03afb6a893e", + "bytes": 150 + }, + { + "path": "libs/python/capture_worker/capture_worker/cli.py", + "mode": "100644", + "git_blob": "eb2d869f951f0205085b074d067282990657b5a0", + "sha256": "8a16c4cae0ffd11d4f9cd5d168f6abf1c6f9a4b5100e8edd18a29ce7d44d3f03", + "bytes": 1818 + }, + { + "path": "libs/python/capture_worker/capture_worker/preview.py", + "mode": "100644", + "git_blob": "c47abe8a118ea022931843bde802132548194eef", + "sha256": "38b483dc06c9215b73e4c56c222fe563957180a5be58761a2c6dd4ea200b8e31", + "bytes": 3202 + }, + { + "path": "libs/python/capture_worker/capture_worker/transport.py", + "mode": "100644", + "git_blob": "2e5e159bee3a0b5aa69bf90f62906feeffe23c8c", + "sha256": "020414c74bd08ec510e88da8c2f8b9ec5091a19cb585b4c54d2656b4bf300d35", + "bytes": 5033 + }, + { + "path": "libs/python/capture_worker/capture_worker/worker.py", + "mode": "100644", + "git_blob": "d5ed2999fbb958116d73a8fa6319356d8b7d751a", + "sha256": "19a0dfd16a65479de884d4359a3d65f1bc127d8a6d4b44b93c6251757510de68", + "bytes": 23439 + }, + { + "path": "libs/python/capture_worker/capture_worker/writer.py", + "mode": "100644", + "git_blob": "b3d194cc71dfa0d21884936a6ed5f7bdc95b3eb4", + "sha256": "b9e3b21ac26f2160da582a3f566a278dc4088c5a8b121d9b4e74f8d8c16cf96f", + "bytes": 6196 + }, + { + "path": "libs/python/capture_worker/pyproject.toml", + "mode": "100644", + "git_blob": "5d79642edc9c1809fda636d5dcd78ad33e67abcc", + "sha256": "0cba218b59a756185fedf72fb3a3307d1d9cb9218b6189ea92972d3cec139a46", + "bytes": 487 + }, + { + "path": "pyproject.toml", + "mode": "100644", + "git_blob": "52491c6beebc4b17983fc66bb8765154c33cf6d8", + "sha256": "0cb8de1ab3dfbfed84ff16b35f3c89c6440180183ee5851d5d80da83622e53d0", + "bytes": 1233 + }, + { + "path": "tests/conftest.py", + "mode": "100644", + "git_blob": "ad9b61fd8e9c1c3d74f91710d4e82dd7d899e6b4", + "sha256": "f669618fad17e906c91df7a1e9393fc7a54f458c6d62a4385436ba2622beca0e", + "bytes": 1773 + }, + { + "path": "tests/fixtures/mini_session/events/annotations.json", + "mode": "100644", + "git_blob": "fe51488c7066f6687ef680d6bfaa4f7768ef205c", + "sha256": "37517e5f3dc66819f61f5a7bb8ace1921282415f10551d2defa5c3eb0985b570", + "bytes": 3 + }, + { + "path": "tests/fixtures/mini_session/events/checkpoints.json", + "mode": "100644", + "git_blob": "fe51488c7066f6687ef680d6bfaa4f7768ef205c", + "sha256": "37517e5f3dc66819f61f5a7bb8ace1921282415f10551d2defa5c3eb0985b570", + "bytes": 3 + }, + { + "path": "tests/fixtures/mini_session/events/sync_anchors.json", + "mode": "100644", + "git_blob": "fe51488c7066f6687ef680d6bfaa4f7768ef205c", + "sha256": "37517e5f3dc66819f61f5a7bb8ace1921282415f10551d2defa5c3eb0985b570", + "bytes": 3 + }, + { + "path": "tests/fixtures/mini_session/integrity.json", + "mode": "100644", + "git_blob": "d10093b866427fcaed78a85e60e600d8657a86a7", + "sha256": "af5d9bacd3eace7e831d48dee83eb5d9f578f4f4819d92218c4b55b0cb3ed556", + "bytes": 227 + }, + { + "path": "tests/fixtures/mini_session/manifest.json", + "mode": "100644", + "git_blob": "800dab5b41774bc043ebdee4714195770e75229b", + "sha256": "c5254d3e4c0bc6a0ecaef124dc12d88117d647928a8e1725b71429097438d380", + "bytes": 235 + }, + { + "path": "tests/fixtures/mini_session/processing/.gitkeep", + "mode": "100644", + "git_blob": "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", + "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "bytes": 0 + }, + { + "path": "tests/fixtures/mini_session/sources/sim.emg.main/health/gaps.jsonl", + "mode": "100644", + "git_blob": "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", + "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "bytes": 0 + }, + { + "path": "tests/fixtures/mini_session/sources/sim.emg.main/source.json", + "mode": "100644", + "git_blob": "9528c95289b4b1b49d11d412b5ab2e3d019b4066", + "sha256": "4e7626e51bfb804c27f83bf98ee186a47ec9f36fec0cbd7863ea8ecb1ecfbd10", + "bytes": 112 + }, + { + "path": "tests/fixtures/mini_session/sources/sim.emg.main/streams/sim.emg.main.batch/segments/000000.mcap", + "mode": "100644", + "git_blob": "320ce3607fadf57d05cf506987d045cf5b62ad9f", + "sha256": "3c4d91b3bf5d48dcf54a598fff5b1b4ee42260b756d6f5df3986da496c6a9649", + "bytes": 28 + }, + { + "path": "tests/fixtures/mini_session/sources/sim.emg.main/streams/sim.emg.main.batch/stream.json", + "mode": "100644", + "git_blob": "12c4db8831572fc4ab3db9ba5f784fa236078e5f", + "sha256": "8f8c02b89fd93e55643151e5222488e1174dd97a6b7a74f3ae5da8215b4d68e1", + "bytes": 216 + }, + { + "path": "tests/fixtures/mini_session/sources/sim.imu.upper/source.json", + "mode": "100644", + "git_blob": "fcc248c52b8319f5e7fd0067763b74640f0040dd", + "sha256": "a6198f509edc557c1e1d8583a767a540962977751c80a1b6491e3d594b60c7a8", + "bytes": 118 + }, + { + "path": "tests/fixtures/mini_session/sources/sim.imu.upper/streams/sim.imu.upper.frames/segments/000000.mcap", + "mode": "100644", + "git_blob": "320ce3607fadf57d05cf506987d045cf5b62ad9f", + "sha256": "3c4d91b3bf5d48dcf54a598fff5b1b4ee42260b756d6f5df3986da496c6a9649", + "bytes": 28 + }, + { + "path": "tests/fixtures/mini_session/sources/sim.imu.upper/streams/sim.imu.upper.frames/stream.json", + "mode": "100644", + "git_blob": "9c634d4af594372063fcc612331ba338ae95f8c9", + "sha256": "ec39026bed1b833d4decb0ef7b0efb94c5557a5647bc50addc060bef3a30d50d", + "bytes": 219 + }, + { + "path": "tests/ui/test_analysis_history.py", + "mode": "100644", + "git_blob": "f013473f750b515a8305e2f7f8426b6520e26a65", + "sha256": "48175547922125c308fa49bbb84149e3dac8903902e7cc64fa7c15b4ca40eccd", + "bytes": 10465 + }, + { + "path": "workers/python_host/capture_sim/__init__.py", + "mode": "100644", + "git_blob": "2646a1792544ac97cba76fd7d7246c313604351e", + "sha256": "a3c8506a26d20b0b10cd55f00b019b7ddc1e2d4cb5cffd5c155d70ef338d21ae", + "bytes": 259 + }, + { + "path": "workers/python_host/capture_sim/advertise.py", + "mode": "100644", + "git_blob": "c93044ce53b7a38d2e7db9fcbad83174b394ffd2", + "sha256": "6a41dafed67d08d4e3829c053dc5a2767ae28293d63733b4b4ae187a8d4a94b9", + "bytes": 15205 + } + ] +} diff --git a/docs/evidence/analysis-history-401c5d17da79/current-scope/README.md b/docs/evidence/analysis-history-401c5d17da79/current-scope/README.md new file mode 100644 index 00000000..f02292b8 --- /dev/null +++ b/docs/evidence/analysis-history-401c5d17da79/current-scope/README.md @@ -0,0 +1,23 @@ +# Current scope and saved-history receiving + +This one native journey qualifies the joined scope/history hooks on actual main `3e3ecc5ecc1cfc79c79901eb5cffe10b0ec5852e`. The exact runtime tree is `167bbac3bba862cc1532d954fe2d503e561a00df`; the corrected screen is Git blob `6893f119593f8ff6551167efcb1939d014a081e6`. The two history modules and the original history tests retain their authored bytes. + +The three-way screen merge required one resolution in `set_package`: retain the current scope owner's resolved path, conditional scope reset and `package_loaded` signal, and pass that same path to history. A real startup check then exposed that `_sync_enabled()` runs before `thread.start()`. Counting the retained thread handle as busy keeps native controls reserved until the existing finished cleanup clears it. The worker and thread cleanup remain unchanged from the current parent. The start-job method keeps its current lifecycle and uses the authored _clear_result_view() helper in place of the two direct gallery/inspector clears; it is unchanged between the initial composition and the one-line busy correction. + +## Accepted current boundary + +The final method ran through actual `QApplication.exec()` and `QTimer`, using the real `SessionHeader`, `AnalysisScreen` and two real QThread/MCAP feature jobs. **24 checks passed, none failed; process exit 0 in 3.534 seconds.** It verifies selected nanosecond ranges in saved parameters and manifests, control disable/restore, explicit read-only reopening without replacing the next scope, same-package normalization, and rejection of a real queued A completion after switching to B. All 142 frozen source files and both packages' raw inputs stayed byte-identical. + +Both jobs intentionally use the existing `completed_with_warnings` contract. Each saved manifest contains exactly the two expected warnings for this fixture: its `sealed` state and absent duration integrity metadata. Exact custom range values are independently checked; no unexpected execution failure or warning is accepted as success. + +The captured frame was inspected. The new scope and history controls remain legible together. The unusually long private package path wraps and clips in the existing narrow left column, so this frame is not claimed as complete layout acceptance. + +## Controls and limits + +The complete first control on the uncorrected composition passed identity/range checks and failed the real startup Refresh-disable condition. Its method, source hashes, receipt and log remain separate. A later continuation encountered ENOSPC while capturing artifacts and produced no complete receipt; that attempt is not acceptance or a newly inferred product failure. The final method emits its full receipt and PNG to stdout before transport, and the native process exits normally. + +The original 14-test and 19-check successes remain pinned to runtime `37443f0d` on `72c15d6b` dependencies. The QC/2 successor remains pinned to `e43da3b8`. The separately recorded current nested-numeric gallery gap remains with its own owner. This is a Linux/PySide6 component journey; it does not claim a Windows MainWindow, full suite, daemon, hardware or installed-release result. + +## Replay + +Materialize only the 142 exact source files listed in `candidate-source-inputs.json` into an isolated source directory, preserving the recorded Git blobs and SHA-256 values. Use the existing CaptureSuite environment with PySide6 and its analysis dependencies; no installation is part of this receiver. Run `check_scope_history.py --source --inputs candidate-source-inputs.json --output ` with Python `-B`. The output directory must not already exist. Capture the line beginning `HAMON_SCOPE_HISTORY_RECEIPT `; it contains the complete report and the native PNG as base64. Persist its raw stdout and extracted PNG with hash readback. The method creates only its own package/state/output data and verifies source bytes before and after execution. diff --git a/docs/evidence/analysis-history-401c5d17da79/current-scope/candidate-source-inputs.json b/docs/evidence/analysis-history-401c5d17da79/current-scope/candidate-source-inputs.json new file mode 100644 index 00000000..e1199525 --- /dev/null +++ b/docs/evidence/analysis-history-401c5d17da79/current-scope/candidate-source-inputs.json @@ -0,0 +1,865 @@ +{ + "repository": "Jacob-Met/CaptureSuite", + "canonical_parent": "3e3ecc5ecc1cfc79c79901eb5cffe10b0ec5852e", + "canonical_tree": "18e97093f04de23de5e9878fd22c1f5ed986d5f3", + "history_author_runtime": "37443f0d4d5ffa684b5423d58501856cadbe0655", + "composition_tree": "167bbac3bba862cc1532d954fe2d503e561a00df", + "composed_screen_git_blob": "6893f119593f8ff6551167efcb1939d014a081e6", + "files": [ + { + "path": "desktop/capture_desktop/__init__.py", + "git_blob": "48777bd04b62e3b3b877e12311f7257819ab3a07", + "bytes": 119, + "sha256": "8426c94323c4cca0879b8612345e3577d0a75f6239237a28d79d94a42004c3b5" + }, + { + "path": "desktop/capture_desktop/__main__.py", + "git_blob": "f78ccce984b725bf7263407d5b4b2d4c56131433", + "bytes": 723, + "sha256": "8dbad73a7373565a3513ccbb613f11bffdd13a05861c3e8e07392b8d51008aa2" + }, + { + "path": "desktop/capture_desktop/analysis_history.py", + "git_blob": "1b8fd23aee632cc3af19990b9d7685c6a3ed1b5e", + "bytes": 6375, + "sha256": "2e0db8cee59ef268d3c91ea0beac7d761d83a3003862841cc9d7f1782fd3543c" + }, + { + "path": "desktop/capture_desktop/app.py", + "git_blob": "363b6acbdcf0ba382bd040903946e6916ab282c9", + "bytes": 47945, + "sha256": "e33cf4446d4edfda3634cb5445aa9456d2f243a8b710c0d9c6497b2ec28078b2" + }, + { + "path": "desktop/capture_desktop/daemon_link.py", + "git_blob": "620e5a753fbd8448c3a57fcfa6a8b8540ac0bcd0", + "bytes": 10899, + "sha256": "ab76628bbe0231c7e5e4d570f2abed01100dddd6a24bb62020b670a6b62427dd" + }, + { + "path": "desktop/capture_desktop/export_wizard.py", + "git_blob": "b22d0098eb9af3860c654591e411dbab68a0f05d", + "bytes": 6734, + "sha256": "fb957ff184109bcb4e379dde30414048e855c93ec390f9b50c7ab603c3cd4e30" + }, + { + "path": "desktop/capture_desktop/main.py", + "git_blob": "90ad2adebae1f52ffabb889efe43a31dca1b6454", + "bytes": 1059, + "sha256": "e61c29a1925f8d85b24438f087dec360a4481a32e0dc2bd8ed8feb6629026e84" + }, + { + "path": "desktop/capture_desktop/persistence.py", + "git_blob": "2f2da2bfda654009baa0e723465c82c1690a0676", + "bytes": 3379, + "sha256": "cdb1fa0094fec72543d5051435850e51d78d79d4bde8d5c83520fa072a2c74c4" + }, + { + "path": "desktop/capture_desktop/schema_form.py", + "git_blob": "2d5fa62b1448e168e639e3e8879989a3461e1053", + "bytes": 12206, + "sha256": "7d825b5dc7566d630f31775df6fcc9def1e916eaff5be17a552bf89f28b3418b" + }, + { + "path": "desktop/capture_desktop/screen_analysis.py", + "git_blob": "6893f119593f8ff6551167efcb1939d014a081e6", + "bytes": 19038, + "sha256": "1475764b8453ed870174fcaf98bc02370db76b5001c4175feb93263ad33d5b70" + }, + { + "path": "desktop/capture_desktop/screen_capture.py", + "git_blob": "b2d3cf05d57484f5efdbb0df85e5f0a065dab3d9", + "bytes": 34181, + "sha256": "4e101ddeeaed7f7f2b4ec2ab2e4b1f4f55ebb86f73b394d25cfd2b904cd2572e" + }, + { + "path": "desktop/capture_desktop/screen_presets.py", + "git_blob": "c143fb87629fb90f656a7a3b4b9f3c136b03f596", + "bytes": 5230, + "sha256": "b62d6f4bef6c1f0fc04b9eaf6a8afd1b2eeb17f6ce14946a06b0495ba33d402c" + }, + { + "path": "desktop/capture_desktop/screen_review.py", + "git_blob": "88a902ca7699faa2964f3fc22ec3348a339905a4", + "bytes": 7003, + "sha256": "e5aff59de4b194123ca4c4518b34e7b6103326fbd6b0280e2122d984d01072ec" + }, + { + "path": "desktop/capture_desktop/screen_settings.py", + "git_blob": "fe6d1e8884b7300e4cb5039b8e86679339e43b4d", + "bytes": 4581, + "sha256": "519436946827fac53d0be68270c2929bd1ce615a58b2372e9e3fc10619a7ba6e" + }, + { + "path": "desktop/capture_desktop/screen_setup.py", + "git_blob": "1df45aac30d63d6ab2e8ddc7efe0db394c513ab1", + "bytes": 11452, + "sha256": "01eb01ffffe835fcf5d26120d508800cc3cdac1e91ffaa3d0d2fa669c6326182" + }, + { + "path": "desktop/capture_desktop/state.py", + "git_blob": "95046ba5ef7f7bbf5685a54b7ae8fd400814148c", + "bytes": 17906, + "sha256": "97fc98498f4553fc7f052d0dc4db992cf2fc136ba7c4405cd275bd156c74e314" + }, + { + "path": "desktop/capture_desktop/theme.py", + "git_blob": "e309ce92bf66f65ca7c111698e1f536f05e4dca9", + "bytes": 12072, + "sha256": "c77f24e1afeb06400385bd0d535800f13dc15d972891e1ff8af504cbe5c818f3" + }, + { + "path": "desktop/capture_desktop/widgets_analysis_history.py", + "git_blob": "8798627cd7d694c5a09c3c402a739a4ec45b6574", + "bytes": 8458, + "sha256": "a3b77c87483c1412b50de7ddde1498f6bfd3968002fc3ac3bfa474a2477d9bc4" + }, + { + "path": "desktop/capture_desktop/widgets_analysis_jobs.py", + "git_blob": "c4d2f4513032d744f1f8066f0c887cda71d9b911", + "bytes": 6304, + "sha256": "5cdea6045456e61a58b5525dd224a22a140962d31d2adc5b0102168444468f98" + }, + { + "path": "desktop/capture_desktop/widgets_analysis_plots.py", + "git_blob": "bb6c3033b5e4ed96a2e08857d38715b836926bf5", + "bytes": 9382, + "sha256": "85c73f881ee7d60ef2f868f7ff73fc57c0a4ef99a717f7f5015534db23e1ab86" + }, + { + "path": "desktop/capture_desktop/widgets_analysis_scope.py", + "git_blob": "7b15a34fc1f8a9f31164d4ee9b4d144ff01a8d2d", + "bytes": 10391, + "sha256": "3f58ffba9125d0ce88fa99317f6aa593fe8aeb4b0dc1d799c95c9c04fb0b73ff" + }, + { + "path": "desktop/capture_desktop/widgets_mappings.py", + "git_blob": "62dd1b137ffc54a05aa81f37eb8627dd12e0032a", + "bytes": 3658, + "sha256": "89808d37cb0fce476665a24766963c7a509f5b1802d05dedbf9ca44351081f4b" + }, + { + "path": "desktop/capture_desktop/widgets_modality_expanded.py", + "git_blob": "70d67f7405730707ad67d1da0e71a7e87bf8b68e", + "bytes": 8566, + "sha256": "12db25b37e8b2724e5eaabdcb1810aa979633885097b6ec11c33d98a46a83a70" + }, + { + "path": "desktop/capture_desktop/widgets_preview.py", + "git_blob": "d0a760164a413616ab406a54d81c7b3f9b30d638", + "bytes": 27254, + "sha256": "78d79c9af67f7e0cbcee3a3a693a22e72753256ca465bab7edb9c2037822dec4" + }, + { + "path": "desktop/capture_desktop/widgets_radar_array.py", + "git_blob": "d270e7aa8b36a9a6376cfbd76a46ec6448bb9ae4", + "bytes": 2965, + "sha256": "be08874ade0b4d9197ea85cb6ae3b30db75273ddd3c426faaaf28b4f796653a8" + }, + { + "path": "desktop/capture_desktop/widgets_session_header.py", + "git_blob": "b1f4cbf5ab35ef06b4bf1da45f0be6ffb34b0a4a", + "bytes": 5749, + "sha256": "b9e11a7e3709283ed37bacbe96836d6720467f2bdcb934d75491df5dc02927fa" + }, + { + "path": "desktop/capture_desktop/widgets_session_timeline.py", + "git_blob": "2d9ba524b1e6231c934f6d037796a53e135a12f8", + "bytes": 10010, + "sha256": "7671ad4b632fd83498ad0c02f9030e4f46a0ef2d99a3764c13de3996e3c2ade4" + }, + { + "path": "desktop/pyproject.toml", + "git_blob": "dada23f8692dfda4c7c07fc012608844c7f41ab9", + "bytes": 552, + "sha256": "3646f83dcc0764b3c8cb198b98b03201dc47808bb80bfec4837e329e47bd012f" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/__init__.py", + "git_blob": "67a4fb257b771af771edb4010e573ceeab86a51f", + "bytes": 497, + "sha256": "14cfe6dccd33a0bda74fac3c9339e1a37a3538b2110a8ae6e307801b776eb43a" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/discover.py", + "git_blob": "d5c4fa7e06ac6e9139ebfc78fade90a3df5e451a", + "bytes": 4023, + "sha256": "344ee5d7cb0f5e95ac7524a0c1141b0a293bb9445e2bd4789c6736f39cfcb90d" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/eval/__init__.py", + "git_blob": "140fcb2784c4b73ddf69d21ddccfdcc8191cc0aa", + "bytes": 154, + "sha256": "54661df9ed7d7e0d4b1c2ab5941f107ceb608e4fdfaff810014ef5fad1431fe1" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/eval/job.py", + "git_blob": "95d40a6c28aabcdc311c18e3e195627f29ceb1a7", + "bytes": 3984, + "sha256": "a7f2a43c2fc3723c471e42a5532465dc5cfa44d4411c6cf581bba6910603fc57" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/features/__init__.py", + "git_blob": "e52dc3839105744e19193f8fc8067b818389a20b", + "bytes": 66, + "sha256": "3cdd6c626b6da12b8df56d8ddf35fca27c0a744865965ec01dd89d47da476fa1" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/features/emg.py", + "git_blob": "7f7536500a63ddc8b06774b8da65df8d56cd4f2b", + "bytes": 3072, + "sha256": "11f8f8350464b7c7c079353ca649b4c4aad2580ef8d355fe741c025c262b168e" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/features/imu.py", + "git_blob": "0ee47b3d579e4c3732634958dda21ae724beca9e", + "bytes": 2605, + "sha256": "246bfd1cc3ce72afa0680537062b6795e22b8a06ba6301503d7489a4440c6849" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/features/io.py", + "git_blob": "b998063a5036b73a67b773f70c193b1f9827c248", + "bytes": 1409, + "sha256": "c677d209292cca790ccdf1a64ba834f71a078ccce31ea57452e67ece358822ca" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/features/numeric_batch.py", + "git_blob": "77f19ccb048c93c0f4fca460eef0502180b37717", + "bytes": 4030, + "sha256": "ecdeb88ca4dd093b973294a53954e9fa0e5d6b4b908225a52d097ef70c7d2154" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/features/radar_doppler.py", + "git_blob": "ee20f7314cb1af4512901d6009f73e3dddf9025c", + "bytes": 2289, + "sha256": "cffc0ecbb8053fbc2244850c1927469366f4ae93b5439e4d194de2065877fa5c" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/features/radar_frame.py", + "git_blob": "e798dee0fb72dd261b504a99ac76f815515dda9e", + "bytes": 3323, + "sha256": "f85c5fe5e2db68606f68e36a42a0c8f323086f0b1e7f233c0ddefa24cdccb443" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/features/video_qc.py", + "git_blob": "fa73c80d39a0d699f80d7e877b37167cf8b48b6a", + "bytes": 1766, + "sha256": "0e25c50e01fc2da47bc7b510d68ba3e72aba33d3e1c79c57b727f5c55c723e27" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/grids.py", + "git_blob": "2e03f79d9317d2d97b721321130a9a5e6212b111", + "bytes": 1007, + "sha256": "936c5404783145f7a2bc4c13df22d3b85612bcb227115bba74f0b78a11c0c483" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/jobs.py", + "git_blob": "7badee5cdf5a4b30a283e0dcbb2c5d85fb787489", + "bytes": 19627, + "sha256": "e7e9dda44eb014d18192563f1e2c0ae78cece850fbc853b0be3919daaf5ee276" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/kinematics/__init__.py", + "git_blob": "aaf360b8a0085f89b95cd976857f0933596098a7", + "bytes": 178, + "sha256": "50a0f7fd39648abf269fc549d2c17eb48b1dc9add10ebdb76edc1935d6f80160" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/kinematics/compute.py", + "git_blob": "928751e9c861e2b0da298214269e57111f492865", + "bytes": 6899, + "sha256": "6e3ca19bfda0c02877f5d778f0c1191b5aebad605373732ef182bd714dd7f086" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/kinematics/job.py", + "git_blob": "fb8be113d8699427072f6dbcdae222a37738ac18", + "bytes": 4523, + "sha256": "d676e84f54aa1ae2b0f998c2cb37c4e02541c1fd0e3464e38e9865c0049a7239" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/kinematics/registry.py", + "git_blob": "a28cfd708c90552401fb0b3157c60f713a06e14f", + "bytes": 1155, + "sha256": "1e53fb9da4c6a2743bc1a3f0e687d94599cf995d33f2a2555e0ce5ebc3966d48" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/loaders/__init__.py", + "git_blob": "eb6fae21d4bb79055f8d1af1528e846020f21459", + "bytes": 361, + "sha256": "2d51c509baf3c0b5c33360637d12e5ce3c7507a859e4f37030f2c3d711ef0b3d" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/loaders/base.py", + "git_blob": "941a6aa3cea6777f90534ea634cccf8fdd319a3f", + "bytes": 2461, + "sha256": "696093b31f22d2bef32fc2962c7a11249a590a0b4d776c40cef4edcbc1e48a97" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/loaders/emg.py", + "git_blob": "c35d22af7bdeea570e6ae45a713428627e90894c", + "bytes": 3089, + "sha256": "86eb7114be689cdbd2edd76affa2994e7278714916692a35381abd02ba9d599a" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/loaders/imu.py", + "git_blob": "8823f04bd089789ca4cbff6602154bf066d4161d", + "bytes": 2773, + "sha256": "5ea4747145bf5588974dfd72c834766436c5a2bc0d58d34ace0f8ef403b310d6" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/loaders/mcap_iter.py", + "git_blob": "b61ca0a914e4d3909790839774327aa5824c1b71", + "bytes": 1196, + "sha256": "03a418e7689840e378665aac92c42769dd14ba2c88a821a5cbf0cee80766540c" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/loaders/numeric_batch.py", + "git_blob": "668e5397d6a603d8665fe639b3218128bbda72c2", + "bytes": 7139, + "sha256": "7c84c0425c1b9b821df711f4c40ea89ac13f267dbe6472922eb41a9263e4835c" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/loaders/radar_doppler.py", + "git_blob": "fc87bfb7fbbeb98ad8d5d11b3438b2d04882de6c", + "bytes": 1539, + "sha256": "4942d08eb47229839e339ce7f2f8a64aee7e5fab44bac77029fcd7a3e3e490c1" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/loaders/radar_frame.py", + "git_blob": "a44af5392ba2b5b8b64de685f42772b141f1b8b1", + "bytes": 1828, + "sha256": "d071f9d95b371798974698fd0caa1fc4c865a85fb772232fd43e7227b15fad2b" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/loaders/video.py", + "git_blob": "6a192cd5999b45df08c666b9dad21dc29cf91824", + "bytes": 2200, + "sha256": "3c3e873ab641904a39ca649dac39072f11948031d068cc21ee459e996d1fc185" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/ml_bundle/__init__.py", + "git_blob": "619d634ebf6fcc82a7871ad9c463660a24fd65ae", + "bytes": 179, + "sha256": "e785a2e3bf65852018d811b38ecbaf6ff9c479648025789145218809dd50d8a1" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/ml_bundle/job.py", + "git_blob": "59c2e4df46aa041e48aaf7184a3dd0ba345aff6d", + "bytes": 9419, + "sha256": "c14c74760e20c818ce5e2428d0b03a8a949899b0bba6c46e37fa8fd797631c75" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/pipeline.py", + "git_blob": "8113ab4cb51678a122bbb702a23f2200c9333233", + "bytes": 5262, + "sha256": "e8c0152040ba5b5f3f37ac53fb5188bac9dd9aaf0d5816d6a718be505c20898c" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/plots/modality.py", + "git_blob": "1de343cc2e11e663501ba190441325d5637d1492", + "bytes": 2419, + "sha256": "bc3aa15ee79d50280a6c9d6aa144fe0519f85dd2c74a0cfa99323f7d57ecd28d" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/plots/style.py", + "git_blob": "3725e840e5eb046accea79d4b6376f902392dac8", + "bytes": 1249, + "sha256": "231e7b1c998f4349d5859295007235ffd41848f12fbb7819193bec9630cd3942" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/plots/sync_dashboard.py", + "git_blob": "828204e998a46b9571b3a2b3ba08acd9fc6caa31", + "bytes": 1149, + "sha256": "6f9e0c64193688eb841565729b9d1e9a64136779e892419acabdc81591afd3d5" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/plugins/__init__.py", + "git_blob": "39c9c93eab1f5abf65ea73299c34b05ec184dd63", + "bytes": 225, + "sha256": "c511d4b9cd1cda042b781b06fbb02d2d99004de214735d6daeb459d6e41381fe" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/plugins/dummy.py", + "git_blob": "0152651c271234bf38252bed51efda3a3fc19c0f", + "bytes": 1618, + "sha256": "facf059d247bca44f2697383e12cc1296b1d1d12bede1196f4a52a1352d60495" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/plugins/handlers.py", + "git_blob": "03c8589064dfc4c6cfec6e4d00b7f46b10014414", + "bytes": 10646, + "sha256": "9be2e1820529b94e54d06790d53aa94cf658f982efb4063c6b64f9d07acc4b2e" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/plugins/manifest.yaml", + "git_blob": "0628968ee3965170b486306f974c81dd4eb84a53", + "bytes": 3876, + "sha256": "1efe3ee2d9eeeeac03c2c03c582edf0119c9abd6d214dfdca3d827fa10a5c048" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/plugins/numeric.py", + "git_blob": "d8adbc1d90dbfdeac0cd9179c95f027532c1a5d4", + "bytes": 3390, + "sha256": "75b55cb453095ad5470ce2532b65d3dce771e6a2f8ad1e46a538b4291fa4cf93" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/plugins/registry.py", + "git_blob": "3c582e1ab0de2b22956ac47fb628227eacdd1faf", + "bytes": 5389, + "sha256": "33a4d07600db8b116fbd46b67492f62129df513df5b66a2c455dced0b2a9dc69" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/pose/__init__.py", + "git_blob": "108be2956adfed6328f397d88a3b61ebada0ac48", + "bytes": 156, + "sha256": "d58a03cae86259b2cb0ecd0a5ce2347c6824f14cfea6871c94d76acc3541a380" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/pose/job.py", + "git_blob": "1a1a3f2436b0ac8decc551f84e76fa6c4c6e602d", + "bytes": 6262, + "sha256": "1f4c44f443c07e22e8c9ca877232c6780c4b1da7834d5565b82cf547b2f4c439" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/qc.py", + "git_blob": "530b86af1247599c127e2d0c3fa5e4d7d12169f6", + "bytes": 9187, + "sha256": "f24e0593a3723311d41054aef40b56c4bb46d4f3ba5ef4b01afcae3a6cc4440a" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/report_html.py", + "git_blob": "bb8032024cfce30c6fe9a2bd2c13b0d2cbc2d102", + "bytes": 4716, + "sha256": "f2c89c7faf6e4edc265540140272396b4195eb5aed9edf05c4912aac74286f03" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/types.py", + "git_blob": "2adf26816e0ef9e84e6763cf8bbff69d64697949", + "bytes": 3428, + "sha256": "e7996d02483f69265a2ef2ec0b28078c86f4f479daa53e38faf8b4a62645d02c" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/version.py", + "git_blob": "d04b8cc1dd9271ca3ccf836d97436d9a961417c6", + "bytes": 62, + "sha256": "9e25143344b110699f68b6acdbef49576fc91c2cbda34956d7e2cb85bbbc4ae3" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/windows.py", + "git_blob": "80bea6bd69365a48c5b204c26d054b8ae179437a", + "bytes": 5618, + "sha256": "af40235d55341d2a6b11d7f67a0195779676301fa822b2bd05240d138ee28c50" + }, + { + "path": "libs/python/capture_analysis/pyproject.toml", + "git_blob": "6db8b1158b14da660128d7ac0ceacb45b8eb9924", + "bytes": 677, + "sha256": "84cd96465e48439bdd81f5fa126fea5da11ee7587b488bfaaa67a4cd8f760c75" + }, + { + "path": "libs/python/capture_protocol/LICENSE", + "git_blob": "d645695673349e3947e8e5ae42332d0ac3164cd7", + "bytes": 11358, + "sha256": "cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30" + }, + { + "path": "libs/python/capture_protocol/NOTICE", + "git_blob": "7f9ac0678aa56452f06e6e5f3badc9a873e2008a", + "bytes": 124, + "sha256": "3efb470f58c900a58deaef889527e074206274b0fd5fb0e2e62613c093064307" + }, + { + "path": "libs/python/capture_protocol/capture_protocol/__init__.py", + "git_blob": "0e7ab2cf8689d3adbc689c283e8a23d12607b2d0", + "bytes": 698, + "sha256": "556f474a3d740adc03c40426acde432ab7a394b947f8268bd90eecc7832dff8a" + }, + { + "path": "libs/python/capture_protocol/capture_protocol/codec.py", + "git_blob": "3034065efca2c52e34c3e67e147bdda526d2c8db", + "bytes": 7011, + "sha256": "f6c09246a7b165358835e51b99b1508e68d840f4bdbd54b5fb72db33d4912712" + }, + { + "path": "libs/python/capture_protocol/capture_protocol/config_schema.py", + "git_blob": "c9b4a694e620e5597d338230fcb0f25ea3a757f6", + "bytes": 8444, + "sha256": "00d855895faec7d674cdb8e4da1ddc687888c9e9863f91d4950d24d9fb815e6e" + }, + { + "path": "libs/python/capture_protocol/capture_protocol/constants.py", + "git_blob": "2542cda6bdb6a83d4334336f34d92f80040bc4a0", + "bytes": 486, + "sha256": "7f187edf873cd13f55bc09ff7972785797eb488d74dd5befcb395fc928a71d72" + }, + { + "path": "libs/python/capture_protocol/capture_protocol/control_client.py", + "git_blob": "45e1c4b535ece8d7178cd6b32ab1affcc9e73e92", + "bytes": 20823, + "sha256": "68de412465b2eaa04886a2bb4566aa0595c898df7d7e782b3031b8ba919db7fa" + }, + { + "path": "libs/python/capture_protocol/capture_protocol/framing.py", + "git_blob": "9dd5021b815b31ab02eaaa814210525ebb543862", + "bytes": 2884, + "sha256": "3ff7c7284d9907a2ad516c83fab383a4151996da3f2d5a1d27e24d7c7575d92e" + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/__init__.py", + "git_blob": "16ae7d90a122b4973139c563ac0f72efa061b1de", + "bytes": 90, + "sha256": "1fac8216894ce1a1b5362de3b59398fbd78f005a59636aea9f074951bed5c1d7" + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/__init__.py", + "git_blob": "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", + "bytes": 0, + "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/__init__.py", + "git_blob": "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", + "bytes": 0, + "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/arrays_pb2.py", + "git_blob": "a29ed506c4dd33f697ba74d13b6e8a9c945c6b6d", + "bytes": 2876, + "sha256": "6355750076724275e49f9a5faec383b2be92c0336ed58805a88954964bd13b86" + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/common_pb2.py", + "git_blob": "66031212a0da44800dcc671b0d4bf0cd39e71f06", + "bytes": 9746, + "sha256": "6736e3b86b3c8749d34065794da1c880772ce69e2f248fdd2febd003f083bbd3" + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/control_pb2.py", + "git_blob": "0597489cf8609a76e2094270965039da9b739ca3", + "bytes": 20028, + "sha256": "f2eea386aebf830ec47fa7379e6fb0493e0a199efecc7b90974bc8bb8c8b96b6" + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/data/__init__.py", + "git_blob": "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", + "bytes": 0, + "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/data/emg_batch_pb2.py", + "git_blob": "d8495ebeb8ab140824eaa5412be0779cf929ec6a", + "bytes": 1624, + "sha256": "1db5ef51143a546072e34cc7be7b263db996fa5f4d0d71606b230cb75b531a14" + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/data/imu_frame_pb2.py", + "git_blob": "54bbf93dc638cdab95f49744ea7e0b43fefad374", + "bytes": 2222, + "sha256": "4a2048d2a737362bf26b99166e95c457d1492fcfba8848c894fe4d2748ff9f51" + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/data/numeric_batch_pb2.py", + "git_blob": "beedaaae054bfb083af3642c96ca7c64af14cc8d", + "bytes": 1454, + "sha256": "a087cc019b9849f4ef47bcdf4c789a7da90d443240b7bef97c832bb23c1d4e24" + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/data/radar_doppler_pb2.py", + "git_blob": "ad8fe84317d2f4049682f70bead19f90c6932457", + "bytes": 1773, + "sha256": "d1b85358aba0c2f4fc1745218463e9951224322604b18b068a2195359dcf790e" + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/data/radar_frame_pb2.py", + "git_blob": "cef636d7b030b037b23331eec9a86f3b152bc358", + "bytes": 1729, + "sha256": "995ddbbb0aa614afb15088cf039c741421c33ea3e3e963ef1a7361b24754b862" + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/data/video_timing_pb2.py", + "git_blob": "17937a141a9a2d81858cf52d74bc4705afc940b7", + "bytes": 1722, + "sha256": "002a79858ccd2d7763769a1fe1be6a16a7f6b8727d15f952d191bcd2240ba5ef" + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/events_pb2.py", + "git_blob": "030bd4a90be609403e7709605607d8d5b993776e", + "bytes": 5480, + "sha256": "72951a468b0480e7fefc4fd3f9b4caac5fda0abdadf4ffcca92d4f19286429ce" + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/health_pb2.py", + "git_blob": "b27bd32ec488168871ca2342062eb576d56a9e8e", + "bytes": 5898, + "sha256": "e1e0baa7073a9886e4d982d4f00020b490bfd46c32b1b4df129fd0477c1f5e61" + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/presets_pb2.py", + "git_blob": "d20925410185e5cf52bbc56e438534c1c5ff1102", + "bytes": 2066, + "sha256": "d27336594b548f2e6e7ae212fe6de198e6e699c62a5f27752f691d7928ccb27b" + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/preview_pb2.py", + "git_blob": "cb04387df1614a8b9d9755a702129bbbb8d6374e", + "bytes": 5333, + "sha256": "c992e91b9aef0aa0ec8d595eba2f7079889264d9e4de120b623afd1d8702c695" + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/project_pb2.py", + "git_blob": "a8e71f0a426858cc679cb87ce31d1379e70a2817", + "bytes": 3355, + "sha256": "983bc5715147297cdcecca343b9a450f2095fcc1e895859cc3c52a3213d933f5" + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/source_pb2.py", + "git_blob": "b72752efedc743d236713e51283dce923a526f55", + "bytes": 8053, + "sha256": "d15b443f27c910c0e809af19fed81d9c1a75f7112501df85877bf4bf9bc4f7a8" + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/storage_pb2.py", + "git_blob": "4dd1b48ab16900c5c3e88d9788cebf83ee93cc5a", + "bytes": 5487, + "sha256": "f7a7b8903af9bfc2d2a419622c86cc057aed2a898949e4261475a7ac61222474" + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/worker_pb2.py", + "git_blob": "7f3a4fc372384523638853f4bd458f49b664ba70", + "bytes": 11165, + "sha256": "112e832172913024c6fad128a9a9559bbcd14b18de06b1f2a3161ac380258dc0" + }, + { + "path": "libs/python/capture_protocol/capture_protocol/handshake.py", + "git_blob": "9386e73b3c1eecb683d9d0ca98ad415268e307af", + "bytes": 4763, + "sha256": "63f740c992edf8812f666b79f9cd866d9ea33e65e5b310a5ebda2f5ef98ac115" + }, + { + "path": "libs/python/capture_protocol/capture_protocol/structured_log.py", + "git_blob": "fc9c97b288280f4473c6b3c5b5e6ff07332fad49", + "bytes": 4657, + "sha256": "3d7883833286ecc004248294badcc0c66e44a57ecb7844ef281828d797b3c4fc" + }, + { + "path": "libs/python/capture_protocol/pyproject.toml", + "git_blob": "fa71ca45874d34076208507180c69c7a0e38fa76", + "bytes": 355, + "sha256": "61b2e33b2de2a153fb994144f532402c1b6b8ed02afb627ba0a15239e726ca71" + }, + { + "path": "libs/python/capture_session/capture_session/__init__.py", + "git_blob": "894e3c152a98b6e804de90122572afbcd929b3da", + "bytes": 2412, + "sha256": "da530f86c0d1d584862868ddba9f7087ccf5dfbddd64dd1e577337ecfd776419" + }, + { + "path": "libs/python/capture_session/capture_session/app_paths.py", + "git_blob": "46332cea7c62dd44247b219937ae6c8fbc747017", + "bytes": 561, + "sha256": "363e4522240e2356cac7492589cb207a798bc1af6031139bd1fa94890f1c4bfd" + }, + { + "path": "libs/python/capture_session/capture_session/package_reader.py", + "git_blob": "91fbf913c5af8489968425d7ceac51c04233d3e0", + "bytes": 6331, + "sha256": "9a1d9e6e7d24341a083cee602af9538413e948f3369b22660e484356e3d34eb1" + }, + { + "path": "libs/python/capture_session/capture_session/registry.py", + "git_blob": "c1d7799e1d2099424221b2f4af216a43a972c67a", + "bytes": 13989, + "sha256": "809b26ce8d8efc0559a3854cf85ea74b4e486fcd77d253ebfa76bade64b0a8d1" + }, + { + "path": "libs/python/capture_session/capture_session/settings_store.py", + "git_blob": "41b99cdaa78011d3d9b753c3131f32c72af9699f", + "bytes": 4622, + "sha256": "7719524a1f106cc54befcd21088810f9ec28f0160c8e88f60c374e1545fdb98d" + }, + { + "path": "libs/python/capture_session/pyproject.toml", + "git_blob": "c83450d780e97e5bd90feb48cef140917b6e47ff", + "bytes": 389, + "sha256": "3484887da96d4a2f32de8471b537d849f077b195c729ff0cc29307681e8d4895" + }, + { + "path": "libs/python/capture_worker/LICENSE", + "git_blob": "d645695673349e3947e8e5ae42332d0ac3164cd7", + "bytes": 11358, + "sha256": "cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30" + }, + { + "path": "libs/python/capture_worker/NOTICE", + "git_blob": "d74f1cbf89d4c89f70b3e75ab71cfadea8b7128f", + "bytes": 142, + "sha256": "2a7e69c4c7cd4e93a5cc9e9f984873a2d1276f465b91b10c71b951ebcfb2c588" + }, + { + "path": "libs/python/capture_worker/capture_worker/__init__.py", + "git_blob": "4bf1fc6b13bc4f5daab79d937ea89cf6c120cce3", + "bytes": 503, + "sha256": "c7ba88e956df8460002637eb3d8678a4c7217e680a388f833a22f073dc80f8fd" + }, + { + "path": "libs/python/capture_worker/capture_worker/__main__.py", + "git_blob": "a1047121f4173802074eeb66e5dcaf6c542c29c1", + "bytes": 150, + "sha256": "216422b76731bc985daa5fb0efe55a9d5ce600aa7e6081fa3df0c03afb6a893e" + }, + { + "path": "libs/python/capture_worker/capture_worker/cli.py", + "git_blob": "eb2d869f951f0205085b074d067282990657b5a0", + "bytes": 1818, + "sha256": "8a16c4cae0ffd11d4f9cd5d168f6abf1c6f9a4b5100e8edd18a29ce7d44d3f03" + }, + { + "path": "libs/python/capture_worker/capture_worker/preview.py", + "git_blob": "c47abe8a118ea022931843bde802132548194eef", + "bytes": 3202, + "sha256": "38b483dc06c9215b73e4c56c222fe563957180a5be58761a2c6dd4ea200b8e31" + }, + { + "path": "libs/python/capture_worker/capture_worker/transport.py", + "git_blob": "2e5e159bee3a0b5aa69bf90f62906feeffe23c8c", + "bytes": 5033, + "sha256": "020414c74bd08ec510e88da8c2f8b9ec5091a19cb585b4c54d2656b4bf300d35" + }, + { + "path": "libs/python/capture_worker/capture_worker/worker.py", + "git_blob": "d5ed2999fbb958116d73a8fa6319356d8b7d751a", + "bytes": 23439, + "sha256": "19a0dfd16a65479de884d4359a3d65f1bc127d8a6d4b44b93c6251757510de68" + }, + { + "path": "libs/python/capture_worker/capture_worker/writer.py", + "git_blob": "b3d194cc71dfa0d21884936a6ed5f7bdc95b3eb4", + "bytes": 6196, + "sha256": "b9e3b21ac26f2160da582a3f566a278dc4088c5a8b121d9b4e74f8d8c16cf96f" + }, + { + "path": "libs/python/capture_worker/pyproject.toml", + "git_blob": "5d79642edc9c1809fda636d5dcd78ad33e67abcc", + "bytes": 487, + "sha256": "0cba218b59a756185fedf72fb3a3307d1d9cb9218b6189ea92972d3cec139a46" + }, + { + "path": "pyproject.toml", + "git_blob": "52491c6beebc4b17983fc66bb8765154c33cf6d8", + "bytes": 1233, + "sha256": "0cb8de1ab3dfbfed84ff16b35f3c89c6440180183ee5851d5d80da83622e53d0" + }, + { + "path": "tests/analysis/test_numeric_batch_pipeline.py", + "git_blob": "9485adb27d02ab88e65d87576a06b86869a0360b", + "bytes": 19230, + "sha256": "43369bd0fea48d2c8b7dee1d8128b3bb131b508b7b0a14512fc457fcfdb0ba3c" + }, + { + "path": "tests/conftest.py", + "git_blob": "ad9b61fd8e9c1c3d74f91710d4e82dd7d899e6b4", + "bytes": 1773, + "sha256": "f669618fad17e906c91df7a1e9393fc7a54f458c6d62a4385436ba2622beca0e" + }, + { + "path": "tests/fixtures/mini_session/events/annotations.json", + "git_blob": "fe51488c7066f6687ef680d6bfaa4f7768ef205c", + "bytes": 3, + "sha256": "37517e5f3dc66819f61f5a7bb8ace1921282415f10551d2defa5c3eb0985b570" + }, + { + "path": "tests/fixtures/mini_session/events/checkpoints.json", + "git_blob": "fe51488c7066f6687ef680d6bfaa4f7768ef205c", + "bytes": 3, + "sha256": "37517e5f3dc66819f61f5a7bb8ace1921282415f10551d2defa5c3eb0985b570" + }, + { + "path": "tests/fixtures/mini_session/events/sync_anchors.json", + "git_blob": "fe51488c7066f6687ef680d6bfaa4f7768ef205c", + "bytes": 3, + "sha256": "37517e5f3dc66819f61f5a7bb8ace1921282415f10551d2defa5c3eb0985b570" + }, + { + "path": "tests/fixtures/mini_session/integrity.json", + "git_blob": "d10093b866427fcaed78a85e60e600d8657a86a7", + "bytes": 227, + "sha256": "af5d9bacd3eace7e831d48dee83eb5d9f578f4f4819d92218c4b55b0cb3ed556" + }, + { + "path": "tests/fixtures/mini_session/manifest.json", + "git_blob": "800dab5b41774bc043ebdee4714195770e75229b", + "bytes": 235, + "sha256": "c5254d3e4c0bc6a0ecaef124dc12d88117d647928a8e1725b71429097438d380" + }, + { + "path": "tests/fixtures/mini_session/processing/.gitkeep", + "git_blob": "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", + "bytes": 0, + "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + { + "path": "tests/fixtures/mini_session/sources/sim.emg.main/health/gaps.jsonl", + "git_blob": "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", + "bytes": 0, + "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + { + "path": "tests/fixtures/mini_session/sources/sim.emg.main/source.json", + "git_blob": "9528c95289b4b1b49d11d412b5ab2e3d019b4066", + "bytes": 112, + "sha256": "4e7626e51bfb804c27f83bf98ee186a47ec9f36fec0cbd7863ea8ecb1ecfbd10" + }, + { + "path": "tests/fixtures/mini_session/sources/sim.emg.main/streams/sim.emg.main.batch/segments/000000.mcap", + "git_blob": "320ce3607fadf57d05cf506987d045cf5b62ad9f", + "bytes": 28, + "sha256": "3c4d91b3bf5d48dcf54a598fff5b1b4ee42260b756d6f5df3986da496c6a9649" + }, + { + "path": "tests/fixtures/mini_session/sources/sim.emg.main/streams/sim.emg.main.batch/stream.json", + "git_blob": "12c4db8831572fc4ab3db9ba5f784fa236078e5f", + "bytes": 216, + "sha256": "8f8c02b89fd93e55643151e5222488e1174dd97a6b7a74f3ae5da8215b4d68e1" + }, + { + "path": "tests/fixtures/mini_session/sources/sim.imu.upper/source.json", + "git_blob": "fcc248c52b8319f5e7fd0067763b74640f0040dd", + "bytes": 118, + "sha256": "a6198f509edc557c1e1d8583a767a540962977751c80a1b6491e3d594b60c7a8" + }, + { + "path": "tests/fixtures/mini_session/sources/sim.imu.upper/streams/sim.imu.upper.frames/segments/000000.mcap", + "git_blob": "320ce3607fadf57d05cf506987d045cf5b62ad9f", + "bytes": 28, + "sha256": "3c4d91b3bf5d48dcf54a598fff5b1b4ee42260b756d6f5df3986da496c6a9649" + }, + { + "path": "tests/fixtures/mini_session/sources/sim.imu.upper/streams/sim.imu.upper.frames/stream.json", + "git_blob": "9c634d4af594372063fcc612331ba338ae95f8c9", + "bytes": 219, + "sha256": "ec39026bed1b833d4decb0ef7b0efb94c5557a5647bc50addc060bef3a30d50d" + }, + { + "path": "tests/ui/test_analysis_history.py", + "git_blob": "f013473f750b515a8305e2f7f8426b6520e26a65", + "bytes": 10465, + "sha256": "48175547922125c308fa49bbb84149e3dac8903902e7cc64fa7c15b4ca40eccd" + }, + { + "path": "workers/python_host/capture_sim/__init__.py", + "git_blob": "2646a1792544ac97cba76fd7d7246c313604351e", + "bytes": 259, + "sha256": "a3c8506a26d20b0b10cd55f00b019b7ddc1e2d4cb5cffd5c155d70ef338d21ae" + }, + { + "path": "workers/python_host/capture_sim/advertise.py", + "git_blob": "c93044ce53b7a38d2e7db9fcbad83174b394ffd2", + "bytes": 15205, + "sha256": "6a41dafed67d08d4e3829c053dc5a2767ae28293d63733b4b4ae187a8d4a94b9" + } + ], + "scope": "Exact Python/fixture slice for one native scope/history composition journey; no Windows MainWindow or complete suite claim.", + "prior_composed_runtime_tree": "07d78241dca691015bb3e4d8d260b109672b7de0", + "isolation": "Unchanged immutable source leaves may reuse only this worker's frozen receiving slice via hard links; the sole changed screen must be independently written. Both trees are checked for unchanged bytes." +} diff --git a/docs/evidence/analysis-history-401c5d17da79/current-scope/check_scope_history.py b/docs/evidence/analysis-history-401c5d17da79/current-scope/check_scope_history.py new file mode 100644 index 00000000..8e4b3973 --- /dev/null +++ b/docs/evidence/analysis-history-401c5d17da79/current-scope/check_scope_history.py @@ -0,0 +1,272 @@ +# SPDX-License-Identifier: GPL-3.0-only +"""One real native scope/history journey on the received current source.""" +from pathlib import Path +import argparse +import base64 +import hashlib +import importlib.util +import json +import os +import sys +import time +import traceback + + +def hashes(root, raw_only=False): + return {p.relative_to(root).as_posix(): hashlib.sha256(p.read_bytes()).hexdigest() + for p in sorted(root.rglob("*")) if p.is_file() + and (not raw_only or "processing" not in p.relative_to(root).parts)} + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--source", type=Path, required=True) + parser.add_argument("--inputs", type=Path, required=True) + parser.add_argument("--output", type=Path, required=True) + args = parser.parse_args() + source, output = args.source.resolve(), args.output.resolve() + assert source != output and source not in output.parents and not output.exists() + inputs = json.loads(args.inputs.read_bytes()) + expected = {row["path"]: row["sha256"] for row in inputs["files"]} + assert hashes(source) == expected + output.mkdir(parents=True) + for key, name in [("LOCALAPPDATA", "local"), ("APPDATA", "roaming"), + ("XDG_CONFIG_HOME", "config"), ("XDG_DATA_HOME", "data"), + ("XDG_CACHE_HOME", "cache"), ("MPLCONFIGDIR", "mpl"), + ("TMPDIR", "tmp"), ("XDG_RUNTIME_DIR", "runtime")]: + directory = output / "state" / name + directory.mkdir(parents=True, mode=0o700) + os.environ[key] = str(directory) + os.environ["QT_QPA_PLATFORM"] = "offscreen" + sys.dont_write_bytecode = True + for rel in reversed(["desktop", "libs/python/capture_analysis", "libs/python/capture_session", + "libs/python/capture_protocol", "libs/python/capture_protocol/capture_protocol/generated", + "libs/python/capture_worker"]): + sys.path.insert(0, str(source / rel)) + report = {"canonical_parent": inputs["canonical_parent"], "runtime_tree": inputs["composition_tree"], + "screen_git_blob": inputs["composed_screen_git_blob"], "checks": [], "errors": [], + "method": "QApplication.exec/QTimer; actual SessionHeader and AnalysisScreen, two real QThread/MCAP feature jobs", + "method_sha256": hashlib.sha256(Path(__file__).read_bytes()).hexdigest(), + "source_inputs_sha256": hashlib.sha256(args.inputs.read_bytes()).hexdigest(), + "scope": "One changed scope/history boundary. No Windows MainWindow, full-suite, nested-image repair or installed-release claim."} + + def check(name, condition, *, fatal=True): + report["checks"].append({"name": name, "passed": bool(condition)}) + if fatal: + assert condition, name + + try: + import PySide6 + from PySide6.QtCore import QBuffer, QCoreApplication, QEvent, QIODevice, QTimer, Qt + from PySide6.QtTest import QTest + from PySide6.QtWidgets import QApplication, QMessageBox, QPlainTextEdit, QVBoxLayout, QWidget + from capture_desktop import theme + from capture_desktop.screen_analysis import AnalysisScreen + from capture_desktop.state import CaptureState + from capture_desktop.widgets_session_header import SessionHeader + helper_path = source / "tests/analysis/test_numeric_batch_pipeline.py" + spec = importlib.util.spec_from_file_location("current_numeric_fixture", helper_path) + fixture = importlib.util.module_from_spec(spec) + spec.loader.exec_module(fixture) + + def package(name): + root = output / (name + ".mmsession") + root.mkdir() + (root / "manifest.json").write_text(json.dumps({"sessionId": name, "state": "sealed"}) + "\n") + stream = root / "sources/lsl/streams/numeric" + stream.mkdir(parents=True) + fixture._write_mcap(stream / "segments/000000.mcap", [(1_000_000_000, fixture._batch())]) + (stream / "stream.json").write_text(json.dumps({"sourceId": "lsl", "streamId": "numeric.stream", "modality": "eeg", "dataSchemaId": "generic.numeric_batch/1", "nominalRateHz": 2.0, "units": "V", "dimensions": [2]}) + "\n") + return root + + first, second = package("scope history A"), package("scope history B") + raw_before = {str(p): hashes(p, raw_only=True) for p in [first, second]} + app = QApplication([]) + theme.apply_theme(app, setting="dark") + shell = QWidget() + layout = QVBoxLayout(shell) + header, screen = SessionHeader(), AnalysisScreen(CaptureState()) + layout.addWidget(header) + layout.addWidget(screen, 1) + header.scope_changed.connect(screen.set_scope) + + def package_loaded(summary): + if summary is None: + header.clear() + else: + header.refresh_sealed(summary, selection=screen.scope) + + screen.package_loaded.connect(package_loaded) + shell.resize(1280, 1050) + shell.show() + picker = header._scope_picker + state = {"phase": "start", "deadline": time.monotonic() + 50, "dialogs": [], "cancelled": False} + ranges = [(1_500_000_001, 2_500_000_001), (1_000_000_001, 2_000_000_001)] + + def choose(bounds): + picker._mode.setCurrentIndex(picker._mode.findData("range")) + picker._start.setText(f"{bounds[0] // 10**9}.{bounds[0] % 10**9:09d}") + picker._end.setText(f"{bounds[1] // 10**9}.{bounds[1] % 10**9:09d}") + + def jobs(root): + directory = root / "processing/jobs" + return set(directory.iterdir()) if directory.exists() else set() + + def assert_job(job, bounds): + params = json.loads((job / "params.json").read_bytes()) + manifest = json.loads((job / "job_manifest.json").read_bytes()) + check("real saved job retains its exact selected nanosecond parameters", + (params["startSessionNs"], params["endSessionNs"]) == bounds and params["checkpointSection"] is None) + check("completed current numeric job reports that selected interval", + (manifest["timeRange"]["startSessionNs"], manifest["timeRange"]["endSessionNs"]) == bounds + and manifest["status"] == "completed_with_warnings") + check("successful saved job contains only the two expected fixture metadata warnings", + manifest["warnings"] == [ + "package state is 'sealed' (prefer finalized)", + "package duration_ns is unknown/zero — analysis uses an open time window (integrity entries lack endSessionTimeNs)", + ]) + report.setdefault("saved_job_manifests", []).append(manifest) + return params, manifest + + def finish(): + timer.stop() + shell.close() + app.quit() + + def tick(): + try: + modal = QApplication.activeModalWidget() + if isinstance(modal, QMessageBox): + state["dialogs"].append(modal.text()) + modal.accept() + if state["cancelled"]: + if screen._thread is None: + finish() + return + if time.monotonic() > state["deadline"]: + raise TimeoutError("The bounded native scope/history journey did not finish.") + phase = state["phase"] + if phase == "start": + screen.set_package(str(first) + "/.") + check("screen, header and history use one normalized package identity", + screen.package_path == header.package_path == screen._history.package == str(first)) + screen._command.setCurrentIndex(screen._command.findData("features")) + choose(ranges[0]) + check("real header selection enables the composed Analysis screen with exact bounds", + screen._btn_run.isEnabled() and screen.scope is picker.selection + and (screen.scope.start_ns, screen.scope.end_ns) == ranges[0]) + QTest.mouseClick(screen._btn_run, Qt.MouseButton.LeftButton) + check("real feature worker disables saved-history actions while running", + screen._thread is not None and not screen._history._open.isEnabled() + and not screen._history._refresh.isEnabled(), fatal=False) + report["initial_busy_state"] = {"thread_retained": screen._thread is not None, "thread_running": screen._thread.isRunning() if screen._thread is not None else False, "history_refresh_enabled": screen._history._refresh.isEnabled(), "history_open_enabled": screen._history._open.isEnabled()} + state["phase"] = "first-job" + elif phase == "first-job" and screen._thread is None: + check("the first real worker completes without a modal failure", not state["dialogs"]) + check("settled first job restores native Run and history controls", + screen._btn_run.isEnabled() and not screen._btn_cancel.isEnabled() + and screen._history._refresh.isEnabled() and screen._history._open.isEnabled() + and screen._history._details.isEnabled()) + check("completed scoped job reaches the saved-history viewer", + len(jobs(first)) == 1 and bool(screen._last_job_dir) + and screen._history.loaded_job_id == Path(screen._last_job_dir).name) + job = Path(screen._last_job_dir) + assert_job(job, ranges[0]) + state["first_job"] = job + state["saved_bytes"] = hashes(job) + choose(ranges[1]) + selected = screen.scope + QTest.mouseClick(screen._history._refresh, Qt.MouseButton.LeftButton) + QTest.mouseClick(screen._history._open, Qt.MouseButton.LeftButton) + check("explicitly reopening the old job preserves the next selected scope", + screen.scope == picker.selection == selected + and (selected.start_ns, selected.end_ns) == ranges[1]) + check("reopen is read-only and starts no additional worker", + hashes(job) == state["saved_bytes"] and jobs(first) == {job} + and screen._thread is None) + QTest.mouseClick(screen._history._details, Qt.MouseButton.LeftButton) + dialog = screen._history._dialog + params_editor = dialog.findChild(QPlainTextEdit, "analysisHistoryParameters") + saved_params = json.loads(params_editor.toPlainText()) + check("native read-only details show the saved scope, distinct from the next selection", + params_editor.isReadOnly() + and (saved_params["startSessionNs"], saved_params["endSessionNs"]) == ranges[0] + and screen.scope == selected) + dialog.close() + screen.set_package(str(first) + "/.") + check("same-package refresh preserves both scope and loaded saved result", + screen.scope == picker.selection == selected + and screen._history.loaded_job_id == job.name) + state["phase"] = "capture-and-second-job" + elif phase == "capture-and-second-job": + buffer = QBuffer() + buffer.open(QIODevice.OpenModeFlag.WriteOnly) + captured = shell.grab().save(buffer, "PNG") + frame = bytes(buffer.data()) + buffer.close() + check("combined native frame is captured", captured and frame.startswith(b"\x89PNG\r\n\x1a\n")) + report["native_frame"] = {"filename": "scope-history-reopened.png", "bytes": len(frame), "sha256": hashlib.sha256(frame).hexdigest(), "base64": base64.b64encode(frame).decode()} + state["jobs_before_second"] = jobs(first) + QTest.mouseClick(screen._btn_run, Qt.MouseButton.LeftButton) + check("a second real worker starts from the next selection", screen._thread is not None) + # The current application may change package context while a + # worker is pending. Its real queued completion must stay A. + screen.set_package(str(second)) + check("changing package resets scope and clears history as one transition", + screen.package_path == header.package_path == screen._history.package == str(second) + and screen.scope.mode == picker.selection.mode == "full" + and not screen._last_job_dir and not screen._history.loaded_job_id) + state["phase"] = "second-job" + elif phase == "second-job" and screen._thread is None: + completed = jobs(first) - state["jobs_before_second"] + check("late real completion is retained under its originating package only", + len(completed) == 1 and not jobs(second) and not state["dialogs"]) + second_job = next(iter(completed)) + assert_job(second_job, ranges[1]) + check("late foreign completion cannot repaint current history or scope", + screen.package_path == str(second) and screen.scope.mode == picker.selection.mode == "full" + and not screen._last_job_dir and not screen._history.loaded_job_id + and "Result saved for the previous package" in screen._log.toPlainText()) + check("late-job settlement restores controls for the current package only", + screen._btn_run.isEnabled() and not screen._btn_cancel.isEnabled() + and screen._history._refresh.isEnabled() and not screen._history._open.isEnabled()) + check("the prior reopened job remains byte-identical after the second job", + hashes(state["first_job"]) == state["saved_bytes"]) + check("both real package raw inputs remain byte-identical", + all(hashes(p, raw_only=True) == raw_before[str(p)] for p in [first, second])) + report["real_jobs"] = [str(state["first_job"]), str(second_job)] + report["raw_package_hashes"] = raw_before + report["last_native_log"] = screen._log.toPlainText() + report["dialogs"] = state["dialogs"] + finish() + except BaseException: + report["errors"].append(traceback.format_exc()) + state["cancelled"] = True + if screen._thread is not None: + screen._cancel_job() + else: + finish() + + timer = QTimer() + timer.timeout.connect(tick) + timer.start(15) + report["event_loop_exit"] = app.exec() + shell.deleteLater() + QCoreApplication.sendPostedEvents(None, QEvent.Type.DeferredDelete) + app.processEvents() + report["pyside6"] = PySide6.__version__ + report["python"] = sys.version + except BaseException: + report["errors"].append(traceback.format_exc()) + report["source_unchanged"] = hashes(source) == expected + report["passed"] = sum(row["passed"] for row in report["checks"]) + report["failed"] = sum(not row["passed"] for row in report["checks"]) + report["exit_code"] = 0 if not report["errors"] and not report["failed"] and report["source_unchanged"] else 1 + # Emit the complete native receipt and frame before the caller persists them. + # Package/job writes stay real; artifact transport cannot erase an outcome. + print("HAMON_SCOPE_HISTORY_RECEIPT " + json.dumps(report, separators=(",", ":")), flush=True) + return report["exit_code"] + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/docs/evidence/analysis-history-401c5d17da79/current-scope/custody.json b/docs/evidence/analysis-history-401c5d17da79/current-scope/custody.json new file mode 100644 index 00000000..ea5d347c --- /dev/null +++ b/docs/evidence/analysis-history-401c5d17da79/current-scope/custody.json @@ -0,0 +1,100 @@ +{ + "schema": "hamon.exact-source-custody.v1", + "source_and_method_destination": "/Users/me/hamon/estate-401c5d17da79/capturesuite-history/scope-prepared-6893f119", + "prepared_checkpoint": { + "schema": "hamon.prepared-source-custody.v1", + "root": "/Users/me/hamon/estate-401c5d17da79/capturesuite-history/scope-prepared-6893f119", + "uid": 501, + "canonical_parent": "3e3ecc5ecc1cfc79c79901eb5cffe10b0ec5852e", + "runtime_tree": "167bbac3bba862cc1532d954fe2d503e561a00df", + "candidate_screen_blob": "6893f119593f8ff6551167efcb1939d014a081e6", + "files": [ + { + "path": "screen_analysis.py", + "bytes": 19038, + "sha256": "1475764b8453ed870174fcaf98bc02370db76b5001c4175feb93263ad33d5b70" + }, + { + "path": "check_scope_history.py", + "bytes": 16423, + "sha256": "c45eb2b2b02b8c9423565d811ae7782eff576b1313bf5cef366c4af8bf4e3802" + }, + { + "path": "candidate-source-inputs.json", + "bytes": 36983, + "sha256": "7e2d4d219c8a4b70865f780750fa8fe5362da54a43898097082a44784f807438" + }, + { + "path": "correction.diff", + "bytes": 411, + "sha256": "a673362be10374234e4c0a7747db5dc0ebe4d197c9053a8791204b703cbeb79d" + }, + { + "path": "startup-negative.json", + "bytes": 1711, + "sha256": "5c31757b0432077a91140cb4deb60503f83e353cb4eb2e1fe9c384a76e6e36f6" + } + ], + "preparation_sha256": "047a3ec794ef2037c116ab68de6544f191163909498d58fea13ab4dbb6c95e1a", + "source_blobs_and_changed_trees_verified": true, + "native_acceptance": "Pending actual corrected native journey; this checkpoint preserves source and receiver, not acceptance." + }, + "prepared_checkpoint_sha256": "3f1fdce7f3db1506b8f617adb3eb6b930e0af4aa3eb4eb225c2e3ff9b00e8d67", + "qualified_receiving_destination": "/Users/me/hamon/estate-401c5d17da79/capturesuite-history/scope-prepared-6893f119/qualified-receiving", + "qualified_checkpoint": { + "schema": "hamon.native-receiving-custody.v1", + "root": "/Users/me/hamon/estate-401c5d17da79/capturesuite-history/scope-prepared-6893f119/qualified-receiving", + "runtime_tree": "167bbac3bba862cc1532d954fe2d503e561a00df", + "screen_git_blob": "6893f119593f8ff6551167efcb1939d014a081e6", + "method_sha256": "c45eb2b2b02b8c9423565d811ae7782eff576b1313bf5cef366c4af8bf4e3802", + "native_platform": "Linux Python3.12/PySide6 6.11.2 from the established CaptureSuite environment; Mac is custody only", + "process_exit_code": 0, + "checks_passed": 24, + "checks_failed": 0, + "seconds": 3.534, + "raw_stdout_and_stderr_sha_verified": true, + "frame_extracted_and_read_back_exact": true, + "files": [ + { + "path": "README.md", + "bytes": 3748, + "sha256": "983f657b0ab4bc194c16cb3938d2494d110ecd3fd5f4c0de7890f6f0b8de306e" + }, + { + "path": "native.stderr.log", + "bytes": 250, + "sha256": "bcd516d5e9014bd0f43bf526bc701b744bbd4ea9c35d16fdd65e6fde7b0270d5" + }, + { + "path": "native.stdout.log", + "bytes": 268056, + "sha256": "aab4b265957f5404474d87c430bb03167b3514fb8fb05399e23cf5534f4b9c70" + }, + { + "path": "process.json", + "bytes": 817, + "sha256": "668d3732d79062b8390c6f9b2660bebca1b1deb566b0852a049d7a952fc217f6" + }, + { + "path": "receipt.json", + "bytes": 13734, + "sha256": "2b7114760bd212372ae1071c4954e1904724010c486cbff510f254f1f2fa9471" + }, + { + "path": "receiving.json", + "bytes": 2196, + "sha256": "31e28e425b8dfc74b5224418671d6720cd3ddc86a2fd7fae0ba2e5210330403f" + }, + { + "path": "scope-history-reopened.png", + "bytes": 193004, + "sha256": "c8ec0afb810a76da3254e035cdac3a5e0ec46097976743e1917e672441a550f5" + } + ], + "qualification_scope": "One current scope/history journey; original 37443/72c15 acceptance and e43 QC remain separate." + }, + "qualified_checkpoint_sha256": "69757fc3f931d781c999a728e7ae3d381999c94a267f3d93d961cc5f6f7c5059", + "verification": "Both checkpoints were independently read back through RDC and SHA-256 matched. Full final native stdout and its embedded original PNG are preserved in the qualified receiving destination.", + "prior_0ed_packet": "/Users/me/hamon/estate-401c5d17da79/capturesuite-history/source-pr-0ed1ccaa-2355dee/packet", + "prior_0ed_checkpoint_sha256": "7ec1926ff45e95b1034cbd0b14919fcfcd5896ee4a7ac63b0f70a9450d651839" +} diff --git a/docs/evidence/analysis-history-401c5d17da79/current-scope/freshness-d43.json b/docs/evidence/analysis-history-401c5d17da79/current-scope/freshness-d43.json new file mode 100644 index 00000000..1711f6fe --- /dev/null +++ b/docs/evidence/analysis-history-401c5d17da79/current-scope/freshness-d43.json @@ -0,0 +1,346 @@ +{ + "schema": "hamon.capture-history-publication-freshness.v1", + "repository": "Jacob-Met/CaptureSuite", + "qualified_parent": "3e3ecc5ecc1cfc79c79901eb5cffe10b0ec5852e", + "latest_observed_main": "d43bdea867d6198a707a5f55e29216c76054517e", + "source_url": "https://api.github.com/repos/Jacob-Met/CaptureSuite/compare/3e3ecc5ecc1cfc79c79901eb5cffe10b0ec5852e...d43bdea867d6198a707a5f55e29216c76054517e", + "compare_html_url": "https://github.com/Jacob-Met/CaptureSuite/compare/3e3ecc5ecc1cfc79c79901eb5cffe10b0ec5852e...d43bdea867d6198a707a5f55e29216c76054517e", + "base_commit": "3e3ecc5ecc1cfc79c79901eb5cffe10b0ec5852e", + "merge_base_commit": "3e3ecc5ecc1cfc79c79901eb5cffe10b0ec5852e", + "status": "ahead", + "ahead_by": 3, + "behind_by": 0, + "total_commits": 3, + "commits": [ + { + "sha": "0dd591b41bea35ce0639bba312d6f56b77f68088", + "parents": [ + "e43da3b855475c8aacf815c201fa03eddaeec0f1" + ], + "message": "Preserve missing pose evidence in kinematic labels\n\nMask non-simulated landmarks by each joint's required finite geometry and confidence instead of selecting synthetic fallback angles. Retain independent limb validity and NaN velocity/AFR values at invalid frames, with unchanged complete-geometry and explicit-sim Parquet bytes.\n\nReceive the frozen 21-test native author result, independent four-workflow/36-assertion CLI review, and one current-QC/report CLI composition check. Preserve all 777 unrelated current-main leaves and the complete current progress log. Existing supported Windows CI remains required before merge.\n\nCloses #56" + }, + { + "sha": "711e8ec22d462b7588e52727cf3d6524d7524c7a", + "parents": [ + "0dd591b41bea35ce0639bba312d6f56b77f68088", + "284d168d7614e2465bafba1092d8cbe4b6e13b40" + ], + "message": "Merge current main and retain both kinematics and storage progress entries\n\nPreserve all37 frozen non-PROGRESS contribution leaves and all815 unrelated current-main leaves. Resolve only the concurrent PROGRESS prepend, retaining the exact current log plus the original1527-byte entry. Runtime, regression tests and receiving evidence are unchanged." + }, + { + "sha": "d43bdea867d6198a707a5f55e29216c76054517e", + "parents": [ + "3e3ecc5ecc1cfc79c79901eb5cffe10b0ec5852e", + "711e8ec22d462b7588e52727cf3d6524d7524c7a" + ], + "message": "Preserve missing pose evidence in kinematic labels\n\nKeep absent or invalid non-simulated pose geometry masked independently for each elbow and shoulder. Preserve complete-input and explicit-simulation math; only explicit sim_ models select fixture equations.\n\nQualified source head 711e8ec22d462b7588e52727cf3d6524d7524c7a with the current desktop scope and Windows atomic-write changes in actual CI checkout dc9ab33f4b3f3aefbb6308bbffb4e3f041d4b524, tree fea0e03773742d330963b89e0ceb72a22c7ad495. Windows run 37786404581 passed 400 Python tests with six missing-daemon skips, all 30 CTests, and all six separate native daemon/recovery cases without skips. All existing workflow gates remain unchanged.\n\nIndependent real CLI receiving passed 4/4 cases and36 assertions; baseline complete geometry and explicit sim Parquet bytes remain exact. All37 non-progress contribution leaves, all current unrelated leaves and the complete prior progress log were received from current3e3ecc5e. Original negative evidence and both CI generations are preserved. No installed release or physical measurement claim.\n\nCloses #56." + } + ], + "files": [ + { + "filename": "docs/design/KINEMATICS_PIPELINE.md", + "status": "modified", + "sha": "4206818b8834c56db530ca939b04cfe59e73aff6", + "additions": 24, + "deletions": 0, + "changes": 24 + }, + { + "filename": "docs/design/research/PROGRESS.md", + "status": "modified", + "sha": "36b05b80604935e3c70d1f076be5150e8639c164", + "additions": 24, + "deletions": 0, + "changes": 24 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/author/README.md", + "status": "added", + "sha": "5eee94afdfc2af12ad806fb816c3a9bf7f56f480", + "additions": 113, + "deletions": 0, + "changes": 113 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/author/author-receipt.json", + "status": "added", + "sha": "c51c2acc07ef57aae579c908f1fe3c31bb4b472c", + "additions": 60, + "deletions": 0, + "changes": 60 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/author/baseline-native-readback.json", + "status": "added", + "sha": "2110facf1a59ad9c1656aed76a09fad3cf8496cf", + "additions": 7, + "deletions": 0, + "changes": 7 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/author/baseline-runtime.tar.gz", + "status": "added", + "sha": "e973cff1bb0a0bffd768bf9fcef5400834ab2280", + "additions": 0, + "deletions": 0, + "changes": 0 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/author/baseline-source-manifest.json", + "status": "added", + "sha": "90416594a540a5227a70071b7597c87b291ff8de", + "additions": 812, + "deletions": 0, + "changes": 812 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/author/baseline-tests.json", + "status": "added", + "sha": "dc03cfdffaabb0209fd855482e78abb21179a658", + "additions": 298, + "deletions": 0, + "changes": 298 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/author/baseline-tests.log", + "status": "added", + "sha": "16860275d5331b2398cf48b0a2dca14601534df8", + "additions": 289, + "deletions": 0, + "changes": 289 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/author/baseline-tests.xml", + "status": "added", + "sha": "ed4db6467dd4d1410cc51e45097269ced09ef5c6", + "additions": 232, + "deletions": 0, + "changes": 232 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/author/candidate-native-readback.json", + "status": "added", + "sha": "369ab414496f49d86b28afa8a7a78b6b1e7a4e92", + "additions": 12, + "deletions": 0, + "changes": 12 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/author/candidate-source-manifest.json", + "status": "added", + "sha": "4fb157009d615aef9c7e000355df2d1750d56392", + "additions": 35, + "deletions": 0, + "changes": 35 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/author/candidate-tests.json", + "status": "added", + "sha": "15e3c7ebfc9af89e52f7d9ad5c31aaac0bf22d9f", + "additions": 301, + "deletions": 0, + "changes": 301 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/author/candidate-tests.log", + "status": "added", + "sha": "c124b9b2ffcbebd9cc3e5f87ac061017abf78741", + "additions": 12, + "deletions": 0, + "changes": 12 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/author/candidate-tests.xml", + "status": "added", + "sha": "6c202590a276a097c6b037d7939dce273fc5aaf2", + "additions": 1, + "deletions": 0, + "changes": 1 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/author/environment.json", + "status": "added", + "sha": "345664d3eb842ccc52018d36bd81cd9e892463ff", + "additions": 19, + "deletions": 0, + "changes": 19 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/author/manifest.json", + "status": "added", + "sha": "e96529b2c4475276c8483ca62414875ff049b596", + "additions": 100, + "deletions": 0, + "changes": 100 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/author/product.patch", + "status": "added", + "sha": "5f5581fb530ed1ee5f45ae89116dd772b2c00ca8", + "additions": 430, + "deletions": 0, + "changes": 430 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/author/static-checks.json", + "status": "added", + "sha": "fb1093707700a5fbbc746d7fcb3d4d6a29f6f0c6", + "additions": 28, + "deletions": 0, + "changes": 28 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/author/test-artifact-manifest.json", + "status": "added", + "sha": "b84b3cbc9bc474efa700cc7e1d632b162628ef1a", + "additions": 1665, + "deletions": 0, + "changes": 1665 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/author/test-artifacts.tar.gz", + "status": "added", + "sha": "692f10a8452e12ef0060177a89648ba0e247e9fc", + "additions": 0, + "deletions": 0, + "changes": 0 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/author/test_kinematics_validity.py", + "status": "added", + "sha": "7cf66857bcbeb9b72851ad53ce7c08f97d528fc8", + "additions": 202, + "deletions": 0, + "changes": 202 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/current/README.md", + "status": "added", + "sha": "5e3b6e546922665e6639b3a4f49c837983fc56f5", + "additions": 43, + "deletions": 0, + "changes": 43 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/current/junit.xml", + "status": "added", + "sha": "e574c6fab6ed3890ac856040421e2a576f385607", + "additions": 1, + "deletions": 0, + "changes": 1 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/current/manifest.json", + "status": "added", + "sha": "741306eabe2798bdc0927e34773cf9f7478b312a", + "additions": 51, + "deletions": 0, + "changes": 51 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/current/process.log", + "status": "added", + "sha": "7e1ead8287c87a8d972a2cf50390981926c5dd1a", + "additions": 12, + "deletions": 0, + "changes": 12 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/current/receipt.json", + "status": "added", + "sha": "75d0d3aee60e47679da6672ee3e9c8ec07b16d8f", + "additions": 300, + "deletions": 0, + "changes": 300 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/current/receive-current-seam.cjs", + "status": "added", + "sha": "cdc7717acd47e6776ca9c1afc100e429cc6e5ea9", + "additions": 16, + "deletions": 0, + "changes": 16 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/current/source-manifest.json", + "status": "added", + "sha": "6cb4dfce021abbeaff5e7e1b36f10c5822c9cdb6", + "additions": 818, + "deletions": 0, + "changes": 818 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/current/test-artifact-manifest.json", + "status": "added", + "sha": "4747226f7cb788048bdf0593ad3f82911da0b4eb", + "additions": 130, + "deletions": 0, + "changes": 130 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/current/test-artifacts.tar.gz", + "status": "added", + "sha": "30a23f4ce7066ac1db085ea21179b763f3ad0829", + "additions": 0, + "deletions": 0, + "changes": 0 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/independent/README.md", + "status": "added", + "sha": "355804bd71cd836250a57126b3fee28a47f233be", + "additions": 13, + "deletions": 0, + "changes": 13 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/independent/independent-cli-artifacts.tar.gz", + "status": "added", + "sha": "739fc581cae5561014b45049f225a2d4abdc2a6f", + "additions": 0, + "deletions": 0, + "changes": 0 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/independent/manifest.json", + "status": "added", + "sha": "b58ee77faebd30f53581475d4f4a931cf54c64e6", + "additions": 30, + "deletions": 0, + "changes": 30 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/independent/receiving.json", + "status": "added", + "sha": "4e63e2efd9e71728329abf66fe283597ee8ee815", + "additions": 59, + "deletions": 0, + "changes": 59 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/independent/source-review.json", + "status": "added", + "sha": "bbfb3c062188f4287388741cfd526d07249f5177", + "additions": 26, + "deletions": 0, + "changes": 26 + }, + { + "filename": "libs/python/capture_analysis/capture_analysis/kinematics/compute.py", + "status": "modified", + "sha": "fb8be59b00e15d9c264aad0983cf75a757c9e210", + "additions": 53, + "deletions": 43, + "changes": 96 + }, + { + "filename": "tests/analysis/test_kinematics_validity.py", + "status": "added", + "sha": "7cf66857bcbeb9b72851ad53ce7c08f97d528fc8", + "additions": 202, + "deletions": 0, + "changes": 202 + } + ], + "decision": "Retain the qualified actual 3e3 parent. This later merge changes only the kinematics compute implementation, its tests/design/evidence and shared progress. The accepted 24-check native journey exercised numeric features; no desktop/history/scope or numeric-feature source changed. These receipts do not claim complete d43 acceptance." +} diff --git a/docs/evidence/analysis-history-401c5d17da79/current-scope/native.stderr.log b/docs/evidence/analysis-history-401c5d17da79/current-scope/native.stderr.log new file mode 100644 index 00000000..90774a0e --- /dev/null +++ b/docs/evidence/analysis-history-401c5d17da79/current-scope/native.stderr.log @@ -0,0 +1,5 @@ +This plugin does not support propagateSizeHints() +This plugin does not support propagateSizeHints() +This plugin does not support propagateSizeHints() +This plugin does not support propagateSizeHints() +This plugin does not support propagateSizeHints() diff --git a/docs/evidence/analysis-history-401c5d17da79/current-scope/nonaccepting-continuation/check_scope_history.py b/docs/evidence/analysis-history-401c5d17da79/current-scope/nonaccepting-continuation/check_scope_history.py new file mode 100644 index 00000000..944472f0 --- /dev/null +++ b/docs/evidence/analysis-history-401c5d17da79/current-scope/nonaccepting-continuation/check_scope_history.py @@ -0,0 +1,251 @@ +# SPDX-License-Identifier: GPL-3.0-only +"""One real native scope/history journey on the received current source.""" +from pathlib import Path +import argparse +import hashlib +import importlib.util +import json +import os +import sys +import time +import traceback + + +def hashes(root, raw_only=False): + return {p.relative_to(root).as_posix(): hashlib.sha256(p.read_bytes()).hexdigest() + for p in sorted(root.rglob("*")) if p.is_file() + and (not raw_only or "processing" not in p.relative_to(root).parts)} + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--source", type=Path, required=True) + parser.add_argument("--inputs", type=Path, required=True) + parser.add_argument("--output", type=Path, required=True) + args = parser.parse_args() + source, output = args.source.resolve(), args.output.resolve() + assert source != output and source not in output.parents and not output.exists() + inputs = json.loads(args.inputs.read_bytes()) + expected = {row["path"]: row["sha256"] for row in inputs["files"]} + assert hashes(source) == expected + output.mkdir(parents=True) + for key, name in [("LOCALAPPDATA", "local"), ("APPDATA", "roaming"), + ("XDG_CONFIG_HOME", "config"), ("XDG_DATA_HOME", "data"), + ("XDG_CACHE_HOME", "cache"), ("MPLCONFIGDIR", "mpl"), + ("TMPDIR", "tmp"), ("XDG_RUNTIME_DIR", "runtime")]: + directory = output / "state" / name + directory.mkdir(parents=True, mode=0o700) + os.environ[key] = str(directory) + os.environ["QT_QPA_PLATFORM"] = "offscreen" + sys.dont_write_bytecode = True + for rel in reversed(["desktop", "libs/python/capture_analysis", "libs/python/capture_session", + "libs/python/capture_protocol", "libs/python/capture_protocol/capture_protocol/generated", + "libs/python/capture_worker"]): + sys.path.insert(0, str(source / rel)) + report = {"canonical_parent": inputs["canonical_parent"], "runtime_tree": inputs["composition_tree"], + "screen_git_blob": inputs["composed_screen_git_blob"], "checks": [], "errors": [], + "method": "QApplication.exec/QTimer; actual SessionHeader and AnalysisScreen, two real QThread/MCAP feature jobs", + "method_sha256": hashlib.sha256(Path(__file__).read_bytes()).hexdigest(), + "source_inputs_sha256": hashlib.sha256(args.inputs.read_bytes()).hexdigest(), + "scope": "One changed scope/history boundary. No Windows MainWindow, full-suite, nested-image repair or installed-release claim."} + + def check(name, condition, *, fatal=True): + report["checks"].append({"name": name, "passed": bool(condition)}) + if fatal: + assert condition, name + + try: + import PySide6 + from PySide6.QtCore import QCoreApplication, QEvent, QTimer, Qt + from PySide6.QtTest import QTest + from PySide6.QtWidgets import QApplication, QMessageBox, QPlainTextEdit, QVBoxLayout, QWidget + from capture_desktop import theme + from capture_desktop.screen_analysis import AnalysisScreen + from capture_desktop.state import CaptureState + from capture_desktop.widgets_session_header import SessionHeader + helper_path = source / "tests/analysis/test_numeric_batch_pipeline.py" + spec = importlib.util.spec_from_file_location("current_numeric_fixture", helper_path) + fixture = importlib.util.module_from_spec(spec) + spec.loader.exec_module(fixture) + + def package(name): + root = output / (name + ".mmsession") + root.mkdir() + (root / "manifest.json").write_text(json.dumps({"sessionId": name, "state": "sealed"}) + "\n") + stream = root / "sources/lsl/streams/numeric" + stream.mkdir(parents=True) + fixture._write_mcap(stream / "segments/000000.mcap", [(1_000_000_000, fixture._batch())]) + (stream / "stream.json").write_text(json.dumps({"sourceId": "lsl", "streamId": "numeric.stream", "modality": "eeg", "dataSchemaId": "generic.numeric_batch/1", "nominalRateHz": 2.0, "units": "V", "dimensions": [2]}) + "\n") + return root + + first, second = package("scope history A"), package("scope history B") + raw_before = {str(p): hashes(p, raw_only=True) for p in [first, second]} + app = QApplication([]) + theme.apply_theme(app, setting="dark") + shell = QWidget() + layout = QVBoxLayout(shell) + header, screen = SessionHeader(), AnalysisScreen(CaptureState()) + layout.addWidget(header) + layout.addWidget(screen, 1) + header.scope_changed.connect(screen.set_scope) + + def package_loaded(summary): + if summary is None: + header.clear() + else: + header.refresh_sealed(summary, selection=screen.scope) + + screen.package_loaded.connect(package_loaded) + shell.resize(1280, 1050) + shell.show() + picker = header._scope_picker + state = {"phase": "start", "deadline": time.monotonic() + 50, "dialogs": [], "cancelled": False} + ranges = [(1_500_000_001, 2_500_000_001), (1_000_000_001, 2_000_000_001)] + + def choose(bounds): + picker._mode.setCurrentIndex(picker._mode.findData("range")) + picker._start.setText(f"{bounds[0] // 10**9}.{bounds[0] % 10**9:09d}") + picker._end.setText(f"{bounds[1] // 10**9}.{bounds[1] % 10**9:09d}") + + def jobs(root): + directory = root / "processing/jobs" + return set(directory.iterdir()) if directory.exists() else set() + + def assert_job(job, bounds): + params = json.loads((job / "params.json").read_bytes()) + manifest = json.loads((job / "job_manifest.json").read_bytes()) + check("real saved job retains its exact selected nanosecond parameters", + (params["startSessionNs"], params["endSessionNs"]) == bounds and params["checkpointSection"] is None) + check("completed current numeric job reports that selected interval", + (manifest["timeRange"]["startSessionNs"], manifest["timeRange"]["endSessionNs"]) == bounds + and manifest["status"] in {"completed", "completed_with_warnings"}) + return params, manifest + + def finish(): + timer.stop() + shell.close() + app.quit() + + def tick(): + try: + modal = QApplication.activeModalWidget() + if isinstance(modal, QMessageBox): + state["dialogs"].append(modal.text()) + modal.accept() + if state["cancelled"]: + if screen._thread is None: + finish() + return + if time.monotonic() > state["deadline"]: + raise TimeoutError("The bounded native scope/history journey did not finish.") + phase = state["phase"] + if phase == "start": + screen.set_package(str(first) + "/.") + check("screen, header and history use one normalized package identity", + screen.package_path == header.package_path == screen._history.package == str(first)) + screen._command.setCurrentIndex(screen._command.findData("features")) + choose(ranges[0]) + check("real header selection enables the composed Analysis screen with exact bounds", + screen._btn_run.isEnabled() and screen.scope is picker.selection + and (screen.scope.start_ns, screen.scope.end_ns) == ranges[0]) + QTest.mouseClick(screen._btn_run, Qt.MouseButton.LeftButton) + check("real feature worker disables saved-history actions while running", + screen._thread is not None and not screen._history._open.isEnabled() + and not screen._history._refresh.isEnabled(), fatal=False) + report["initial_busy_state"] = {"thread_retained": screen._thread is not None, "thread_running": screen._thread.isRunning() if screen._thread is not None else False, "history_refresh_enabled": screen._history._refresh.isEnabled(), "history_open_enabled": screen._history._open.isEnabled()} + state["phase"] = "first-job" + elif phase == "first-job" and screen._thread is None: + check("the first real worker completes without a modal failure", not state["dialogs"]) + check("completed scoped job reaches the saved-history viewer", + len(jobs(first)) == 1 and bool(screen._last_job_dir) + and screen._history.loaded_job_id == Path(screen._last_job_dir).name) + job = Path(screen._last_job_dir) + assert_job(job, ranges[0]) + state["first_job"] = job + state["saved_bytes"] = hashes(job) + choose(ranges[1]) + selected = screen.scope + QTest.mouseClick(screen._history._refresh, Qt.MouseButton.LeftButton) + QTest.mouseClick(screen._history._open, Qt.MouseButton.LeftButton) + check("explicitly reopening the old job preserves the next selected scope", + screen.scope == picker.selection == selected + and (selected.start_ns, selected.end_ns) == ranges[1]) + check("reopen is read-only and starts no additional worker", + hashes(job) == state["saved_bytes"] and jobs(first) == {job} + and screen._thread is None) + QTest.mouseClick(screen._history._details, Qt.MouseButton.LeftButton) + dialog = screen._history._dialog + params_editor = dialog.findChild(QPlainTextEdit, "analysisHistoryParameters") + saved_params = json.loads(params_editor.toPlainText()) + check("native read-only details show the saved scope, distinct from the next selection", + params_editor.isReadOnly() + and (saved_params["startSessionNs"], saved_params["endSessionNs"]) == ranges[0] + and screen.scope == selected) + dialog.close() + screen.set_package(str(first) + "/.") + check("same-package refresh preserves both scope and loaded saved result", + screen.scope == picker.selection == selected + and screen._history.loaded_job_id == job.name) + state["phase"] = "capture-and-second-job" + elif phase == "capture-and-second-job": + check("combined native frame is captured", shell.grab().save(str(output / "scope-history-reopened.png"))) + state["jobs_before_second"] = jobs(first) + QTest.mouseClick(screen._btn_run, Qt.MouseButton.LeftButton) + check("a second real worker starts from the next selection", screen._thread is not None) + # The current application may change package context while a + # worker is pending. Its real queued completion must stay A. + screen.set_package(str(second)) + check("changing package resets scope and clears history as one transition", + screen.package_path == header.package_path == screen._history.package == str(second) + and screen.scope.mode == picker.selection.mode == "full" + and not screen._last_job_dir and not screen._history.loaded_job_id) + state["phase"] = "second-job" + elif phase == "second-job" and screen._thread is None: + completed = jobs(first) - state["jobs_before_second"] + check("late real completion is retained under its originating package only", + len(completed) == 1 and not jobs(second) and not state["dialogs"]) + second_job = next(iter(completed)) + assert_job(second_job, ranges[1]) + check("late foreign completion cannot repaint current history or scope", + screen.package_path == str(second) and screen.scope.mode == picker.selection.mode == "full" + and not screen._last_job_dir and not screen._history.loaded_job_id + and "Result saved for the previous package" in screen._log.toPlainText()) + check("the prior reopened job remains byte-identical after the second job", + hashes(state["first_job"]) == state["saved_bytes"]) + check("both real package raw inputs remain byte-identical", + all(hashes(p, raw_only=True) == raw_before[str(p)] for p in [first, second])) + report["real_jobs"] = [str(state["first_job"]), str(second_job)] + report["raw_package_hashes"] = raw_before + report["last_native_log"] = screen._log.toPlainText() + report["dialogs"] = state["dialogs"] + finish() + except BaseException: + report["errors"].append(traceback.format_exc()) + state["cancelled"] = True + if screen._thread is not None: + screen._cancel_job() + else: + finish() + + timer = QTimer() + timer.timeout.connect(tick) + timer.start(15) + report["event_loop_exit"] = app.exec() + shell.deleteLater() + QCoreApplication.sendPostedEvents(None, QEvent.Type.DeferredDelete) + app.processEvents() + report["pyside6"] = PySide6.__version__ + report["python"] = sys.version + except BaseException: + report["errors"].append(traceback.format_exc()) + report["source_unchanged"] = hashes(source) == expected + report["passed"] = sum(row["passed"] for row in report["checks"]) + report["failed"] = sum(not row["passed"] for row in report["checks"]) + report["exit_code"] = 0 if not report["errors"] and not report["failed"] and report["source_unchanged"] else 1 + (output / "receipt.json").write_text(json.dumps(report, indent=2) + "\n") + print(json.dumps({k: report[k] for k in ["passed", "failed", "source_unchanged", "exit_code"]})) + return report["exit_code"] + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/docs/evidence/analysis-history-401c5d17da79/current-scope/nonaccepting-continuation/receipt-state.json b/docs/evidence/analysis-history-401c5d17da79/current-scope/nonaccepting-continuation/receipt-state.json new file mode 100644 index 00000000..022d1eef --- /dev/null +++ b/docs/evidence/analysis-history-401c5d17da79/current-scope/nonaccepting-continuation/receipt-state.json @@ -0,0 +1,10 @@ +{ + "method_sha256": "1f7029cb84c999feed1b5b636d65551a75938f5875d09bbff20065aa9d1cc0b2", + "source_blob": "ee2db9acacdc92d3aa8ba0bfe12f638e9418f9b4", + "runtime_tree": "07d78241dca691015bb3e4d8d260b109672b7de0", + "classification": "Non-accepting artifact-capture continuation; no complete native outcome claimed", + "reason": "ENOSPC while writing frame/receipt and supervisor artifacts", + "receipt_bytes": 0, + "receipt_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "preservation": "Original private source, method, partial native fixture and zero-byte receipt were retained without deletion or truncation. The final qualified method emits a complete report and PNG through stdout." +} diff --git a/docs/evidence/analysis-history-401c5d17da79/current-scope/process.json b/docs/evidence/analysis-history-401c5d17da79/current-scope/process.json new file mode 100644 index 00000000..7ecceded --- /dev/null +++ b/docs/evidence/analysis-history-401c5d17da79/current-scope/process.json @@ -0,0 +1,19 @@ +{ + "command": [ + "/workspace/scratch/234cae4aee53/capturesuite-venv/bin/python", + "-B", + "/dev/shm/hamon-401c5d17da79-capture-history-pr/scope-current-seam/check_scope_history_qualified.py", + "--source", + "/dev/shm/hamon-401c5d17da79-capture-history-pr/scope-current-seam/receiving-source-candidate", + "--inputs", + "/dev/shm/hamon-401c5d17da79-capture-history-pr/scope-current-seam/candidate-source-inputs.json", + "--output", + "/dev/shm/hamon-401c5d17da79-capture-history-pr/scope-current-seam/native-scope-qualified" + ], + "exit_code": 0, + "seconds": 3.534, + "free_before": 11571200, + "free_after": 13574144, + "stdout_sha256": "aab4b265957f5404474d87c430bb03167b3514fb8fb05399e23cf5534f4b9c70", + "stderr_sha256": "bcd516d5e9014bd0f43bf526bc701b744bbd4ea9c35d16fdd65e6fde7b0270d5" +} diff --git a/docs/evidence/analysis-history-401c5d17da79/current-scope/receipt.json b/docs/evidence/analysis-history-401c5d17da79/current-scope/receipt.json new file mode 100644 index 00000000..a21d97a4 --- /dev/null +++ b/docs/evidence/analysis-history-401c5d17da79/current-scope/receipt.json @@ -0,0 +1,380 @@ +{ + "canonical_parent": "3e3ecc5ecc1cfc79c79901eb5cffe10b0ec5852e", + "runtime_tree": "167bbac3bba862cc1532d954fe2d503e561a00df", + "screen_git_blob": "6893f119593f8ff6551167efcb1939d014a081e6", + "checks": [ + { + "name": "screen, header and history use one normalized package identity", + "passed": true + }, + { + "name": "real header selection enables the composed Analysis screen with exact bounds", + "passed": true + }, + { + "name": "real feature worker disables saved-history actions while running", + "passed": true + }, + { + "name": "the first real worker completes without a modal failure", + "passed": true + }, + { + "name": "settled first job restores native Run and history controls", + "passed": true + }, + { + "name": "completed scoped job reaches the saved-history viewer", + "passed": true + }, + { + "name": "real saved job retains its exact selected nanosecond parameters", + "passed": true + }, + { + "name": "completed current numeric job reports that selected interval", + "passed": true + }, + { + "name": "successful saved job contains only the two expected fixture metadata warnings", + "passed": true + }, + { + "name": "explicitly reopening the old job preserves the next selected scope", + "passed": true + }, + { + "name": "reopen is read-only and starts no additional worker", + "passed": true + }, + { + "name": "native read-only details show the saved scope, distinct from the next selection", + "passed": true + }, + { + "name": "same-package refresh preserves both scope and loaded saved result", + "passed": true + }, + { + "name": "combined native frame is captured", + "passed": true + }, + { + "name": "a second real worker starts from the next selection", + "passed": true + }, + { + "name": "changing package resets scope and clears history as one transition", + "passed": true + }, + { + "name": "late real completion is retained under its originating package only", + "passed": true + }, + { + "name": "real saved job retains its exact selected nanosecond parameters", + "passed": true + }, + { + "name": "completed current numeric job reports that selected interval", + "passed": true + }, + { + "name": "successful saved job contains only the two expected fixture metadata warnings", + "passed": true + }, + { + "name": "late foreign completion cannot repaint current history or scope", + "passed": true + }, + { + "name": "late-job settlement restores controls for the current package only", + "passed": true + }, + { + "name": "the prior reopened job remains byte-identical after the second job", + "passed": true + }, + { + "name": "both real package raw inputs remain byte-identical", + "passed": true + } + ], + "errors": [], + "method": "QApplication.exec/QTimer; actual SessionHeader and AnalysisScreen, two real QThread/MCAP feature jobs", + "method_sha256": "c45eb2b2b02b8c9423565d811ae7782eff576b1313bf5cef366c4af8bf4e3802", + "source_inputs_sha256": "7e2d4d219c8a4b70865f780750fa8fe5362da54a43898097082a44784f807438", + "scope": "One changed scope/history boundary. No Windows MainWindow, full-suite, nested-image repair or installed-release claim.", + "initial_busy_state": { + "thread_retained": true, + "thread_running": true, + "history_refresh_enabled": false, + "history_open_enabled": false + }, + "saved_job_manifests": [ + { + "analysisGrids": [], + "captureAnalysisVersion": "0.1.0", + "createdUtc": "2026-10-08T14:16:48Z", + "errors": [], + "evalWindowCount": null, + "featureTables": [ + { + "featureSchemaVersion": 1, + "relativePath": "features/numeric/source-6c736c/stream-6e756d657269632e73747265616d/windows.parquet", + "rows": 1 + } + ], + "gapPolicy": "mask", + "gapSummary": { + "closed": 0, + "maskedNs": 0, + "open": 0, + "validFraction": null + }, + "jobId": "20261008T141648Z_3bcabb8c", + "kinematicsRows": null, + "manifestSha256": "53cfd49d90b9467e45769ff379fe20457e738e27dbff76ce64e4845d4e0a7028", + "mlBundleWindowCount": null, + "modalities": [ + "eeg" + ], + "outputs": [ + { + "bytes": 257, + "kind": "params", + "relativePath": "params.json", + "sha256": "6fbf697209770acc7d5e1690e95bd7869ba803a809c593f0e5b011508f6c5798" + }, + { + "bytes": 1141, + "kind": "qc_json", + "relativePath": "reports/qc.json", + "sha256": "fd46c1fdbb332dfb11d3b3362d51c25d57f8c2a79396d5bdfca537a6705dbd5b" + }, + { + "bytes": 2220, + "kind": "qc_html", + "relativePath": "reports/qc.html", + "sha256": "e7a1d98a2ce429128b11125b062c70f968f2bffd9198d326563457e5573de10d" + }, + { + "bytes": 5266, + "kind": "feature_parquet", + "relativePath": "features/numeric/source-6c736c/stream-6e756d657269632e73747265616d/windows.parquet", + "sha256": "03cfd112d75b61015ea9e109359f349857d5a9f7fbcd04718ab425ae8945da92" + }, + { + "bytes": 156, + "kind": "feature_csv", + "relativePath": "features/numeric/source-6c736c/stream-6e756d657269632e73747265616d/windows.csv", + "sha256": "b82f0241cf32d20ee1809d8a67e406b6074dd0fe1197316c900c1bf8cc236191" + }, + { + "bytes": 2691, + "kind": "feature_schema", + "relativePath": "features/_schema.json", + "sha256": "5d389cc9b624d1d818c6739554fcaf5d881ad4cffb0d31d74486fa644a969e85" + }, + { + "bytes": 3279, + "kind": "manifest", + "relativePath": "job_manifest.json", + "sha256": "305136787550fa5ef4df95ee41187dea93f414ad39d7eaa8c551f7a9666f73c4" + } + ], + "packagePath": "/dev/shm/hamon-401c5d17da79-capture-history-pr/scope-current-seam/native-scope-qualified/scope history A.mmsession", + "packageState": "sealed", + "paramsDigest": "3bcabb8cfbc12d0ec01c35b20c8d098b0559e7161440de5406af9e5cf4775f33", + "pluginIds": [ + "emg.envelope.v1", + "imu.kinematics.v1", + "radar.rd_energy.v1", + "radar_doppler.mag.v1", + "video.timing_qc.v1", + "numeric.basic.v1", + "test.dummy.feature.v1" + ], + "pluginManifestVersion": "1.0.0", + "poseJobId": null, + "poseModelId": null, + "poseTables": [], + "schemaId": "capture.analysis_job/1", + "sessionId": "scope history A", + "sourcesSelected": [ + "lsl" + ], + "status": "completed_with_warnings", + "syncAnchorsApplied": { + "anchors": [], + "applied": false + }, + "timeRange": { + "checkpointIds": [], + "endSessionNs": 2500000001, + "mode": "custom", + "startSessionNs": 1500000001 + }, + "tooling": { + "captureAnalysis": "0.1.0", + "matplotlib": "3.11.2", + "numpy": "2.5.3", + "pandas": "3.0.6", + "platform": "Linux-6.18.44-x86_64-with-glibc2.39", + "python": "3.12.14", + "scipy": "1.18.1" + }, + "warnings": [ + "package state is 'sealed' (prefer finalized)", + "package duration_ns is unknown/zero — analysis uses an open time window (integrity entries lack endSessionTimeNs)" + ] + }, + { + "analysisGrids": [], + "captureAnalysisVersion": "0.1.0", + "createdUtc": "2026-10-08T14:16:48Z", + "errors": [], + "evalWindowCount": null, + "featureTables": [ + { + "featureSchemaVersion": 1, + "relativePath": "features/numeric/source-6c736c/stream-6e756d657269632e73747265616d/windows.parquet", + "rows": 1 + } + ], + "gapPolicy": "mask", + "gapSummary": { + "closed": 0, + "maskedNs": 0, + "open": 0, + "validFraction": null + }, + "jobId": "20261008T141648Z_b793f3b4", + "kinematicsRows": null, + "manifestSha256": "53cfd49d90b9467e45769ff379fe20457e738e27dbff76ce64e4845d4e0a7028", + "mlBundleWindowCount": null, + "modalities": [ + "eeg" + ], + "outputs": [ + { + "bytes": 257, + "kind": "params", + "relativePath": "params.json", + "sha256": "efa12cb2a20649da7c1f3f823a265ee25b31540d28feeee0b47125b944e3d7e4" + }, + { + "bytes": 1141, + "kind": "qc_json", + "relativePath": "reports/qc.json", + "sha256": "fd46c1fdbb332dfb11d3b3362d51c25d57f8c2a79396d5bdfca537a6705dbd5b" + }, + { + "bytes": 2220, + "kind": "qc_html", + "relativePath": "reports/qc.html", + "sha256": "e7a1d98a2ce429128b11125b062c70f968f2bffd9198d326563457e5573de10d" + }, + { + "bytes": 5266, + "kind": "feature_parquet", + "relativePath": "features/numeric/source-6c736c/stream-6e756d657269632e73747265616d/windows.parquet", + "sha256": "858438d0c22ee6ecb5e304d22c7ad80579ecbe2178ebf5f8cd169494ae249b0d" + }, + { + "bytes": 156, + "kind": "feature_csv", + "relativePath": "features/numeric/source-6c736c/stream-6e756d657269632e73747265616d/windows.csv", + "sha256": "786ee658a04e19c111cc65914e64dbbff86c063dfe897b67e9a5290188af874e" + }, + { + "bytes": 2691, + "kind": "feature_schema", + "relativePath": "features/_schema.json", + "sha256": "5d389cc9b624d1d818c6739554fcaf5d881ad4cffb0d31d74486fa644a969e85" + }, + { + "bytes": 3279, + "kind": "manifest", + "relativePath": "job_manifest.json", + "sha256": "dd592f615b84e455c6dc18dd7385b05f45c5e9b195c0b33236062e3870f5e8af" + } + ], + "packagePath": "/dev/shm/hamon-401c5d17da79-capture-history-pr/scope-current-seam/native-scope-qualified/scope history A.mmsession", + "packageState": "sealed", + "paramsDigest": "b793f3b4690f50a5651d48f7479d01d0c846391249aecbf2afb7a44d96a05fc7", + "pluginIds": [ + "emg.envelope.v1", + "imu.kinematics.v1", + "radar.rd_energy.v1", + "radar_doppler.mag.v1", + "video.timing_qc.v1", + "numeric.basic.v1", + "test.dummy.feature.v1" + ], + "pluginManifestVersion": "1.0.0", + "poseJobId": null, + "poseModelId": null, + "poseTables": [], + "schemaId": "capture.analysis_job/1", + "sessionId": "scope history A", + "sourcesSelected": [ + "lsl" + ], + "status": "completed_with_warnings", + "syncAnchorsApplied": { + "anchors": [], + "applied": false + }, + "timeRange": { + "checkpointIds": [], + "endSessionNs": 2000000001, + "mode": "custom", + "startSessionNs": 1000000001 + }, + "tooling": { + "captureAnalysis": "0.1.0", + "matplotlib": "3.11.2", + "numpy": "2.5.3", + "pandas": "3.0.6", + "platform": "Linux-6.18.44-x86_64-with-glibc2.39", + "python": "3.12.14", + "scipy": "1.18.1" + }, + "warnings": [ + "package state is 'sealed' (prefer finalized)", + "package duration_ns is unknown/zero — analysis uses an open time window (integrity entries lack endSessionTimeNs)" + ] + } + ], + "native_frame": { + "filename": "scope-history-reopened.png", + "bytes": 193004, + "sha256": "c8ec0afb810a76da3254e035cdac3a5e0ec46097976743e1917e672441a550f5" + }, + "real_jobs": [ + "/dev/shm/hamon-401c5d17da79-capture-history-pr/scope-current-seam/native-scope-qualified/scope history A.mmsession/processing/jobs/20261008T141648Z_3bcabb8c", + "/dev/shm/hamon-401c5d17da79-capture-history-pr/scope-current-seam/native-scope-qualified/scope history A.mmsession/processing/jobs/20261008T141648Z_b793f3b4" + ], + "raw_package_hashes": { + "/dev/shm/hamon-401c5d17da79-capture-history-pr/scope-current-seam/native-scope-qualified/scope history A.mmsession": { + "manifest.json": "53cfd49d90b9467e45769ff379fe20457e738e27dbff76ce64e4845d4e0a7028", + "sources/lsl/streams/numeric/segments/000000.mcap": "f3df8e3cc95f76462c502935aad5abafd4392ed3224c239775650c5b49bcd18f", + "sources/lsl/streams/numeric/stream.json": "1adfb22cb81843c0e5bef319c9c2268ea2746e930232f6d89e154d133e0fa885" + }, + "/dev/shm/hamon-401c5d17da79-capture-history-pr/scope-current-seam/native-scope-qualified/scope history B.mmsession": { + "manifest.json": "bb31522d57c0572ddf144fdebb5037fa4dc51940cbe52034bbfd64911f9cdc3b", + "sources/lsl/streams/numeric/segments/000000.mcap": "f3df8e3cc95f76462c502935aad5abafd4392ed3224c239775650c5b49bcd18f", + "sources/lsl/streams/numeric/stream.json": "1adfb22cb81843c0e5bef319c9c2268ea2746e930232f6d89e154d133e0fa885" + } + }, + "last_native_log": "Starting features on /dev/shm/hamon-401c5d17da79-capture-history-pr/scope-current-seam/native-scope-qualified/scope history A.mmsession\nscope=1.000000001–2.000000001 s\nstart (0%)\nqc (15%)\nwrite_qc (25%)\nfeatures_plots (45%)\nmanifest (90%)\ndone (100%)\nDone status=completed_with_warnings job_id=20261008T141648Z_b793f3b4\ndir=/dev/shm/hamon-401c5d17da79-capture-history-pr/scope-current-seam/native-scope-qualified/scope history A.mmsession/processing/jobs/20261008T141648Z_b793f3b4\nResult saved for the previous package; select that package to inspect it.", + "dialogs": [], + "event_loop_exit": 0, + "pyside6": "6.11.2", + "python": "3.12.14 (main, Aug 25 2026, 14:00:49) [Clang 22.1.3 ]", + "source_unchanged": true, + "passed": 24, + "failed": 0, + "exit_code": 0 +} diff --git a/docs/evidence/analysis-history-401c5d17da79/current-scope/receiving.json b/docs/evidence/analysis-history-401c5d17da79/current-scope/receiving.json new file mode 100644 index 00000000..4af1b82d --- /dev/null +++ b/docs/evidence/analysis-history-401c5d17da79/current-scope/receiving.json @@ -0,0 +1,37 @@ +{ + "schema": "hamon.current-scope-history-receiving.v1", + "canonical_parent": "3e3ecc5ecc1cfc79c79901eb5cffe10b0ec5852e", + "runtime_tree": "167bbac3bba862cc1532d954fe2d503e561a00df", + "screen_git_blob": "6893f119593f8ff6551167efcb1939d014a081e6", + "screen_sha256": "1475764b8453ed870174fcaf98bc02370db76b5001c4175feb93263ad33d5b70", + "receiver_sha256": "c45eb2b2b02b8c9423565d811ae7782eff576b1313bf5cef366c4af8bf4e3802", + "process_exit_code": 0, + "seconds": 3.534, + "checks_passed": 24, + "checks_failed": 0, + "source_files": 142, + "source_bytes_unchanged": true, + "raw_package_bytes_unchanged": true, + "frame_sha256": "c8ec0afb810a76da3254e035cdac3a5e0ec46097976743e1917e672441a550f5", + "visual_review": "The current native scope picker and saved-history row are legible together. The very long private package path wraps and clips in the existing narrow left control column; this is not a complete layout or Windows MainWindow acceptance.", + "startup_control": { + "source_blob": "ee2db9acacdc92d3aa8ba0bfe12f638e9418f9b4", + "runtime_tree": "07d78241dca691015bb3e4d8d260b109672b7de0", + "method_sha256": "44c24508e4e4aa9d14d1771be486bb953f8b3719652183c2e9d7c3bb81ac2b17", + "passed_before_stop": 2, + "failed": 1, + "receipt": "startup-negative/receipt.json" + }, + "receiver_adjustments": [ + "Accept the existing completed_with_warnings status only with both exact expected fixture metadata warnings and exact saved range.", + "Explicitly verify Run/history controls restore after each completed worker.", + "Emit complete receipt and native PNG in stdout so artifact transport is independent of the native journey." + ], + "nonaccepting_continuation": { + "method_sha256": "1f7029cb84c999feed1b5b636d65551a75938f5875d09bbff20065aa9d1cc0b2", + "cause": "ENOSPC while writing frame/receipt and supervisor artifacts", + "receipt_bytes": 0, + "native_outcome": "not accepted; no complete result claimed" + }, + "qualification_limits": "Original 14 tests / 19 checks remain on 37443 and 72c15; QC/2 remains e43; current numeric nested-gallery limitation remains separate. No full Windows, MainWindow, daemon, hardware or installed-release acceptance." +} diff --git a/docs/evidence/analysis-history-401c5d17da79/current-scope/scope-history-reopened.png b/docs/evidence/analysis-history-401c5d17da79/current-scope/scope-history-reopened.png new file mode 100644 index 00000000..35b7f498 Binary files /dev/null and b/docs/evidence/analysis-history-401c5d17da79/current-scope/scope-history-reopened.png differ diff --git a/docs/evidence/analysis-history-401c5d17da79/current-scope/startup-negative/check_scope_history.py b/docs/evidence/analysis-history-401c5d17da79/current-scope/startup-negative/check_scope_history.py new file mode 100644 index 00000000..6847ebda --- /dev/null +++ b/docs/evidence/analysis-history-401c5d17da79/current-scope/startup-negative/check_scope_history.py @@ -0,0 +1,249 @@ +# SPDX-License-Identifier: GPL-3.0-only +"""One real native scope/history journey on the received current source.""" +from pathlib import Path +import argparse +import hashlib +import importlib.util +import json +import os +import sys +import time +import traceback + + +def hashes(root, raw_only=False): + return {p.relative_to(root).as_posix(): hashlib.sha256(p.read_bytes()).hexdigest() + for p in sorted(root.rglob("*")) if p.is_file() + and (not raw_only or "processing" not in p.relative_to(root).parts)} + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--source", type=Path, required=True) + parser.add_argument("--inputs", type=Path, required=True) + parser.add_argument("--output", type=Path, required=True) + args = parser.parse_args() + source, output = args.source.resolve(), args.output.resolve() + assert source != output and source not in output.parents and not output.exists() + inputs = json.loads(args.inputs.read_bytes()) + expected = {row["path"]: row["sha256"] for row in inputs["files"]} + assert hashes(source) == expected + output.mkdir(parents=True) + for key, name in [("LOCALAPPDATA", "local"), ("APPDATA", "roaming"), + ("XDG_CONFIG_HOME", "config"), ("XDG_DATA_HOME", "data"), + ("XDG_CACHE_HOME", "cache"), ("MPLCONFIGDIR", "mpl"), + ("TMPDIR", "tmp"), ("XDG_RUNTIME_DIR", "runtime")]: + directory = output / "state" / name + directory.mkdir(parents=True, mode=0o700) + os.environ[key] = str(directory) + os.environ["QT_QPA_PLATFORM"] = "offscreen" + sys.dont_write_bytecode = True + for rel in reversed(["desktop", "libs/python/capture_analysis", "libs/python/capture_session", + "libs/python/capture_protocol", "libs/python/capture_protocol/capture_protocol/generated", + "libs/python/capture_worker"]): + sys.path.insert(0, str(source / rel)) + report = {"canonical_parent": inputs["canonical_parent"], "runtime_tree": inputs["composition_tree"], + "screen_git_blob": inputs["composed_screen_git_blob"], "checks": [], "errors": [], + "method": "QApplication.exec/QTimer; actual SessionHeader and AnalysisScreen, two real QThread/MCAP feature jobs", + "method_sha256": hashlib.sha256(Path(__file__).read_bytes()).hexdigest(), + "source_inputs_sha256": hashlib.sha256(args.inputs.read_bytes()).hexdigest(), + "scope": "One changed scope/history boundary. No Windows MainWindow, full-suite, nested-image repair or installed-release claim."} + + def check(name, condition): + report["checks"].append({"name": name, "passed": bool(condition)}) + assert condition, name + + try: + import PySide6 + from PySide6.QtCore import QCoreApplication, QEvent, QTimer, Qt + from PySide6.QtTest import QTest + from PySide6.QtWidgets import QApplication, QMessageBox, QPlainTextEdit, QVBoxLayout, QWidget + from capture_desktop import theme + from capture_desktop.screen_analysis import AnalysisScreen + from capture_desktop.state import CaptureState + from capture_desktop.widgets_session_header import SessionHeader + helper_path = source / "tests/analysis/test_numeric_batch_pipeline.py" + spec = importlib.util.spec_from_file_location("current_numeric_fixture", helper_path) + fixture = importlib.util.module_from_spec(spec) + spec.loader.exec_module(fixture) + + def package(name): + root = output / (name + ".mmsession") + root.mkdir() + (root / "manifest.json").write_text(json.dumps({"sessionId": name, "state": "sealed"}) + "\n") + stream = root / "sources/lsl/streams/numeric" + stream.mkdir(parents=True) + fixture._write_mcap(stream / "segments/000000.mcap", [(1_000_000_000, fixture._batch())]) + (stream / "stream.json").write_text(json.dumps({"sourceId": "lsl", "streamId": "numeric.stream", "modality": "eeg", "dataSchemaId": "generic.numeric_batch/1", "nominalRateHz": 2.0, "units": "V", "dimensions": [2]}) + "\n") + return root + + first, second = package("scope history A"), package("scope history B") + raw_before = {str(p): hashes(p, raw_only=True) for p in [first, second]} + app = QApplication([]) + theme.apply_theme(app, setting="dark") + shell = QWidget() + layout = QVBoxLayout(shell) + header, screen = SessionHeader(), AnalysisScreen(CaptureState()) + layout.addWidget(header) + layout.addWidget(screen, 1) + header.scope_changed.connect(screen.set_scope) + + def package_loaded(summary): + if summary is None: + header.clear() + else: + header.refresh_sealed(summary, selection=screen.scope) + + screen.package_loaded.connect(package_loaded) + shell.resize(1280, 1050) + shell.show() + picker = header._scope_picker + state = {"phase": "start", "deadline": time.monotonic() + 50, "dialogs": [], "cancelled": False} + ranges = [(1_500_000_001, 2_500_000_001), (1_000_000_001, 2_000_000_001)] + + def choose(bounds): + picker._mode.setCurrentIndex(picker._mode.findData("range")) + picker._start.setText(f"{bounds[0] // 10**9}.{bounds[0] % 10**9:09d}") + picker._end.setText(f"{bounds[1] // 10**9}.{bounds[1] % 10**9:09d}") + + def jobs(root): + directory = root / "processing/jobs" + return set(directory.iterdir()) if directory.exists() else set() + + def assert_job(job, bounds): + params = json.loads((job / "params.json").read_bytes()) + manifest = json.loads((job / "job_manifest.json").read_bytes()) + check("real saved job retains its exact selected nanosecond parameters", + (params["startSessionNs"], params["endSessionNs"]) == bounds and params["checkpointSection"] is None) + check("completed current numeric job reports that selected interval", + (manifest["timeRange"]["startSessionNs"], manifest["timeRange"]["endSessionNs"]) == bounds + and manifest["status"] == "completed") + return params, manifest + + def finish(): + timer.stop() + shell.close() + app.quit() + + def tick(): + try: + modal = QApplication.activeModalWidget() + if isinstance(modal, QMessageBox): + state["dialogs"].append(modal.text()) + modal.accept() + if state["cancelled"]: + if screen._thread is None: + finish() + return + if time.monotonic() > state["deadline"]: + raise TimeoutError("The bounded native scope/history journey did not finish.") + phase = state["phase"] + if phase == "start": + screen.set_package(str(first) + "/.") + check("screen, header and history use one normalized package identity", + screen.package_path == header.package_path == screen._history.package == str(first)) + screen._command.setCurrentIndex(screen._command.findData("features")) + choose(ranges[0]) + check("real header selection enables the composed Analysis screen with exact bounds", + screen._btn_run.isEnabled() and screen.scope is picker.selection + and (screen.scope.start_ns, screen.scope.end_ns) == ranges[0]) + QTest.mouseClick(screen._btn_run, Qt.MouseButton.LeftButton) + check("real feature worker disables saved-history actions while running", + screen._thread is not None and not screen._history._open.isEnabled() + and not screen._history._refresh.isEnabled()) + state["phase"] = "first-job" + elif phase == "first-job" and screen._thread is None: + check("the first real worker completes without a modal failure", not state["dialogs"]) + check("completed scoped job reaches the saved-history viewer", + len(jobs(first)) == 1 and bool(screen._last_job_dir) + and screen._history.loaded_job_id == Path(screen._last_job_dir).name) + job = Path(screen._last_job_dir) + assert_job(job, ranges[0]) + state["first_job"] = job + state["saved_bytes"] = hashes(job) + choose(ranges[1]) + selected = screen.scope + QTest.mouseClick(screen._history._refresh, Qt.MouseButton.LeftButton) + QTest.mouseClick(screen._history._open, Qt.MouseButton.LeftButton) + check("explicitly reopening the old job preserves the next selected scope", + screen.scope == picker.selection == selected + and (selected.start_ns, selected.end_ns) == ranges[1]) + check("reopen is read-only and starts no additional worker", + hashes(job) == state["saved_bytes"] and jobs(first) == {job} + and screen._thread is None) + QTest.mouseClick(screen._history._details, Qt.MouseButton.LeftButton) + dialog = screen._history._dialog + params_editor = dialog.findChild(QPlainTextEdit, "analysisHistoryParameters") + saved_params = json.loads(params_editor.toPlainText()) + check("native read-only details show the saved scope, distinct from the next selection", + params_editor.isReadOnly() + and (saved_params["startSessionNs"], saved_params["endSessionNs"]) == ranges[0] + and screen.scope == selected) + dialog.close() + screen.set_package(str(first) + "/.") + check("same-package refresh preserves both scope and loaded saved result", + screen.scope == picker.selection == selected + and screen._history.loaded_job_id == job.name) + state["phase"] = "capture-and-second-job" + elif phase == "capture-and-second-job": + check("combined native frame is captured", shell.grab().save(str(output / "scope-history-reopened.png"))) + state["jobs_before_second"] = jobs(first) + QTest.mouseClick(screen._btn_run, Qt.MouseButton.LeftButton) + check("a second real worker starts from the next selection", screen._thread is not None) + # The current application may change package context while a + # worker is pending. Its real queued completion must stay A. + screen.set_package(str(second)) + check("changing package resets scope and clears history as one transition", + screen.package_path == header.package_path == screen._history.package == str(second) + and screen.scope.mode == picker.selection.mode == "full" + and not screen._last_job_dir and not screen._history.loaded_job_id) + state["phase"] = "second-job" + elif phase == "second-job" and screen._thread is None: + completed = jobs(first) - state["jobs_before_second"] + check("late real completion is retained under its originating package only", + len(completed) == 1 and not jobs(second) and not state["dialogs"]) + second_job = next(iter(completed)) + assert_job(second_job, ranges[1]) + check("late foreign completion cannot repaint current history or scope", + screen.package_path == str(second) and screen.scope.mode == picker.selection.mode == "full" + and not screen._last_job_dir and not screen._history.loaded_job_id + and "Result saved for the previous package" in screen._log.toPlainText()) + check("the prior reopened job remains byte-identical after the second job", + hashes(state["first_job"]) == state["saved_bytes"]) + check("both real package raw inputs remain byte-identical", + all(hashes(p, raw_only=True) == raw_before[str(p)] for p in [first, second])) + report["real_jobs"] = [str(state["first_job"]), str(second_job)] + report["raw_package_hashes"] = raw_before + report["last_native_log"] = screen._log.toPlainText() + report["dialogs"] = state["dialogs"] + finish() + except BaseException: + report["errors"].append(traceback.format_exc()) + state["cancelled"] = True + if screen._thread is not None: + screen._cancel_job() + else: + finish() + + timer = QTimer() + timer.timeout.connect(tick) + timer.start(15) + report["event_loop_exit"] = app.exec() + shell.deleteLater() + QCoreApplication.sendPostedEvents(None, QEvent.Type.DeferredDelete) + app.processEvents() + report["pyside6"] = PySide6.__version__ + report["python"] = sys.version + except BaseException: + report["errors"].append(traceback.format_exc()) + report["source_unchanged"] = hashes(source) == expected + report["passed"] = sum(row["passed"] for row in report["checks"]) + report["failed"] = sum(not row["passed"] for row in report["checks"]) + report["exit_code"] = 0 if not report["errors"] and not report["failed"] and report["source_unchanged"] else 1 + (output / "receipt.json").write_text(json.dumps(report, indent=2) + "\n") + print(json.dumps({k: report[k] for k in ["passed", "failed", "source_unchanged", "exit_code"]})) + return report["exit_code"] + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/docs/evidence/analysis-history-401c5d17da79/current-scope/startup-negative/native.stderr.log b/docs/evidence/analysis-history-401c5d17da79/current-scope/startup-negative/native.stderr.log new file mode 100644 index 00000000..a61736e6 --- /dev/null +++ b/docs/evidence/analysis-history-401c5d17da79/current-scope/startup-negative/native.stderr.log @@ -0,0 +1,3 @@ +This plugin does not support propagateSizeHints() +This plugin does not support propagateSizeHints() +This plugin does not support propagateSizeHints() diff --git a/docs/evidence/analysis-history-401c5d17da79/current-scope/startup-negative/native.stdout.log b/docs/evidence/analysis-history-401c5d17da79/current-scope/startup-negative/native.stdout.log new file mode 100644 index 00000000..85569fcb --- /dev/null +++ b/docs/evidence/analysis-history-401c5d17da79/current-scope/startup-negative/native.stdout.log @@ -0,0 +1 @@ +{"passed": 2, "failed": 1, "source_unchanged": true, "exit_code": 1} diff --git a/docs/evidence/analysis-history-401c5d17da79/current-scope/startup-negative/process.json b/docs/evidence/analysis-history-401c5d17da79/current-scope/startup-negative/process.json new file mode 100644 index 00000000..8713ebe9 --- /dev/null +++ b/docs/evidence/analysis-history-401c5d17da79/current-scope/startup-negative/process.json @@ -0,0 +1,18 @@ +{ + "command": [ + "/workspace/scratch/234cae4aee53/capturesuite-venv/bin/python", + "-B", + "/dev/shm/hamon-401c5d17da79-capture-history-pr/scope-current-seam/check_scope_history.py", + "--source", + "/dev/shm/hamon-401c5d17da79-capture-history-pr/scope-current-seam/receiving-source-verified", + "--inputs", + "/dev/shm/hamon-401c5d17da79-capture-history-pr/scope-current-seam/source-inputs.json", + "--output", + "/dev/shm/hamon-401c5d17da79-capture-history-pr/scope-current-seam/native-scope-run" + ], + "exit_code": 1, + "seconds": 3.46, + "stdout_sha256": "ca6c5fb808170de343775ef9272647c204a8662d37fa236ee83d8b9c59d03a70", + "stderr_sha256": "f1aa9b66f160e1438e3c1b8beee83bb34d3af8ade06f075e0a751d8d46ebb208", + "method_sha256": "44c24508e4e4aa9d14d1771be486bb953f8b3719652183c2e9d7c3bb81ac2b17" +} diff --git a/docs/evidence/analysis-history-401c5d17da79/current-scope/startup-negative/receipt.json b/docs/evidence/analysis-history-401c5d17da79/current-scope/startup-negative/receipt.json new file mode 100644 index 00000000..a24fabcd --- /dev/null +++ b/docs/evidence/analysis-history-401c5d17da79/current-scope/startup-negative/receipt.json @@ -0,0 +1,33 @@ +{ + "canonical_parent": "3e3ecc5ecc1cfc79c79901eb5cffe10b0ec5852e", + "runtime_tree": "07d78241dca691015bb3e4d8d260b109672b7de0", + "screen_git_blob": "ee2db9acacdc92d3aa8ba0bfe12f638e9418f9b4", + "checks": [ + { + "name": "screen, header and history use one normalized package identity", + "passed": true + }, + { + "name": "real header selection enables the composed Analysis screen with exact bounds", + "passed": true + }, + { + "name": "real feature worker disables saved-history actions while running", + "passed": false + } + ], + "errors": [ + "Traceback (most recent call last):\n File \"/dev/shm/hamon-401c5d17da79-capture-history-pr/scope-current-seam/check_scope_history.py\", line 151, in tick\n check(\"real feature worker disables saved-history actions while running\",\n File \"/dev/shm/hamon-401c5d17da79-capture-history-pr/scope-current-seam/check_scope_history.py\", line 54, in check\n assert condition, name\n ^^^^^^^^^\nAssertionError: real feature worker disables saved-history actions while running\n" + ], + "method": "QApplication.exec/QTimer; actual SessionHeader and AnalysisScreen, two real QThread/MCAP feature jobs", + "method_sha256": "44c24508e4e4aa9d14d1771be486bb953f8b3719652183c2e9d7c3bb81ac2b17", + "source_inputs_sha256": "3d76e4d458693e38756479d37fe325301e5ed9eda01ee4945e913f93e6206557", + "scope": "One changed scope/history boundary. No Windows MainWindow, full-suite, nested-image repair or installed-release claim.", + "event_loop_exit": 0, + "pyside6": "6.11.2", + "python": "3.12.14 (main, Aug 25 2026, 14:00:49) [Clang 22.1.3 ]", + "source_unchanged": true, + "passed": 2, + "failed": 1, + "exit_code": 1 +} diff --git a/docs/evidence/analysis-history-401c5d17da79/current-scope/startup-negative/screen_analysis.py.txt b/docs/evidence/analysis-history-401c5d17da79/current-scope/startup-negative/screen_analysis.py.txt new file mode 100644 index 00000000..ee2db9ac --- /dev/null +++ b/docs/evidence/analysis-history-401c5d17da79/current-scope/startup-negative/screen_analysis.py.txt @@ -0,0 +1,517 @@ +# SPDX-License-Identifier: GPL-3.0-only +"""Offline Analysis workbench — jobs in QThread; figures in-app via PyQtGraph.""" + +from __future__ import annotations + +import os +import threading +from pathlib import Path +from typing import Any + +from PySide6.QtCore import QObject, QThread, Signal, Slot +from PySide6.QtWidgets import ( + QComboBox, + QFileDialog, + QHBoxLayout, + QLabel, + QMessageBox, + QProgressBar, + QPushButton, + QSplitter, + QTextEdit, + QVBoxLayout, + QWidget, +) + +from . import theme +from .analysis_history import SavedJobDetails, job_belongs_to_package, load_saved_job +from .persistence import DesktopPersistence +from .state import CaptureState, fmt_time +from .widgets_analysis_history import AnalysisHistory +from .widgets_analysis_jobs import AnalysisJobExtras, peek_ml_bundle_summary +from .widgets_analysis_plots import FigureGallery, JobInspector +from .widgets_analysis_scope import WINDOW_COMMANDS, ScopeSelection +from .widgets_mappings import AnatomicalMappingPanel + + +class _AnalysisWorker(QObject): + progress = Signal(str, float) + finished = Signal(object) # JobResult + failed = Signal(str) + + def __init__( + self, + package: str, + command: str, + gap_policy: str, + extra: dict[str, Any] | None = None, + *, + scope: ScopeSelection | None = None, + ) -> None: + super().__init__() + self._package = package + self._command = command + self._gap_policy = gap_policy + self._extra = dict(extra or {}) + self._scope = scope or ScopeSelection() + self._cancel = threading.Event() + + def request_cancel(self) -> None: + self._cancel.set() + + @Slot() + def run(self) -> None: + try: + from capture_analysis import JobParams, run + + if self._scope.mode != "full" and self._command not in WINDOW_COMMANDS: + raise ValueError("This command requires Full session scope.") + + def on_progress(stage: str, frac: float) -> None: + self.progress.emit(stage, float(frac)) + + result = run( + self._package, + JobParams( + command=self._command, + gap_policy=self._gap_policy, + extra=self._extra, + **self._scope.job_fields(), + ), + progress=on_progress, + cancel=self._cancel, + ) + self.finished.emit(result) + except InterruptedError as exc: + self.failed.emit("\n".join(["cancelled", *getattr(exc, "__notes__", ())])) + except Exception as exc: # noqa: BLE001 + self.failed.emit("\n".join([str(exc), *getattr(exc, "__notes__", ())])) + + +class AnalysisScreen(QWidget): + """Analysis workbench — never talks to the daemon.""" + + package_loaded = Signal(object) # ReviewSummary, or None after a failed open + + def __init__( + self, + state: CaptureState, + persistence: DesktopPersistence | None = None, + parent: QWidget | None = None, + ) -> None: + super().__init__(parent) + self._state = state + self._persistence = persistence + self._package = "" + self._summary = None + self._scope: ScopeSelection | None = ScopeSelection() + self._last_job_dir = "" + self._thread: QThread | None = None + self._worker: _AnalysisWorker | None = None + + root = QVBoxLayout(self) + root.setContentsMargins(12, 10, 12, 10) + root.setSpacing(8) + + title = QLabel("Analysis") + title.setFont(theme.ui(14, bold=True)) + root.addWidget(title) + + self._banner = QLabel( + "Offline jobs write under processing/jobs/. Raw streams are never modified." + ) + self._banner.setObjectName("Dim") + self._banner.setWordWrap(True) + root.addWidget(self._banner) + self._scope_note = QLabel("Scope: full session") + self._scope_note.setWordWrap(True) + self._scope_note.setObjectName("Dim") + root.addWidget(self._scope_note) + + self._history = AnalysisHistory() + self._history.job_loaded.connect(self._show_saved_job) + self._history.view_cleared.connect(self._clear_result_view) + root.addWidget(self._history) + + splitter = QSplitter() + splitter.setChildrenCollapsible(False) + root.addWidget(splitter, 1) + + left = QWidget() + left.setMinimumWidth(300) + left_layout = QVBoxLayout(left) + left_layout.setContentsMargins(0, 0, 8, 0) + left_layout.setSpacing(8) + self._build_controls(left_layout) + self._mappings = AnatomicalMappingPanel(persistence) + left_layout.addWidget(self._mappings) + splitter.addWidget(left) + + self._gallery = FigureGallery() + splitter.addWidget(self._gallery) + + self._inspector = JobInspector() + self._inspector.setMinimumWidth(240) + splitter.addWidget(self._inspector) + splitter.setStretchFactor(0, 0) + splitter.setStretchFactor(1, 3) + splitter.setStretchFactor(2, 1) + + def _build_controls(self, root: QVBoxLayout) -> None: + path_row = QHBoxLayout() + self._path = QLabel("No package selected") + self._path.setObjectName("Dim") + self._path.setWordWrap(True) + self._btn_browse = QPushButton("Browse…") + self._btn_browse.clicked.connect(self._browse) + self._btn_use_open = QPushButton("Use open session") + self._btn_use_open.clicked.connect(self._use_open_session) + path_row.addWidget(self._path, 1) + path_row.addWidget(self._btn_use_open) + path_row.addWidget(self._btn_browse) + root.addLayout(path_row) + + cards = QHBoxLayout() + self._card_session = QLabel("—") + self._card_sources = QLabel("—") + self._card_gaps = QLabel("—") + self._card_duration = QLabel("—") + for label, widget in ( + ("Session", self._card_session), + ("Sources", self._card_sources), + ("Gaps", self._card_gaps), + ("Duration", self._card_duration), + ): + box = QWidget() + box.setObjectName("Card") + col = QVBoxLayout(box) + col.setContentsMargins(8, 6, 8, 6) + head = QLabel(label) + head.setObjectName("Faint") + head.setFont(theme.ui(8)) + widget.setFont(theme.ui(10, bold=True)) + widget.setWordWrap(True) + col.addWidget(head) + col.addWidget(widget) + cards.addWidget(box, 1) + root.addLayout(cards) + + opts = QVBoxLayout() + cmd_row = QHBoxLayout() + cmd_row.addWidget(QLabel("Command")) + self._command = QComboBox() + for label, value in ( + ("QC only", "qc"), + ("Features + plots", "all"), + ("Features only", "features"), + ("Plots only", "plots"), + ("Pose (body teacher)", "pose"), + ("Kinematics (Tier A)", "kinematics"), + ("ML bundle", "ml_bundle"), + ("Eval report", "eval"), + ): + self._command.addItem(label, value) + self._command.currentIndexChanged.connect(self._on_command_changed) + cmd_row.addWidget(self._command, 1) + opts.addLayout(cmd_row) + gap_row = QHBoxLayout() + gap_row.addWidget(QLabel("Gap policy")) + self._gap_policy = QComboBox() + for policy in ("mask", "split", "fail"): + self._gap_policy.addItem(policy, policy) + gap_row.addWidget(self._gap_policy, 1) + opts.addLayout(gap_row) + root.addLayout(opts) + + self._extras = AnalysisJobExtras() + self._extras.set_command("qc") + root.addWidget(self._extras) + + actions = QHBoxLayout() + self._btn_run = QPushButton("Run") + self._btn_run.setObjectName("Primary") + self._btn_run.clicked.connect(self._start_job) + self._btn_cancel = QPushButton("Cancel") + self._btn_cancel.setEnabled(False) + self._btn_cancel.clicked.connect(self._cancel_job) + actions.addWidget(self._btn_run) + actions.addWidget(self._btn_cancel) + root.addLayout(actions) + + aux = QHBoxLayout() + self._btn_open_job = QPushButton("Open job folder") + self._btn_open_job.setEnabled(False) + self._btn_open_job.clicked.connect(self._open_job_folder) + self._btn_open_report = QPushButton("Open QC report (HTML)") + self._btn_open_report.setEnabled(False) + self._btn_open_report.clicked.connect(self._open_report) + aux.addWidget(self._btn_open_job) + aux.addWidget(self._btn_open_report) + root.addLayout(aux) + + self._progress = QProgressBar() + self._progress.setRange(0, 100) + self._progress.setValue(0) + root.addWidget(self._progress) + + self._log = QTextEdit() + self._log.setReadOnly(True) + self._log.setFont(theme.mono(9)) + self._log.setPlaceholderText("Job log…") + self._log.setMaximumHeight(160) + root.addWidget(self._log) + root.addStretch(1) + + def _on_command_changed(self) -> None: + command = str(self._command.currentData() or "qc") + self._extras.set_command(command) + self._extras.refresh() + self._sync_enabled() + + @property + def package_path(self) -> str: + return self._package + + @property + def summary(self): + return self._summary + + @property + def scope(self) -> ScopeSelection | None: + return self._scope + + def set_scope(self, package_path: str, selection: ScopeSelection | None) -> None: + if str(Path(package_path).resolve()) != self._package: + return + self._scope = selection + self._sync_enabled() + + def _scope_error(self) -> str | None: + if self._scope is None: + return "Correct the scope bounds in the session header before running analysis." + try: + self._scope.job_fields() + except ValueError as exc: + return str(exc) + if self._scope.mode != "full" and self._command.currentData() not in WINDOW_COMMANDS: + return ( + "This command uses the full session or its input jobs. " + "Select Full session to run." + ) + return None + + def set_package(self, package_path: str) -> None: + if not package_path: + return + resolved = str(Path(package_path).resolve()) + if resolved != self._package: + self._scope = ScopeSelection() + self._package = resolved + self._path.setText(resolved) + self._history.set_package(resolved) + self._extras.set_package(resolved) + self._refresh_summary() + self._sync_enabled() + self.package_loaded.emit(self._summary) + + def refresh_from_state(self) -> None: + if self._state.package_path and not self._package: + self.set_package(self._state.package_path) + self._sync_enabled() + + def _recording_locked(self) -> bool: + from capture_protocol.generated.capture.v1 import control_pb2 + + return self._state.session_state in ( + control_pb2.SESSION_STATE_RECORDING, + control_pb2.SESSION_STATE_ARMING, + ) + + def _sync_enabled(self) -> None: + busy = self._thread is not None and self._thread.isRunning() + locked = self._recording_locked() + has_pkg = self._summary is not None + scope_error = self._scope_error() + self._btn_run.setEnabled(has_pkg and not busy and not locked and scope_error is None) + self._scope_note.setText( + scope_error or f"Scope: {self._scope.describe()}. QC reports cover the full package." + ) + self._btn_cancel.setEnabled(busy) + self._btn_browse.setEnabled(not busy) + self._btn_use_open.setEnabled(not busy and bool(self._state.package_path)) + self._command.setEnabled(not busy) + self._gap_policy.setEnabled(not busy) + self._history.set_busy(busy) + if locked: + self._banner.setText( + "Analysis is disabled while the session is arming or recording." + ) + + def _refresh_summary(self) -> None: + try: + from capture_session import load_review_summary + + summary = load_review_summary(self._package) + except Exception as exc: # noqa: BLE001 + self._summary = None + for card in ( + self._card_session, self._card_sources, self._card_gaps, self._card_duration, + ): + card.setText("—") + self._banner.setText(f"Could not load package: {exc}") + return + self._summary = summary + self._banner.setText( + f"State {summary.state}. Jobs write only under processing/jobs/." + ) + self._card_session.setText(summary.session_id or "—") + self._card_sources.setText(str(len(summary.source_ids))) + self._card_gaps.setText( + f"{len(summary.gaps)} · {summary.open_gap_count} open" + ) + dur = summary.duration_ns / 1e9 if summary.duration_ns > 1 else 0.0 + self._card_duration.setText(fmt_time(dur) if dur else "unknown") + + def _browse(self) -> None: + start = self._package or str( + Path(os.environ.get("LOCALAPPDATA", "")) / "CaptureSuite" / "sessions" + ) + path = QFileDialog.getExistingDirectory(self, "Select .mmsession package", start) + if path: + self.set_package(path) + + def _use_open_session(self) -> None: + if self._state.package_path: + self.set_package(self._state.package_path) + + def _append_log(self, line: str) -> None: + self._log.append(line) + + def _start_job(self) -> None: + if self._summary is None or (self._thread and self._thread.isRunning()): + return + if self._recording_locked(): + QMessageBox.warning( + self, + "Analysis", + "Stop recording before running offline analysis.", + ) + return + scope_error = self._scope_error() + if scope_error: + QMessageBox.warning(self, "Analysis scope", scope_error) + return + command = str(self._command.currentData()) + gap_policy = str(self._gap_policy.currentData()) + err = self._extras.validate_for(command) + if err: + QMessageBox.warning(self, "Analysis", err) + return + extra = self._extras.build_extra(command) + self._log.clear() + self._clear_result_view() + self._append_log(f"Starting {command} on {self._package}") + self._append_log(f"scope={self._scope.describe()}") + if extra: + self._append_log(f"extra={extra}") + self._progress.setValue(0) + + thread = QThread(self) + worker = _AnalysisWorker(self._package, command, gap_policy, extra, scope=self._scope) + worker.moveToThread(thread) + thread.started.connect(worker.run) + worker.progress.connect(self._on_progress) + worker.finished.connect(self._on_finished) + worker.failed.connect(self._on_failed) + worker.finished.connect(thread.quit) + worker.failed.connect(thread.quit) + thread.finished.connect(worker.deleteLater) + thread.finished.connect(thread.deleteLater) + thread.finished.connect(self._on_thread_finished) + self._thread = thread + self._worker = worker + self._sync_enabled() + thread.start() + + def _cancel_job(self) -> None: + if self._worker is not None: + self._append_log("Cancel requested…") + self._worker.request_cancel() + + @Slot(str, float) + def _on_progress(self, stage: str, frac: float) -> None: + self._progress.setValue(int(max(0.0, min(1.0, frac)) * 100)) + self._append_log(f"{stage} ({frac:.0%})") + + @Slot(object) + def _on_finished(self, result: object) -> None: + job_dir = str(getattr(result, "job_dir", "") or "") + status = str(getattr(result, "status", "") or "") + job_id = str(getattr(result, "job_id", "") or "") + self._append_log(f"Done status={status} job_id={job_id}") + self._append_log(f"dir={job_dir}") + if not job_belongs_to_package(self._package, job_dir): + self._append_log( + "Result saved for the previous package; select that package to inspect it." + ) + return + self._progress.setValue(100) + self._history.refresh(preferred_job_id=job_id) + try: + details = load_saved_job(self._package, Path(job_dir).name) + except (OSError, ValueError, UnicodeError) as exc: + self._append_log(f"Result saved, but the viewer could not load it: {exc}") + return + self._show_saved_job(details) + + def _clear_result_view(self) -> None: + self._last_job_dir = "" + self._btn_open_job.setEnabled(False) + self._btn_open_report.setEnabled(False) + self._gallery.clear() + self._inspector.clear() + self._history.clear_loaded() + + @Slot(object) + def _show_saved_job(self, details: SavedJobDetails) -> None: + if not job_belongs_to_package(self._package, details.job.directory): + return + job_dir = str(details.job.directory) + self._last_job_dir = job_dir + self._history.show_loaded(details) + self._btn_open_job.setEnabled(bool(job_dir)) + report = Path(job_dir) / "reports" / "qc.html" if job_dir else Path() + self._btn_open_report.setEnabled(report.is_file()) + if job_dir: + path = Path(job_dir) + self._gallery.load_job_dir(path) + self._inspector.load_job_dir(path) + self._append_log("Figures loaded in-app (sync dashboard + gallery tabs).") + ml_summary = peek_ml_bundle_summary(path) + if ml_summary: + self._append_log(ml_summary) + eval_path = path / "eval" / "eval_report.json" + if eval_path.is_file(): + self._append_log(f"Eval report: {eval_path.name}") + self._extras.refresh() + + @Slot(str) + def _on_failed(self, message: str) -> None: + self._append_log(f"FAIL: {message}") + self._history.refresh() + if message.split("\n", 1)[0] != "cancelled": + QMessageBox.warning(self, "Analysis failed", message) + + def _on_thread_finished(self) -> None: + self._thread = None + self._worker = None + self._sync_enabled() + + def _open_job_folder(self) -> None: + if self._last_job_dir and Path(self._last_job_dir).is_dir(): + os.startfile(self._last_job_dir) # noqa: S606 — explorer only + + def _open_report(self) -> None: + path = Path(self._last_job_dir) / "reports" / "qc.html" + if path.is_file(): + os.startfile(str(path)) # noqa: S606 — HTML QC external per workbench spec diff --git a/docs/evidence/analysis-history-401c5d17da79/current-scope/startup-negative/source-inputs.json b/docs/evidence/analysis-history-401c5d17da79/current-scope/startup-negative/source-inputs.json new file mode 100644 index 00000000..1abccfd7 --- /dev/null +++ b/docs/evidence/analysis-history-401c5d17da79/current-scope/startup-negative/source-inputs.json @@ -0,0 +1,863 @@ +{ + "repository": "Jacob-Met/CaptureSuite", + "canonical_parent": "3e3ecc5ecc1cfc79c79901eb5cffe10b0ec5852e", + "canonical_tree": "18e97093f04de23de5e9878fd22c1f5ed986d5f3", + "history_author_runtime": "37443f0d4d5ffa684b5423d58501856cadbe0655", + "composition_tree": "07d78241dca691015bb3e4d8d260b109672b7de0", + "composed_screen_git_blob": "ee2db9acacdc92d3aa8ba0bfe12f638e9418f9b4", + "files": [ + { + "path": "desktop/capture_desktop/__init__.py", + "git_blob": "48777bd04b62e3b3b877e12311f7257819ab3a07", + "bytes": 119, + "sha256": "8426c94323c4cca0879b8612345e3577d0a75f6239237a28d79d94a42004c3b5" + }, + { + "path": "desktop/capture_desktop/__main__.py", + "git_blob": "f78ccce984b725bf7263407d5b4b2d4c56131433", + "bytes": 723, + "sha256": "8dbad73a7373565a3513ccbb613f11bffdd13a05861c3e8e07392b8d51008aa2" + }, + { + "path": "desktop/capture_desktop/analysis_history.py", + "git_blob": "1b8fd23aee632cc3af19990b9d7685c6a3ed1b5e", + "bytes": 6375, + "sha256": "2e0db8cee59ef268d3c91ea0beac7d761d83a3003862841cc9d7f1782fd3543c" + }, + { + "path": "desktop/capture_desktop/app.py", + "git_blob": "363b6acbdcf0ba382bd040903946e6916ab282c9", + "bytes": 47945, + "sha256": "e33cf4446d4edfda3634cb5445aa9456d2f243a8b710c0d9c6497b2ec28078b2" + }, + { + "path": "desktop/capture_desktop/daemon_link.py", + "git_blob": "620e5a753fbd8448c3a57fcfa6a8b8540ac0bcd0", + "bytes": 10899, + "sha256": "ab76628bbe0231c7e5e4d570f2abed01100dddd6a24bb62020b670a6b62427dd" + }, + { + "path": "desktop/capture_desktop/export_wizard.py", + "git_blob": "b22d0098eb9af3860c654591e411dbab68a0f05d", + "bytes": 6734, + "sha256": "fb957ff184109bcb4e379dde30414048e855c93ec390f9b50c7ab603c3cd4e30" + }, + { + "path": "desktop/capture_desktop/main.py", + "git_blob": "90ad2adebae1f52ffabb889efe43a31dca1b6454", + "bytes": 1059, + "sha256": "e61c29a1925f8d85b24438f087dec360a4481a32e0dc2bd8ed8feb6629026e84" + }, + { + "path": "desktop/capture_desktop/persistence.py", + "git_blob": "2f2da2bfda654009baa0e723465c82c1690a0676", + "bytes": 3379, + "sha256": "cdb1fa0094fec72543d5051435850e51d78d79d4bde8d5c83520fa072a2c74c4" + }, + { + "path": "desktop/capture_desktop/schema_form.py", + "git_blob": "2d5fa62b1448e168e639e3e8879989a3461e1053", + "bytes": 12206, + "sha256": "7d825b5dc7566d630f31775df6fcc9def1e916eaff5be17a552bf89f28b3418b" + }, + { + "path": "desktop/capture_desktop/screen_analysis.py", + "git_blob": "ee2db9acacdc92d3aa8ba0bfe12f638e9418f9b4", + "bytes": 19067, + "sha256": "5c059bcca587879ec1cd4c21188db641a3063ad9848898bbc8ad500fb3c8f4c8" + }, + { + "path": "desktop/capture_desktop/screen_capture.py", + "git_blob": "b2d3cf05d57484f5efdbb0df85e5f0a065dab3d9", + "bytes": 34181, + "sha256": "4e101ddeeaed7f7f2b4ec2ab2e4b1f4f55ebb86f73b394d25cfd2b904cd2572e" + }, + { + "path": "desktop/capture_desktop/screen_presets.py", + "git_blob": "c143fb87629fb90f656a7a3b4b9f3c136b03f596", + "bytes": 5230, + "sha256": "b62d6f4bef6c1f0fc04b9eaf6a8afd1b2eeb17f6ce14946a06b0495ba33d402c" + }, + { + "path": "desktop/capture_desktop/screen_review.py", + "git_blob": "88a902ca7699faa2964f3fc22ec3348a339905a4", + "bytes": 7003, + "sha256": "e5aff59de4b194123ca4c4518b34e7b6103326fbd6b0280e2122d984d01072ec" + }, + { + "path": "desktop/capture_desktop/screen_settings.py", + "git_blob": "fe6d1e8884b7300e4cb5039b8e86679339e43b4d", + "bytes": 4581, + "sha256": "519436946827fac53d0be68270c2929bd1ce615a58b2372e9e3fc10619a7ba6e" + }, + { + "path": "desktop/capture_desktop/screen_setup.py", + "git_blob": "1df45aac30d63d6ab2e8ddc7efe0db394c513ab1", + "bytes": 11452, + "sha256": "01eb01ffffe835fcf5d26120d508800cc3cdac1e91ffaa3d0d2fa669c6326182" + }, + { + "path": "desktop/capture_desktop/state.py", + "git_blob": "95046ba5ef7f7bbf5685a54b7ae8fd400814148c", + "bytes": 17906, + "sha256": "97fc98498f4553fc7f052d0dc4db992cf2fc136ba7c4405cd275bd156c74e314" + }, + { + "path": "desktop/capture_desktop/theme.py", + "git_blob": "e309ce92bf66f65ca7c111698e1f536f05e4dca9", + "bytes": 12072, + "sha256": "c77f24e1afeb06400385bd0d535800f13dc15d972891e1ff8af504cbe5c818f3" + }, + { + "path": "desktop/capture_desktop/widgets_analysis_history.py", + "git_blob": "8798627cd7d694c5a09c3c402a739a4ec45b6574", + "bytes": 8458, + "sha256": "a3b77c87483c1412b50de7ddde1498f6bfd3968002fc3ac3bfa474a2477d9bc4" + }, + { + "path": "desktop/capture_desktop/widgets_analysis_jobs.py", + "git_blob": "c4d2f4513032d744f1f8066f0c887cda71d9b911", + "bytes": 6304, + "sha256": "5cdea6045456e61a58b5525dd224a22a140962d31d2adc5b0102168444468f98" + }, + { + "path": "desktop/capture_desktop/widgets_analysis_plots.py", + "git_blob": "bb6c3033b5e4ed96a2e08857d38715b836926bf5", + "bytes": 9382, + "sha256": "85c73f881ee7d60ef2f868f7ff73fc57c0a4ef99a717f7f5015534db23e1ab86" + }, + { + "path": "desktop/capture_desktop/widgets_analysis_scope.py", + "git_blob": "7b15a34fc1f8a9f31164d4ee9b4d144ff01a8d2d", + "bytes": 10391, + "sha256": "3f58ffba9125d0ce88fa99317f6aa593fe8aeb4b0dc1d799c95c9c04fb0b73ff" + }, + { + "path": "desktop/capture_desktop/widgets_mappings.py", + "git_blob": "62dd1b137ffc54a05aa81f37eb8627dd12e0032a", + "bytes": 3658, + "sha256": "89808d37cb0fce476665a24766963c7a509f5b1802d05dedbf9ca44351081f4b" + }, + { + "path": "desktop/capture_desktop/widgets_modality_expanded.py", + "git_blob": "70d67f7405730707ad67d1da0e71a7e87bf8b68e", + "bytes": 8566, + "sha256": "12db25b37e8b2724e5eaabdcb1810aa979633885097b6ec11c33d98a46a83a70" + }, + { + "path": "desktop/capture_desktop/widgets_preview.py", + "git_blob": "d0a760164a413616ab406a54d81c7b3f9b30d638", + "bytes": 27254, + "sha256": "78d79c9af67f7e0cbcee3a3a693a22e72753256ca465bab7edb9c2037822dec4" + }, + { + "path": "desktop/capture_desktop/widgets_radar_array.py", + "git_blob": "d270e7aa8b36a9a6376cfbd76a46ec6448bb9ae4", + "bytes": 2965, + "sha256": "be08874ade0b4d9197ea85cb6ae3b30db75273ddd3c426faaaf28b4f796653a8" + }, + { + "path": "desktop/capture_desktop/widgets_session_header.py", + "git_blob": "b1f4cbf5ab35ef06b4bf1da45f0be6ffb34b0a4a", + "bytes": 5749, + "sha256": "b9e11a7e3709283ed37bacbe96836d6720467f2bdcb934d75491df5dc02927fa" + }, + { + "path": "desktop/capture_desktop/widgets_session_timeline.py", + "git_blob": "2d9ba524b1e6231c934f6d037796a53e135a12f8", + "bytes": 10010, + "sha256": "7671ad4b632fd83498ad0c02f9030e4f46a0ef2d99a3764c13de3996e3c2ade4" + }, + { + "path": "desktop/pyproject.toml", + "git_blob": "dada23f8692dfda4c7c07fc012608844c7f41ab9", + "bytes": 552, + "sha256": "3646f83dcc0764b3c8cb198b98b03201dc47808bb80bfec4837e329e47bd012f" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/__init__.py", + "git_blob": "67a4fb257b771af771edb4010e573ceeab86a51f", + "bytes": 497, + "sha256": "14cfe6dccd33a0bda74fac3c9339e1a37a3538b2110a8ae6e307801b776eb43a" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/discover.py", + "git_blob": "d5c4fa7e06ac6e9139ebfc78fade90a3df5e451a", + "bytes": 4023, + "sha256": "344ee5d7cb0f5e95ac7524a0c1141b0a293bb9445e2bd4789c6736f39cfcb90d" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/eval/__init__.py", + "git_blob": "140fcb2784c4b73ddf69d21ddccfdcc8191cc0aa", + "bytes": 154, + "sha256": "54661df9ed7d7e0d4b1c2ab5941f107ceb608e4fdfaff810014ef5fad1431fe1" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/eval/job.py", + "git_blob": "95d40a6c28aabcdc311c18e3e195627f29ceb1a7", + "bytes": 3984, + "sha256": "a7f2a43c2fc3723c471e42a5532465dc5cfa44d4411c6cf581bba6910603fc57" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/features/__init__.py", + "git_blob": "e52dc3839105744e19193f8fc8067b818389a20b", + "bytes": 66, + "sha256": "3cdd6c626b6da12b8df56d8ddf35fca27c0a744865965ec01dd89d47da476fa1" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/features/emg.py", + "git_blob": "7f7536500a63ddc8b06774b8da65df8d56cd4f2b", + "bytes": 3072, + "sha256": "11f8f8350464b7c7c079353ca649b4c4aad2580ef8d355fe741c025c262b168e" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/features/imu.py", + "git_blob": "0ee47b3d579e4c3732634958dda21ae724beca9e", + "bytes": 2605, + "sha256": "246bfd1cc3ce72afa0680537062b6795e22b8a06ba6301503d7489a4440c6849" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/features/io.py", + "git_blob": "b998063a5036b73a67b773f70c193b1f9827c248", + "bytes": 1409, + "sha256": "c677d209292cca790ccdf1a64ba834f71a078ccce31ea57452e67ece358822ca" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/features/numeric_batch.py", + "git_blob": "77f19ccb048c93c0f4fca460eef0502180b37717", + "bytes": 4030, + "sha256": "ecdeb88ca4dd093b973294a53954e9fa0e5d6b4b908225a52d097ef70c7d2154" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/features/radar_doppler.py", + "git_blob": "ee20f7314cb1af4512901d6009f73e3dddf9025c", + "bytes": 2289, + "sha256": "cffc0ecbb8053fbc2244850c1927469366f4ae93b5439e4d194de2065877fa5c" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/features/radar_frame.py", + "git_blob": "e798dee0fb72dd261b504a99ac76f815515dda9e", + "bytes": 3323, + "sha256": "f85c5fe5e2db68606f68e36a42a0c8f323086f0b1e7f233c0ddefa24cdccb443" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/features/video_qc.py", + "git_blob": "fa73c80d39a0d699f80d7e877b37167cf8b48b6a", + "bytes": 1766, + "sha256": "0e25c50e01fc2da47bc7b510d68ba3e72aba33d3e1c79c57b727f5c55c723e27" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/grids.py", + "git_blob": "2e03f79d9317d2d97b721321130a9a5e6212b111", + "bytes": 1007, + "sha256": "936c5404783145f7a2bc4c13df22d3b85612bcb227115bba74f0b78a11c0c483" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/jobs.py", + "git_blob": "7badee5cdf5a4b30a283e0dcbb2c5d85fb787489", + "bytes": 19627, + "sha256": "e7e9dda44eb014d18192563f1e2c0ae78cece850fbc853b0be3919daaf5ee276" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/kinematics/__init__.py", + "git_blob": "aaf360b8a0085f89b95cd976857f0933596098a7", + "bytes": 178, + "sha256": "50a0f7fd39648abf269fc549d2c17eb48b1dc9add10ebdb76edc1935d6f80160" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/kinematics/compute.py", + "git_blob": "928751e9c861e2b0da298214269e57111f492865", + "bytes": 6899, + "sha256": "6e3ca19bfda0c02877f5d778f0c1191b5aebad605373732ef182bd714dd7f086" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/kinematics/job.py", + "git_blob": "fb8be113d8699427072f6dbcdae222a37738ac18", + "bytes": 4523, + "sha256": "d676e84f54aa1ae2b0f998c2cb37c4e02541c1fd0e3464e38e9865c0049a7239" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/kinematics/registry.py", + "git_blob": "a28cfd708c90552401fb0b3157c60f713a06e14f", + "bytes": 1155, + "sha256": "1e53fb9da4c6a2743bc1a3f0e687d94599cf995d33f2a2555e0ce5ebc3966d48" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/loaders/__init__.py", + "git_blob": "eb6fae21d4bb79055f8d1af1528e846020f21459", + "bytes": 361, + "sha256": "2d51c509baf3c0b5c33360637d12e5ce3c7507a859e4f37030f2c3d711ef0b3d" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/loaders/base.py", + "git_blob": "941a6aa3cea6777f90534ea634cccf8fdd319a3f", + "bytes": 2461, + "sha256": "696093b31f22d2bef32fc2962c7a11249a590a0b4d776c40cef4edcbc1e48a97" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/loaders/emg.py", + "git_blob": "c35d22af7bdeea570e6ae45a713428627e90894c", + "bytes": 3089, + "sha256": "86eb7114be689cdbd2edd76affa2994e7278714916692a35381abd02ba9d599a" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/loaders/imu.py", + "git_blob": "8823f04bd089789ca4cbff6602154bf066d4161d", + "bytes": 2773, + "sha256": "5ea4747145bf5588974dfd72c834766436c5a2bc0d58d34ace0f8ef403b310d6" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/loaders/mcap_iter.py", + "git_blob": "b61ca0a914e4d3909790839774327aa5824c1b71", + "bytes": 1196, + "sha256": "03a418e7689840e378665aac92c42769dd14ba2c88a821a5cbf0cee80766540c" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/loaders/numeric_batch.py", + "git_blob": "668e5397d6a603d8665fe639b3218128bbda72c2", + "bytes": 7139, + "sha256": "7c84c0425c1b9b821df711f4c40ea89ac13f267dbe6472922eb41a9263e4835c" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/loaders/radar_doppler.py", + "git_blob": "fc87bfb7fbbeb98ad8d5d11b3438b2d04882de6c", + "bytes": 1539, + "sha256": "4942d08eb47229839e339ce7f2f8a64aee7e5fab44bac77029fcd7a3e3e490c1" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/loaders/radar_frame.py", + "git_blob": "a44af5392ba2b5b8b64de685f42772b141f1b8b1", + "bytes": 1828, + "sha256": "d071f9d95b371798974698fd0caa1fc4c865a85fb772232fd43e7227b15fad2b" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/loaders/video.py", + "git_blob": "6a192cd5999b45df08c666b9dad21dc29cf91824", + "bytes": 2200, + "sha256": "3c3e873ab641904a39ca649dac39072f11948031d068cc21ee459e996d1fc185" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/ml_bundle/__init__.py", + "git_blob": "619d634ebf6fcc82a7871ad9c463660a24fd65ae", + "bytes": 179, + "sha256": "e785a2e3bf65852018d811b38ecbaf6ff9c479648025789145218809dd50d8a1" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/ml_bundle/job.py", + "git_blob": "59c2e4df46aa041e48aaf7184a3dd0ba345aff6d", + "bytes": 9419, + "sha256": "c14c74760e20c818ce5e2428d0b03a8a949899b0bba6c46e37fa8fd797631c75" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/pipeline.py", + "git_blob": "8113ab4cb51678a122bbb702a23f2200c9333233", + "bytes": 5262, + "sha256": "e8c0152040ba5b5f3f37ac53fb5188bac9dd9aaf0d5816d6a718be505c20898c" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/plots/modality.py", + "git_blob": "1de343cc2e11e663501ba190441325d5637d1492", + "bytes": 2419, + "sha256": "bc3aa15ee79d50280a6c9d6aa144fe0519f85dd2c74a0cfa99323f7d57ecd28d" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/plots/style.py", + "git_blob": "3725e840e5eb046accea79d4b6376f902392dac8", + "bytes": 1249, + "sha256": "231e7b1c998f4349d5859295007235ffd41848f12fbb7819193bec9630cd3942" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/plots/sync_dashboard.py", + "git_blob": "828204e998a46b9571b3a2b3ba08acd9fc6caa31", + "bytes": 1149, + "sha256": "6f9e0c64193688eb841565729b9d1e9a64136779e892419acabdc81591afd3d5" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/plugins/__init__.py", + "git_blob": "39c9c93eab1f5abf65ea73299c34b05ec184dd63", + "bytes": 225, + "sha256": "c511d4b9cd1cda042b781b06fbb02d2d99004de214735d6daeb459d6e41381fe" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/plugins/dummy.py", + "git_blob": "0152651c271234bf38252bed51efda3a3fc19c0f", + "bytes": 1618, + "sha256": "facf059d247bca44f2697383e12cc1296b1d1d12bede1196f4a52a1352d60495" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/plugins/handlers.py", + "git_blob": "03c8589064dfc4c6cfec6e4d00b7f46b10014414", + "bytes": 10646, + "sha256": "9be2e1820529b94e54d06790d53aa94cf658f982efb4063c6b64f9d07acc4b2e" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/plugins/manifest.yaml", + "git_blob": "0628968ee3965170b486306f974c81dd4eb84a53", + "bytes": 3876, + "sha256": "1efe3ee2d9eeeeac03c2c03c582edf0119c9abd6d214dfdca3d827fa10a5c048" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/plugins/numeric.py", + "git_blob": "d8adbc1d90dbfdeac0cd9179c95f027532c1a5d4", + "bytes": 3390, + "sha256": "75b55cb453095ad5470ce2532b65d3dce771e6a2f8ad1e46a538b4291fa4cf93" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/plugins/registry.py", + "git_blob": "3c582e1ab0de2b22956ac47fb628227eacdd1faf", + "bytes": 5389, + "sha256": "33a4d07600db8b116fbd46b67492f62129df513df5b66a2c455dced0b2a9dc69" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/pose/__init__.py", + "git_blob": "108be2956adfed6328f397d88a3b61ebada0ac48", + "bytes": 156, + "sha256": "d58a03cae86259b2cb0ecd0a5ce2347c6824f14cfea6871c94d76acc3541a380" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/pose/job.py", + "git_blob": "1a1a3f2436b0ac8decc551f84e76fa6c4c6e602d", + "bytes": 6262, + "sha256": "1f4c44f443c07e22e8c9ca877232c6780c4b1da7834d5565b82cf547b2f4c439" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/qc.py", + "git_blob": "530b86af1247599c127e2d0c3fa5e4d7d12169f6", + "bytes": 9187, + "sha256": "f24e0593a3723311d41054aef40b56c4bb46d4f3ba5ef4b01afcae3a6cc4440a" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/report_html.py", + "git_blob": "bb8032024cfce30c6fe9a2bd2c13b0d2cbc2d102", + "bytes": 4716, + "sha256": "f2c89c7faf6e4edc265540140272396b4195eb5aed9edf05c4912aac74286f03" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/types.py", + "git_blob": "2adf26816e0ef9e84e6763cf8bbff69d64697949", + "bytes": 3428, + "sha256": "e7996d02483f69265a2ef2ec0b28078c86f4f479daa53e38faf8b4a62645d02c" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/version.py", + "git_blob": "d04b8cc1dd9271ca3ccf836d97436d9a961417c6", + "bytes": 62, + "sha256": "9e25143344b110699f68b6acdbef49576fc91c2cbda34956d7e2cb85bbbc4ae3" + }, + { + "path": "libs/python/capture_analysis/capture_analysis/windows.py", + "git_blob": "80bea6bd69365a48c5b204c26d054b8ae179437a", + "bytes": 5618, + "sha256": "af40235d55341d2a6b11d7f67a0195779676301fa822b2bd05240d138ee28c50" + }, + { + "path": "libs/python/capture_analysis/pyproject.toml", + "git_blob": "6db8b1158b14da660128d7ac0ceacb45b8eb9924", + "bytes": 677, + "sha256": "84cd96465e48439bdd81f5fa126fea5da11ee7587b488bfaaa67a4cd8f760c75" + }, + { + "path": "libs/python/capture_protocol/LICENSE", + "git_blob": "d645695673349e3947e8e5ae42332d0ac3164cd7", + "bytes": 11358, + "sha256": "cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30" + }, + { + "path": "libs/python/capture_protocol/NOTICE", + "git_blob": "7f9ac0678aa56452f06e6e5f3badc9a873e2008a", + "bytes": 124, + "sha256": "3efb470f58c900a58deaef889527e074206274b0fd5fb0e2e62613c093064307" + }, + { + "path": "libs/python/capture_protocol/capture_protocol/__init__.py", + "git_blob": "0e7ab2cf8689d3adbc689c283e8a23d12607b2d0", + "bytes": 698, + "sha256": "556f474a3d740adc03c40426acde432ab7a394b947f8268bd90eecc7832dff8a" + }, + { + "path": "libs/python/capture_protocol/capture_protocol/codec.py", + "git_blob": "3034065efca2c52e34c3e67e147bdda526d2c8db", + "bytes": 7011, + "sha256": "f6c09246a7b165358835e51b99b1508e68d840f4bdbd54b5fb72db33d4912712" + }, + { + "path": "libs/python/capture_protocol/capture_protocol/config_schema.py", + "git_blob": "c9b4a694e620e5597d338230fcb0f25ea3a757f6", + "bytes": 8444, + "sha256": "00d855895faec7d674cdb8e4da1ddc687888c9e9863f91d4950d24d9fb815e6e" + }, + { + "path": "libs/python/capture_protocol/capture_protocol/constants.py", + "git_blob": "2542cda6bdb6a83d4334336f34d92f80040bc4a0", + "bytes": 486, + "sha256": "7f187edf873cd13f55bc09ff7972785797eb488d74dd5befcb395fc928a71d72" + }, + { + "path": "libs/python/capture_protocol/capture_protocol/control_client.py", + "git_blob": "45e1c4b535ece8d7178cd6b32ab1affcc9e73e92", + "bytes": 20823, + "sha256": "68de412465b2eaa04886a2bb4566aa0595c898df7d7e782b3031b8ba919db7fa" + }, + { + "path": "libs/python/capture_protocol/capture_protocol/framing.py", + "git_blob": "9dd5021b815b31ab02eaaa814210525ebb543862", + "bytes": 2884, + "sha256": "3ff7c7284d9907a2ad516c83fab383a4151996da3f2d5a1d27e24d7c7575d92e" + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/__init__.py", + "git_blob": "16ae7d90a122b4973139c563ac0f72efa061b1de", + "bytes": 90, + "sha256": "1fac8216894ce1a1b5362de3b59398fbd78f005a59636aea9f074951bed5c1d7" + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/__init__.py", + "git_blob": "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", + "bytes": 0, + "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/__init__.py", + "git_blob": "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", + "bytes": 0, + "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/arrays_pb2.py", + "git_blob": "a29ed506c4dd33f697ba74d13b6e8a9c945c6b6d", + "bytes": 2876, + "sha256": "6355750076724275e49f9a5faec383b2be92c0336ed58805a88954964bd13b86" + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/common_pb2.py", + "git_blob": "66031212a0da44800dcc671b0d4bf0cd39e71f06", + "bytes": 9746, + "sha256": "6736e3b86b3c8749d34065794da1c880772ce69e2f248fdd2febd003f083bbd3" + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/control_pb2.py", + "git_blob": "0597489cf8609a76e2094270965039da9b739ca3", + "bytes": 20028, + "sha256": "f2eea386aebf830ec47fa7379e6fb0493e0a199efecc7b90974bc8bb8c8b96b6" + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/data/__init__.py", + "git_blob": "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", + "bytes": 0, + "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/data/emg_batch_pb2.py", + "git_blob": "d8495ebeb8ab140824eaa5412be0779cf929ec6a", + "bytes": 1624, + "sha256": "1db5ef51143a546072e34cc7be7b263db996fa5f4d0d71606b230cb75b531a14" + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/data/imu_frame_pb2.py", + "git_blob": "54bbf93dc638cdab95f49744ea7e0b43fefad374", + "bytes": 2222, + "sha256": "4a2048d2a737362bf26b99166e95c457d1492fcfba8848c894fe4d2748ff9f51" + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/data/numeric_batch_pb2.py", + "git_blob": "beedaaae054bfb083af3642c96ca7c64af14cc8d", + "bytes": 1454, + "sha256": "a087cc019b9849f4ef47bcdf4c789a7da90d443240b7bef97c832bb23c1d4e24" + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/data/radar_doppler_pb2.py", + "git_blob": "ad8fe84317d2f4049682f70bead19f90c6932457", + "bytes": 1773, + "sha256": "d1b85358aba0c2f4fc1745218463e9951224322604b18b068a2195359dcf790e" + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/data/radar_frame_pb2.py", + "git_blob": "cef636d7b030b037b23331eec9a86f3b152bc358", + "bytes": 1729, + "sha256": "995ddbbb0aa614afb15088cf039c741421c33ea3e3e963ef1a7361b24754b862" + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/data/video_timing_pb2.py", + "git_blob": "17937a141a9a2d81858cf52d74bc4705afc940b7", + "bytes": 1722, + "sha256": "002a79858ccd2d7763769a1fe1be6a16a7f6b8727d15f952d191bcd2240ba5ef" + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/events_pb2.py", + "git_blob": "030bd4a90be609403e7709605607d8d5b993776e", + "bytes": 5480, + "sha256": "72951a468b0480e7fefc4fd3f9b4caac5fda0abdadf4ffcca92d4f19286429ce" + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/health_pb2.py", + "git_blob": "b27bd32ec488168871ca2342062eb576d56a9e8e", + "bytes": 5898, + "sha256": "e1e0baa7073a9886e4d982d4f00020b490bfd46c32b1b4df129fd0477c1f5e61" + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/presets_pb2.py", + "git_blob": "d20925410185e5cf52bbc56e438534c1c5ff1102", + "bytes": 2066, + "sha256": "d27336594b548f2e6e7ae212fe6de198e6e699c62a5f27752f691d7928ccb27b" + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/preview_pb2.py", + "git_blob": "cb04387df1614a8b9d9755a702129bbbb8d6374e", + "bytes": 5333, + "sha256": "c992e91b9aef0aa0ec8d595eba2f7079889264d9e4de120b623afd1d8702c695" + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/project_pb2.py", + "git_blob": "a8e71f0a426858cc679cb87ce31d1379e70a2817", + "bytes": 3355, + "sha256": "983bc5715147297cdcecca343b9a450f2095fcc1e895859cc3c52a3213d933f5" + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/source_pb2.py", + "git_blob": "b72752efedc743d236713e51283dce923a526f55", + "bytes": 8053, + "sha256": "d15b443f27c910c0e809af19fed81d9c1a75f7112501df85877bf4bf9bc4f7a8" + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/storage_pb2.py", + "git_blob": "4dd1b48ab16900c5c3e88d9788cebf83ee93cc5a", + "bytes": 5487, + "sha256": "f7a7b8903af9bfc2d2a419622c86cc057aed2a898949e4261475a7ac61222474" + }, + { + "path": "libs/python/capture_protocol/capture_protocol/generated/capture/v1/worker_pb2.py", + "git_blob": "7f3a4fc372384523638853f4bd458f49b664ba70", + "bytes": 11165, + "sha256": "112e832172913024c6fad128a9a9559bbcd14b18de06b1f2a3161ac380258dc0" + }, + { + "path": "libs/python/capture_protocol/capture_protocol/handshake.py", + "git_blob": "9386e73b3c1eecb683d9d0ca98ad415268e307af", + "bytes": 4763, + "sha256": "63f740c992edf8812f666b79f9cd866d9ea33e65e5b310a5ebda2f5ef98ac115" + }, + { + "path": "libs/python/capture_protocol/capture_protocol/structured_log.py", + "git_blob": "fc9c97b288280f4473c6b3c5b5e6ff07332fad49", + "bytes": 4657, + "sha256": "3d7883833286ecc004248294badcc0c66e44a57ecb7844ef281828d797b3c4fc" + }, + { + "path": "libs/python/capture_protocol/pyproject.toml", + "git_blob": "fa71ca45874d34076208507180c69c7a0e38fa76", + "bytes": 355, + "sha256": "61b2e33b2de2a153fb994144f532402c1b6b8ed02afb627ba0a15239e726ca71" + }, + { + "path": "libs/python/capture_session/capture_session/__init__.py", + "git_blob": "894e3c152a98b6e804de90122572afbcd929b3da", + "bytes": 2412, + "sha256": "da530f86c0d1d584862868ddba9f7087ccf5dfbddd64dd1e577337ecfd776419" + }, + { + "path": "libs/python/capture_session/capture_session/app_paths.py", + "git_blob": "46332cea7c62dd44247b219937ae6c8fbc747017", + "bytes": 561, + "sha256": "363e4522240e2356cac7492589cb207a798bc1af6031139bd1fa94890f1c4bfd" + }, + { + "path": "libs/python/capture_session/capture_session/package_reader.py", + "git_blob": "91fbf913c5af8489968425d7ceac51c04233d3e0", + "bytes": 6331, + "sha256": "9a1d9e6e7d24341a083cee602af9538413e948f3369b22660e484356e3d34eb1" + }, + { + "path": "libs/python/capture_session/capture_session/registry.py", + "git_blob": "c1d7799e1d2099424221b2f4af216a43a972c67a", + "bytes": 13989, + "sha256": "809b26ce8d8efc0559a3854cf85ea74b4e486fcd77d253ebfa76bade64b0a8d1" + }, + { + "path": "libs/python/capture_session/capture_session/settings_store.py", + "git_blob": "41b99cdaa78011d3d9b753c3131f32c72af9699f", + "bytes": 4622, + "sha256": "7719524a1f106cc54befcd21088810f9ec28f0160c8e88f60c374e1545fdb98d" + }, + { + "path": "libs/python/capture_session/pyproject.toml", + "git_blob": "c83450d780e97e5bd90feb48cef140917b6e47ff", + "bytes": 389, + "sha256": "3484887da96d4a2f32de8471b537d849f077b195c729ff0cc29307681e8d4895" + }, + { + "path": "libs/python/capture_worker/LICENSE", + "git_blob": "d645695673349e3947e8e5ae42332d0ac3164cd7", + "bytes": 11358, + "sha256": "cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30" + }, + { + "path": "libs/python/capture_worker/NOTICE", + "git_blob": "d74f1cbf89d4c89f70b3e75ab71cfadea8b7128f", + "bytes": 142, + "sha256": "2a7e69c4c7cd4e93a5cc9e9f984873a2d1276f465b91b10c71b951ebcfb2c588" + }, + { + "path": "libs/python/capture_worker/capture_worker/__init__.py", + "git_blob": "4bf1fc6b13bc4f5daab79d937ea89cf6c120cce3", + "bytes": 503, + "sha256": "c7ba88e956df8460002637eb3d8678a4c7217e680a388f833a22f073dc80f8fd" + }, + { + "path": "libs/python/capture_worker/capture_worker/__main__.py", + "git_blob": "a1047121f4173802074eeb66e5dcaf6c542c29c1", + "bytes": 150, + "sha256": "216422b76731bc985daa5fb0efe55a9d5ce600aa7e6081fa3df0c03afb6a893e" + }, + { + "path": "libs/python/capture_worker/capture_worker/cli.py", + "git_blob": "eb2d869f951f0205085b074d067282990657b5a0", + "bytes": 1818, + "sha256": "8a16c4cae0ffd11d4f9cd5d168f6abf1c6f9a4b5100e8edd18a29ce7d44d3f03" + }, + { + "path": "libs/python/capture_worker/capture_worker/preview.py", + "git_blob": "c47abe8a118ea022931843bde802132548194eef", + "bytes": 3202, + "sha256": "38b483dc06c9215b73e4c56c222fe563957180a5be58761a2c6dd4ea200b8e31" + }, + { + "path": "libs/python/capture_worker/capture_worker/transport.py", + "git_blob": "2e5e159bee3a0b5aa69bf90f62906feeffe23c8c", + "bytes": 5033, + "sha256": "020414c74bd08ec510e88da8c2f8b9ec5091a19cb585b4c54d2656b4bf300d35" + }, + { + "path": "libs/python/capture_worker/capture_worker/worker.py", + "git_blob": "d5ed2999fbb958116d73a8fa6319356d8b7d751a", + "bytes": 23439, + "sha256": "19a0dfd16a65479de884d4359a3d65f1bc127d8a6d4b44b93c6251757510de68" + }, + { + "path": "libs/python/capture_worker/capture_worker/writer.py", + "git_blob": "b3d194cc71dfa0d21884936a6ed5f7bdc95b3eb4", + "bytes": 6196, + "sha256": "b9e3b21ac26f2160da582a3f566a278dc4088c5a8b121d9b4e74f8d8c16cf96f" + }, + { + "path": "libs/python/capture_worker/pyproject.toml", + "git_blob": "5d79642edc9c1809fda636d5dcd78ad33e67abcc", + "bytes": 487, + "sha256": "0cba218b59a756185fedf72fb3a3307d1d9cb9218b6189ea92972d3cec139a46" + }, + { + "path": "pyproject.toml", + "git_blob": "52491c6beebc4b17983fc66bb8765154c33cf6d8", + "bytes": 1233, + "sha256": "0cb8de1ab3dfbfed84ff16b35f3c89c6440180183ee5851d5d80da83622e53d0" + }, + { + "path": "tests/analysis/test_numeric_batch_pipeline.py", + "git_blob": "9485adb27d02ab88e65d87576a06b86869a0360b", + "bytes": 19230, + "sha256": "43369bd0fea48d2c8b7dee1d8128b3bb131b508b7b0a14512fc457fcfdb0ba3c" + }, + { + "path": "tests/conftest.py", + "git_blob": "ad9b61fd8e9c1c3d74f91710d4e82dd7d899e6b4", + "bytes": 1773, + "sha256": "f669618fad17e906c91df7a1e9393fc7a54f458c6d62a4385436ba2622beca0e" + }, + { + "path": "tests/fixtures/mini_session/events/annotations.json", + "git_blob": "fe51488c7066f6687ef680d6bfaa4f7768ef205c", + "bytes": 3, + "sha256": "37517e5f3dc66819f61f5a7bb8ace1921282415f10551d2defa5c3eb0985b570" + }, + { + "path": "tests/fixtures/mini_session/events/checkpoints.json", + "git_blob": "fe51488c7066f6687ef680d6bfaa4f7768ef205c", + "bytes": 3, + "sha256": "37517e5f3dc66819f61f5a7bb8ace1921282415f10551d2defa5c3eb0985b570" + }, + { + "path": "tests/fixtures/mini_session/events/sync_anchors.json", + "git_blob": "fe51488c7066f6687ef680d6bfaa4f7768ef205c", + "bytes": 3, + "sha256": "37517e5f3dc66819f61f5a7bb8ace1921282415f10551d2defa5c3eb0985b570" + }, + { + "path": "tests/fixtures/mini_session/integrity.json", + "git_blob": "d10093b866427fcaed78a85e60e600d8657a86a7", + "bytes": 227, + "sha256": "af5d9bacd3eace7e831d48dee83eb5d9f578f4f4819d92218c4b55b0cb3ed556" + }, + { + "path": "tests/fixtures/mini_session/manifest.json", + "git_blob": "800dab5b41774bc043ebdee4714195770e75229b", + "bytes": 235, + "sha256": "c5254d3e4c0bc6a0ecaef124dc12d88117d647928a8e1725b71429097438d380" + }, + { + "path": "tests/fixtures/mini_session/processing/.gitkeep", + "git_blob": "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", + "bytes": 0, + "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + { + "path": "tests/fixtures/mini_session/sources/sim.emg.main/health/gaps.jsonl", + "git_blob": "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", + "bytes": 0, + "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + { + "path": "tests/fixtures/mini_session/sources/sim.emg.main/source.json", + "git_blob": "9528c95289b4b1b49d11d412b5ab2e3d019b4066", + "bytes": 112, + "sha256": "4e7626e51bfb804c27f83bf98ee186a47ec9f36fec0cbd7863ea8ecb1ecfbd10" + }, + { + "path": "tests/fixtures/mini_session/sources/sim.emg.main/streams/sim.emg.main.batch/segments/000000.mcap", + "git_blob": "320ce3607fadf57d05cf506987d045cf5b62ad9f", + "bytes": 28, + "sha256": "3c4d91b3bf5d48dcf54a598fff5b1b4ee42260b756d6f5df3986da496c6a9649" + }, + { + "path": "tests/fixtures/mini_session/sources/sim.emg.main/streams/sim.emg.main.batch/stream.json", + "git_blob": "12c4db8831572fc4ab3db9ba5f784fa236078e5f", + "bytes": 216, + "sha256": "8f8c02b89fd93e55643151e5222488e1174dd97a6b7a74f3ae5da8215b4d68e1" + }, + { + "path": "tests/fixtures/mini_session/sources/sim.imu.upper/source.json", + "git_blob": "fcc248c52b8319f5e7fd0067763b74640f0040dd", + "bytes": 118, + "sha256": "a6198f509edc557c1e1d8583a767a540962977751c80a1b6491e3d594b60c7a8" + }, + { + "path": "tests/fixtures/mini_session/sources/sim.imu.upper/streams/sim.imu.upper.frames/segments/000000.mcap", + "git_blob": "320ce3607fadf57d05cf506987d045cf5b62ad9f", + "bytes": 28, + "sha256": "3c4d91b3bf5d48dcf54a598fff5b1b4ee42260b756d6f5df3986da496c6a9649" + }, + { + "path": "tests/fixtures/mini_session/sources/sim.imu.upper/streams/sim.imu.upper.frames/stream.json", + "git_blob": "9c634d4af594372063fcc612331ba338ae95f8c9", + "bytes": 219, + "sha256": "ec39026bed1b833d4decb0ef7b0efb94c5557a5647bc50addc060bef3a30d50d" + }, + { + "path": "tests/ui/test_analysis_history.py", + "git_blob": "f013473f750b515a8305e2f7f8426b6520e26a65", + "bytes": 10465, + "sha256": "48175547922125c308fa49bbb84149e3dac8903902e7cc64fa7c15b4ca40eccd" + }, + { + "path": "workers/python_host/capture_sim/__init__.py", + "git_blob": "2646a1792544ac97cba76fd7d7246c313604351e", + "bytes": 259, + "sha256": "a3c8506a26d20b0b10cd55f00b019b7ddc1e2d4cb5cffd5c155d70ef338d21ae" + }, + { + "path": "workers/python_host/capture_sim/advertise.py", + "git_blob": "c93044ce53b7a38d2e7db9fcbad83174b394ffd2", + "bytes": 15205, + "sha256": "6a41dafed67d08d4e3829c053dc5a2767ae28293d63733b4b4ae187a8d4a94b9" + } + ], + "scope": "Exact Python/fixture slice for one native scope/history composition journey; no Windows MainWindow or complete suite claim." +} diff --git a/docs/evidence/analysis-history-401c5d17da79/independent/37443-candidate.log b/docs/evidence/analysis-history-401c5d17da79/independent/37443-candidate.log new file mode 100644 index 00000000..d38a4b73 --- /dev/null +++ b/docs/evidence/analysis-history-401c5d17da79/independent/37443-candidate.log @@ -0,0 +1,18 @@ +This plugin does not support propagateSizeHints() +candidate: fresh screen reopens real prior A result into gallery and inspector: True +candidate: package switch clears prior package result and launch targets: True +candidate: same basename in package B resolves only B saved figures and metadata: True +candidate: malformed-manifest is visibly unavailable: True +This plugin does not support propagateSizeHints() +candidate: malformed-manifest refuses opening without replacing valid B view: True +candidate: missing-manifest is visibly unavailable: True +candidate: missing-manifest refuses opening without replacing valid B view: True +candidate: foreign-session is visibly unavailable: True +candidate: foreign-session refuses opening without replacing valid B view: True +candidate: foreign-directory is visibly unavailable: True +candidate: foreign-directory refuses opening without replacing valid B view: True +candidate: unavailable-row inspection leaves all saved bytes unchanged: True +candidate: Open revalidates cached row when manifest disappears: True +candidate: failed Open preserves every persisted byte after controlled fixture rename: True +This plugin does not support propagateSizeHints() +candidate: actual QThread QC result exists before deferred delivery: True diff --git a/docs/evidence/analysis-history-401c5d17da79/independent/37443-manual-stall-receipt.json b/docs/evidence/analysis-history-401c5d17da79/independent/37443-manual-stall-receipt.json new file mode 100644 index 00000000..3bbe3755 --- /dev/null +++ b/docs/evidence/analysis-history-401c5d17da79/independent/37443-manual-stall-receipt.json @@ -0,0 +1,10 @@ +{ + "schema": "capturesuite.history.receiving.manual-loop-stall.v1", + "candidate": "37443f0d4d5ffa684b5423d58501856cadbe0655", + "method_sha256": "b46094d3d823145aa07aa088371c6a63343ee7c5d8a06b254c6a4669f8c52da8", + "last_completed_assertion": "actual QThread QC result exists before deferred delivery", + "assertions_completed": 15, + "outcome": "Manual processEvents/QTest.qWait did not return to Python after release. Receiver process was stopped with Ctrl-C through its exact session; exit130. This is a non-accepting harness outcome, not a claimed native-application failure.", + "source_change": "history refresh moved out of thread cleanup, worker/cleanup AST match canonical baseline", + "log_sha256": "3e4b3290f4d02af0cf1a6461560532dffcfb8cea4c5d5349da1d49113ba48e30" +} diff --git a/docs/evidence/analysis-history-401c5d17da79/independent/baseline-receipt.json b/docs/evidence/analysis-history-401c5d17da79/independent/baseline-receipt.json new file mode 100644 index 00000000..b668c5fd --- /dev/null +++ b/docs/evidence/analysis-history-401c5d17da79/independent/baseline-receipt.json @@ -0,0 +1,162 @@ +{ + "checks": [ + { + "evidence": { + "history_loaded_job_id": null, + "inspector": "job_id=retained-prior\nstatus=completed\ngap_policy=mask\nplugin_manifest=1.0.0\npath=/dev/shm/hamon-401c5d17da79-capturesuite-receiving/fixtures/package-a.mmsession/processing/jobs/retained-prior", + "last_job_dir": "/dev/shm/hamon-401c5d17da79-capturesuite-receiving/fixtures/package-a.mmsession/processing/jobs/retained-prior", + "linked_plot_count": 2, + "open_folder_enabled": false, + "open_report_enabled": false, + "package": "/dev/shm/hamon-401c5d17da79-capturesuite-receiving/fixtures/package-b.mmsession", + "png_count": 2, + "sync_title": "receiving-a-401c5d17da79 \u00b7 gap_policy=mask", + "tabs": [ + "Sync", + "emg sim.emg.main channel", + "imu sim.imu.upper accel" + ] + }, + "name": "baseline reproduces stale A view after switching to B", + "pass": true + }, + { + "evidence": { + "job_dir": "/dev/shm/hamon-401c5d17da79-capturesuite-receiving/fixtures/package-a.mmsession/processing/jobs/late-baseline-actual-qc", + "status": "completed" + }, + "name": "actual QThread QC result exists before deferred delivery", + "pass": true + }, + { + "evidence": { + "history_loaded_job_id": null, + "inspector": "job_id=late-baseline-actual-qc\nstatus=completed\ngap_policy=mask\nplugin_manifest=1.0.0\npath=/dev/shm/hamon-401c5d17da79-capturesuite-receiving/fixtures/package-a.mmsession/processing/jobs/late-baseline-actual-qc", + "last_job_dir": "/dev/shm/hamon-401c5d17da79-capturesuite-receiving/fixtures/package-a.mmsession/processing/jobs/late-baseline-actual-qc", + "linked_plot_count": 0, + "open_folder_enabled": true, + "open_report_enabled": true, + "package": "/dev/shm/hamon-401c5d17da79-capturesuite-receiving/fixtures/package-b.mmsession", + "png_count": 0, + "sync_title": "Sync dashboard", + "tabs": [ + "Sync" + ] + }, + "name": "baseline reproduces foreign binding after late real completion", + "pass": true + }, + { + "evidence": null, + "name": "delivery and reopening perform no persisted writes", + "pass": true + }, + { + "evidence": null, + "name": "all captured raw package bytes remain unchanged", + "pass": true + }, + { + "evidence": [], + "name": "no Qt error dialogs or worker failures occurred", + "pass": true + } + ], + "dialog_errors": [], + "free_bytes_after": 21540864, + "harness_sha256": "a5af6de29e75e3870121a7f03b1f3675f31f34c8615eb6ca6b7ecff560c838ce", + "mode": "baseline", + "pyside6": "6.11.2", + "python": "3.12.14 (main, Aug 25 2026, 14:00:49) [Clang 22.1.3 ]", + "qt_platform": "offscreen", + "result": "expected baseline defects reproduced", + "screens": { + "after_package_switch": { + "history_loaded_job_id": null, + "inspector": "job_id=retained-prior\nstatus=completed\ngap_policy=mask\nplugin_manifest=1.0.0\npath=/dev/shm/hamon-401c5d17da79-capturesuite-receiving/fixtures/package-a.mmsession/processing/jobs/retained-prior", + "last_job_dir": "/dev/shm/hamon-401c5d17da79-capturesuite-receiving/fixtures/package-a.mmsession/processing/jobs/retained-prior", + "linked_plot_count": 2, + "open_folder_enabled": false, + "open_report_enabled": false, + "package": "/dev/shm/hamon-401c5d17da79-capturesuite-receiving/fixtures/package-b.mmsession", + "png_count": 2, + "sync_title": "receiving-a-401c5d17da79 \u00b7 gap_policy=mask", + "tabs": [ + "Sync", + "emg sim.emg.main channel", + "imu sim.imu.upper accel" + ] + }, + "initial_a": { + "history_loaded_job_id": null, + "inspector": "job_id=retained-prior\nstatus=completed\ngap_policy=mask\nplugin_manifest=1.0.0\npath=/dev/shm/hamon-401c5d17da79-capturesuite-receiving/fixtures/package-a.mmsession/processing/jobs/retained-prior", + "last_job_dir": "/dev/shm/hamon-401c5d17da79-capturesuite-receiving/fixtures/package-a.mmsession/processing/jobs/retained-prior", + "linked_plot_count": 2, + "open_folder_enabled": false, + "open_report_enabled": false, + "package": "/dev/shm/hamon-401c5d17da79-capturesuite-receiving/fixtures/package-a.mmsession", + "png_count": 2, + "sync_title": "receiving-a-401c5d17da79 \u00b7 gap_policy=mask", + "tabs": [ + "Sync", + "emg sim.emg.main channel", + "imu sim.imu.upper accel" + ] + }, + "late_after_delivery": { + "history_loaded_job_id": null, + "inspector": "job_id=late-baseline-actual-qc\nstatus=completed\ngap_policy=mask\nplugin_manifest=1.0.0\npath=/dev/shm/hamon-401c5d17da79-capturesuite-receiving/fixtures/package-a.mmsession/processing/jobs/late-baseline-actual-qc", + "last_job_dir": "/dev/shm/hamon-401c5d17da79-capturesuite-receiving/fixtures/package-a.mmsession/processing/jobs/late-baseline-actual-qc", + "linked_plot_count": 0, + "open_folder_enabled": true, + "open_report_enabled": true, + "package": "/dev/shm/hamon-401c5d17da79-capturesuite-receiving/fixtures/package-b.mmsession", + "png_count": 0, + "sync_title": "Sync dashboard", + "tabs": [ + "Sync" + ] + }, + "late_before_delivery": { + "history_loaded_job_id": null, + "inspector": "No job loaded", + "last_job_dir": "/dev/shm/hamon-401c5d17da79-capturesuite-receiving/fixtures/package-a.mmsession/processing/jobs/retained-prior", + "linked_plot_count": 0, + "open_folder_enabled": false, + "open_report_enabled": false, + "package": "/dev/shm/hamon-401c5d17da79-capturesuite-receiving/fixtures/package-b.mmsession", + "png_count": 0, + "sync_title": "Sync dashboard", + "tabs": [ + "Sync" + ] + } + }, + "screenshot": { + "path": "/dev/shm/hamon-401c5d17da79-capturesuite-receiving/evidence/baseline-qt.png", + "sha256": "9709a37b5abd159c5eafb7d58b8fb096bda7926fe109ec1f11eb8d50a47ade0f" + }, + "source_commit": "72c15d6b623e217291a824e4e4808a385df896a9", + "source_imports": { + "capture_analysis": { + "path": "/dev/shm/capturesuite-history-401c5d17da79/source/libs/python/capture_analysis/capture_analysis/__init__.py", + "sha256": "14cfe6dccd33a0bda74fac3c9339e1a37a3538b2110a8ae6e307801b776eb43a" + }, + "capture_analysis.jobs": { + "path": "/dev/shm/capturesuite-history-401c5d17da79/source/libs/python/capture_analysis/capture_analysis/jobs.py", + "sha256": "e7e9dda44eb014d18192563f1e2c0ae78cece850fbc853b0be3919daaf5ee276" + }, + "capture_desktop.screen_analysis": { + "path": "/dev/shm/hamon-401c5d17da79-capturesuite-receiving/pins/baseline-screen_analysis.py", + "sha256": "1437b02b942f44378870540f12c5494d08693329abb5d00ca64c0c264f57633e" + }, + "capture_desktop.state": { + "path": "/dev/shm/capturesuite-history-401c5d17da79/source/desktop/capture_desktop/state.py", + "sha256": "97fc98498f4553fc7f052d0dc4db992cf2fc136ba7c4405cd275bd156c74e314" + }, + "capture_desktop.widgets_analysis_plots": { + "path": "/dev/shm/capturesuite-history-401c5d17da79/source/desktop/capture_desktop/widgets_analysis_plots.py", + "sha256": "85c73f881ee7d60ef2f868f7ff73fc57c0a4ef99a717f7f5015534db23e1ab86" + } + } +} diff --git a/docs/evidence/analysis-history-401c5d17da79/independent/baseline.log b/docs/evidence/analysis-history-401c5d17da79/independent/baseline.log new file mode 100644 index 00000000..1af6374c --- /dev/null +++ b/docs/evidence/analysis-history-401c5d17da79/independent/baseline.log @@ -0,0 +1,10 @@ +This plugin does not support propagateSizeHints() +This plugin does not support propagateSizeHints() +baseline: baseline reproduces stale A view after switching to B: True +This plugin does not support propagateSizeHints() +baseline: actual QThread QC result exists before deferred delivery: True +baseline: baseline reproduces foreign binding after late real completion: True +baseline: delivery and reopening perform no persisted writes: True +baseline: all captured raw package bytes remain unchanged: True +baseline: no Qt error dialogs or worker failures occurred: True +{"mode": "baseline", "result": "expected baseline defects reproduced", "checks": 6, "free_bytes": 21540864} diff --git a/docs/evidence/analysis-history-401c5d17da79/independent/c0b5530-candidate.log b/docs/evidence/analysis-history-401c5d17da79/independent/c0b5530-candidate.log new file mode 100644 index 00000000..fd4b850c --- /dev/null +++ b/docs/evidence/analysis-history-401c5d17da79/independent/c0b5530-candidate.log @@ -0,0 +1,38 @@ +This plugin does not support propagateSizeHints() +candidate: fresh screen reopens real prior A result into gallery and inspector: True +candidate: package switch clears prior package result and launch targets: True +candidate: same basename in package B resolves only B saved figures and metadata: True +candidate: malformed-manifest is visibly unavailable: True +This plugin does not support propagateSizeHints() +candidate: malformed-manifest refuses opening without replacing valid B view: True +candidate: missing-manifest is visibly unavailable: True +candidate: missing-manifest refuses opening without replacing valid B view: True +candidate: foreign-session is visibly unavailable: True +candidate: foreign-session refuses opening without replacing valid B view: True +candidate: foreign-directory is visibly unavailable: True +candidate: foreign-directory refuses opening without replacing valid B view: True +candidate: unavailable-row inspection leaves all saved bytes unchanged: True +candidate: Open revalidates cached row when manifest disappears: True +candidate: failed Open preserves every persisted byte after controlled fixture rename: True +This plugin does not support propagateSizeHints() +candidate: actual QThread QC result exists before deferred delivery: True +Fatal Python error: Segmentation fault + +Current thread 0x00007f68537fe6c0 (most recent call first): + + +Thread 0x00007f6889b6f740 (most recent call first): + File "", line 468 in _joinrealpath + File "", line 424 in realpath + File "/opt/codex/runtimes/codex-primary-runtime/dependencies/python/lib/python3.12/pathlib.py", line 1240 in resolve + File "/dev/shm/capturesuite-history-401c5d17da79/source/desktop/capture_desktop/analysis_history.py", line 41 in _jobs_root + File "/dev/shm/capturesuite-history-401c5d17da79/source/desktop/capture_desktop/analysis_history.py", line 124 in list_saved_jobs + File "/dev/shm/capturesuite-history-401c5d17da79/source/desktop/capture_desktop/widgets_analysis_history.py", line 129 in refresh + File "/dev/shm/capturesuite-history-401c5d17da79/source/desktop/capture_desktop/screen_analysis.py", line 439 in _on_thread_finished + File "/dev/shm/hamon-401c5d17da79-capturesuite-receiving/methods/receive_history.py", line 224 in pump + File "/dev/shm/hamon-401c5d17da79-capturesuite-receiving/methods/receive_history.py", line 231 in until + File "/dev/shm/hamon-401c5d17da79-capturesuite-receiving/methods/receive_history.py", line 373 in receive + File "/dev/shm/hamon-401c5d17da79-capturesuite-receiving/methods/receive_history.py", line 433 in main + File "/dev/shm/hamon-401c5d17da79-capturesuite-receiving/methods/receive_history.py", line 437 in + +Extension modules: numpy._core._multiarray_umath, numpy.linalg._umath_linalg, PIL._imaging, kiwisolver._cext, pyarrow.lib, numpy.random._common, numpy.random.bit_generator, numpy.random._bounded_integers, numpy.random._pcg64, numpy.random._generator, numpy.random._mt19937, numpy.random._philox, numpy.random._sfc64, numpy.random.mtrand, _cyutility, pandas._libs._cyutility, pandas._libs.tslibs.ccalendar, pandas._libs.tslibs.np_datetime, pandas._libs.tslibs.dtypes, pandas._libs.tslibs.base, pandas._libs.tslibs.nattype, pandas._libs.tslibs.timezones, pandas._libs.properties, pandas._libs.tslibs.fields, pandas._libs.tslibs.timedeltas, pandas._libs.tslibs.tzconversion, pandas._libs.tslibs.timestamps, pandas._libs.tslibs.offsets, pandas._libs.tslibs.strptime, pandas._libs.tslibs.parsing, pandas._libs.tslibs.conversion, pandas._libs.tslibs.period, pandas._libs.tslibs.vectorized, pandas._libs.ops_dispatch, pandas._libs.missing, pandas._libs.hashtable, pandas._libs.algos, pandas._libs.interval, pandas._libs.lib, pyarrow._compute, pandas._libs.ops, pandas._libs.hashing, pandas._libs.arrays, pandas._libs.tslib, pandas._libs.sparse, pandas._libs.internals, pandas._libs.indexing, pandas._libs.index, pandas._libs.writers, pandas._libs.join, pandas._libs.window.aggregations, pandas._libs.window.indexers, pandas._libs.reshape, pandas._libs.groupby, pandas._libs.json, pandas._libs.parsers, pandas._libs.testing, google._upb._message, shiboken6.Shiboken, PySide6.QtCore, PySide6.QtGui, PySide6.QtWidgets, PySide6.QtTest, PySide6.QtSvg, PySide6.QtOpenGLWidgets, PySide6.QtOpenGL, scipy._cyutility, scipy._lib._ccallback_c, yaml._yaml (total: 69) diff --git a/docs/evidence/analysis-history-401c5d17da79/independent/c0b5530-eventloop-receipt.json b/docs/evidence/analysis-history-401c5d17da79/independent/c0b5530-eventloop-receipt.json new file mode 100644 index 00000000..89965851 --- /dev/null +++ b/docs/evidence/analysis-history-401c5d17da79/independent/c0b5530-eventloop-receipt.json @@ -0,0 +1,74 @@ +{ + "candidate": { + "baseline": "72c15d6b623e217291a824e4e4808a385df896a9", + "commit": "c0b5530c03cce3e42a0430e5411cddf1df716e19", + "focused_tests": "7 passed in 2.61s; no skips", + "harness_notes": "Replaced QTest.qWait polling with QEventLoop plus settling cleanup after a timeout/unsafe teardown; production worker and signal wiring remain baseline bytes.", + "inputs": { + "desktop/capture_desktop/analysis_history.py": { + "bytes": 6375, + "sha256": "2e0db8cee59ef268d3c91ea0beac7d761d83a3003862841cc9d7f1782fd3543c" + }, + "desktop/capture_desktop/screen_analysis.py": { + "bytes": 16407, + "sha256": "4a2e3eaee50fba5236b5567be993582a557de6fe2c62cc0bf3f424483beefb2b" + }, + "desktop/capture_desktop/widgets_analysis_history.py": { + "bytes": 8458, + "sha256": "a3b77c87483c1412b50de7ddde1498f6bfd3968002fc3ac3bfa474a2477d9bc4" + }, + "tests/ui/test_analysis_history.py": { + "bytes": 9023, + "sha256": "eabe6a4e663307965ce00a1f9032325bfc7be6357b7a3a91b79820cafc4c0a97" + } + }, + "runtime": "/workspace/scratch/234cae4aee53/capturesuite-venv/bin/python", + "tree": "c384c9553757fb1614405d124a5026ae49b4be71" + }, + "checks": [ + { + "detail": { + "job_dir": "/dev/shm/hamon-401c5d17da79-capturesuite-receiving/fixtures/package-a.mmsession/processing/jobs/late-eventloop-actual-qc", + "status": "completed" + }, + "label": "real QC was persisted before release", + "pass": true + }, + { + "detail": null, + "label": "selected B is unbound before A completion", + "pass": true + }, + { + "detail": { + "inspector": "No job loaded", + "last_job_dir": "", + "package": "/dev/shm/hamon-401c5d17da79-capturesuite-receiving/fixtures/package-b.mmsession" + }, + "label": "native event loop settles without binding previous-package result", + "pass": true + }, + { + "detail": null, + "label": "completion preserves all bytes after actual job persistence", + "pass": true + }, + { + "detail": [], + "label": "no native error dialogs", + "pass": true + } + ], + "errors": [], + "events": [ + "actual QThread started in native application loop", + "selected B, released real A completion", + "native event loop accepted exact completion boundary" + ], + "loop": "QApplication.exec with QTimer; no manual processEvents or QTest.qWait", + "method_sha256": "f05476354e1d1e40478bcc4ed3e5e753bb3baa99fe1a822e3f12e15018236d7d", + "pass": true, + "process_return": 0, + "schema": "capturesuite.history.native-eventloop-control.v1", + "seconds": 0.24924598599318415 +} diff --git a/docs/evidence/analysis-history-401c5d17da79/independent/c0b5530-eventloop.log b/docs/evidence/analysis-history-401c5d17da79/independent/c0b5530-eventloop.log new file mode 100644 index 00000000..aa4ce3ed --- /dev/null +++ b/docs/evidence/analysis-history-401c5d17da79/independent/c0b5530-eventloop.log @@ -0,0 +1,7 @@ +This plugin does not support propagateSizeHints() +real QC was persisted before release True +selected B is unbound before A completion True +native event loop settles without binding previous-package result True +completion preserves all bytes after actual job persistence True +no native error dialogs True +{"pass": true, "checks": 5, "seconds": 0.24924598599318415, "code": 0} diff --git a/docs/evidence/analysis-history-401c5d17da79/independent/c0b5530-failure-receipt.json b/docs/evidence/analysis-history-401c5d17da79/independent/c0b5530-failure-receipt.json new file mode 100644 index 00000000..87060a24 --- /dev/null +++ b/docs/evidence/analysis-history-401c5d17da79/independent/c0b5530-failure-receipt.json @@ -0,0 +1,345 @@ +{ + "archives": { + "candidate-reopened-a.png": { + "bytes": 204136, + "path": "/dev/shm/hamon-401c5d17da79-capturesuite-receiving/evidence/c0b5530-candidate-reopened-a.png", + "sha256": "a4e78ff532b45507142b2053db0b2391994cb51f9120eeaebb5135cf76755b8c" + }, + "candidate-reopened-b.png": { + "bytes": 217136, + "path": "/dev/shm/hamon-401c5d17da79-capturesuite-receiving/evidence/c0b5530-candidate-reopened-b.png", + "sha256": "a87a869be6e6f65ed50af9e63f386d54edcef524f3f1e44072d1f2318824d6a7" + }, + "candidate.log": { + "bytes": 4375, + "path": "/dev/shm/hamon-401c5d17da79-capturesuite-receiving/evidence/c0b5530-candidate.log", + "sha256": "6aae6bbe36f9f7070a42910ecbbf2297a3dd222d5834cbeabbd816e4003f39b4" + }, + "eventloop-receipt.json": { + "bytes": 2679, + "path": "/dev/shm/hamon-401c5d17da79-capturesuite-receiving/evidence/c0b5530-eventloop-receipt.json", + "sha256": "17a363b7ffee224a1f65f1eea6a61c4e83d47e8b30ae68aab07ccb2298c425d1" + }, + "eventloop.log": { + "bytes": 375, + "path": "/dev/shm/hamon-401c5d17da79-capturesuite-receiving/evidence/c0b5530-eventloop.log", + "sha256": "42724fb02c89311d1a34d82672cbc9c9034c7ac9a376ec365c4f6c53bc01ed52" + } + }, + "assertions_completed": 15, + "candidate_commit": "c0b5530c03cce3e42a0430e5411cddf1df716e19", + "candidate_tree": "c384c9553757fb1614405d124a5026ae49b4be71", + "crash_location": "native thread has no Python frame; main thread in AnalysisScreen._on_thread_finished -> AnalysisHistory.refresh -> Path.resolve", + "fixture_files": { + "package-a.mmsession/events/annotations.json": { + "bytes": 3, + "sha256": "37517e5f3dc66819f61f5a7bb8ace1921282415f10551d2defa5c3eb0985b570" + }, + "package-a.mmsession/events/checkpoints.json": { + "bytes": 3, + "sha256": "37517e5f3dc66819f61f5a7bb8ace1921282415f10551d2defa5c3eb0985b570" + }, + "package-a.mmsession/events/sync_anchors.json": { + "bytes": 3, + "sha256": "37517e5f3dc66819f61f5a7bb8ace1921282415f10551d2defa5c3eb0985b570" + }, + "package-a.mmsession/integrity.json": { + "bytes": 225, + "sha256": "2fb4194b22d4b1c373f25f9ecab51d0c80e14f42a52f53293fd727ce5418f140" + }, + "package-a.mmsession/manifest.json": { + "bytes": 250, + "sha256": "6cc54886cc63fa1263a4077fec322454fdfa133a408836a75451fd77eb7c5243" + }, + "package-a.mmsession/processing/jobs/late-baseline-actual-qc/job_manifest.json": { + "bytes": 2400, + "sha256": "bbb88191cb522d3314139b6ebcb4cd2e6b8aa6c6b7df362d0653a0a75dcba7bc" + }, + "package-a.mmsession/processing/jobs/late-baseline-actual-qc/logs/job.log": { + "bytes": 187, + "sha256": "59f307f1af8f7e20fe908e17afdf3047f6d7eda3d04d2d7e5153f258b6377d37" + }, + "package-a.mmsession/processing/jobs/late-baseline-actual-qc/params.json": { + "bytes": 260, + "sha256": "88f55fe8dddb0794c98f693dd21fdd7764a6bac45203e11ba52eab3ebaa40fc3" + }, + "package-a.mmsession/processing/jobs/late-baseline-actual-qc/reports/qc.html": { + "bytes": 1629, + "sha256": "db815562d270dc133bce019f0c0791bea4e9af52fc62ce7107a41ea6a8485d20" + }, + "package-a.mmsession/processing/jobs/late-baseline-actual-qc/reports/qc.json": { + "bytes": 1296, + "sha256": "2a1addc8accb001643f81a4b1061458f8fa27de6ffcc157fbed5ddb837c9cf27" + }, + "package-a.mmsession/processing/jobs/late-candidate-actual-qc/job_manifest.json": { + "bytes": 2401, + "sha256": "b8e5cceef8c8cc17430606013cc72df5e779880bb77ffaedd9fa043c908fd171" + }, + "package-a.mmsession/processing/jobs/late-candidate-actual-qc/logs/job.log": { + "bytes": 188, + "sha256": "c2b223c3686c245380c6b3788d45deb8f4a56ca9d420039af2ff598f6eb66cc1" + }, + "package-a.mmsession/processing/jobs/late-candidate-actual-qc/params.json": { + "bytes": 261, + "sha256": "9aad1ac26d07fdbf51e882ad70c97ae15942b3057755083b0a8b063506d23fe8" + }, + "package-a.mmsession/processing/jobs/late-candidate-actual-qc/reports/qc.html": { + "bytes": 1629, + "sha256": "db815562d270dc133bce019f0c0791bea4e9af52fc62ce7107a41ea6a8485d20" + }, + "package-a.mmsession/processing/jobs/late-candidate-actual-qc/reports/qc.json": { + "bytes": 1296, + "sha256": "2a1addc8accb001643f81a4b1061458f8fa27de6ffcc157fbed5ddb837c9cf27" + }, + "package-a.mmsession/processing/jobs/late-eventloop-actual-qc/job_manifest.json": { + "bytes": 2401, + "sha256": "612f56635415e2ab8882b9545257b1b2cf50401bb0b3a45358e98904ac908f41" + }, + "package-a.mmsession/processing/jobs/late-eventloop-actual-qc/logs/job.log": { + "bytes": 188, + "sha256": "1fe30cd8c3f36e5370ac406741decd78802073fb793d43b6d5cba99722d346dd" + }, + "package-a.mmsession/processing/jobs/late-eventloop-actual-qc/params.json": { + "bytes": 261, + "sha256": "be905b67387880dbfa478ee1a90def66691d600c2ca2a348ef518e99bd82384f" + }, + "package-a.mmsession/processing/jobs/late-eventloop-actual-qc/reports/qc.html": { + "bytes": 1629, + "sha256": "db815562d270dc133bce019f0c0791bea4e9af52fc62ce7107a41ea6a8485d20" + }, + "package-a.mmsession/processing/jobs/late-eventloop-actual-qc/reports/qc.json": { + "bytes": 1296, + "sha256": "2a1addc8accb001643f81a4b1061458f8fa27de6ffcc157fbed5ddb837c9cf27" + }, + "package-a.mmsession/processing/jobs/retained-prior/features/_schema.json": { + "bytes": 2880, + "sha256": "c80f7d1e05378bf2399098e9887fc463edda22e366236eab3e9b1b0526d1f0f0" + }, + "package-a.mmsession/processing/jobs/retained-prior/features/emg/sim.emg.main/windows.csv": { + "bytes": 501, + "sha256": "0c9b8016e1295976eb10eabdb913efff752cf9936bf4a7cab1d3107a85ca97ff" + }, + "package-a.mmsession/processing/jobs/retained-prior/features/emg/sim.emg.main/windows.parquet": { + "bytes": 7411, + "sha256": "c5d6d1727acd151ca0b1430eecb0dd0491fe2863a9f7c163d7524bfed584e60f" + }, + "package-a.mmsession/processing/jobs/retained-prior/features/imu/sim.imu.upper/windows.csv": { + "bytes": 628, + "sha256": "62212faf4179e9050c4d7a2e3530a461c70d0e56b227138e31b0c273bb21a277" + }, + "package-a.mmsession/processing/jobs/retained-prior/features/imu/sim.imu.upper/windows.parquet": { + "bytes": 7645, + "sha256": "ff4ca0fbfed45e13e95f73d03d8ba56ce0f8305868012ecb5101df277a449ba9" + }, + "package-a.mmsession/processing/jobs/retained-prior/figures/emg_sim.emg.main_channels.png": { + "bytes": 91869, + "sha256": "4c7a4aee76c4895cf99e38874de271e83a52c0e7389093c14a93344e9dc43853" + }, + "package-a.mmsession/processing/jobs/retained-prior/figures/imu_sim.imu.upper_accel.png": { + "bytes": 24298, + "sha256": "8cc603bf604d8925ba13be2c77e0bd8d8f8efbce9529e7d459a449fd61e6a8a4" + }, + "package-a.mmsession/processing/jobs/retained-prior/figures/sync_dashboard.png": { + "bytes": 37253, + "sha256": "bda125c256b17dbd688ec825c2a5b9b8542f346ce95209faf15efadad5c78d48" + }, + "package-a.mmsession/processing/jobs/retained-prior/figures/sync_dashboard_series.json": { + "bytes": 1963, + "sha256": "ba1181c30b0a3ab1b26b716e56bf0787f2e67aa4178cd511f0106486d04aa8e6" + }, + "package-a.mmsession/processing/jobs/retained-prior/job_manifest.json": { + "bytes": 4508, + "sha256": "21471f1ee0cae441202b4b704c6cd1359558ac1bf27f077668508eb1368ae6e7" + }, + "package-a.mmsession/processing/jobs/retained-prior/logs/job.log": { + "bytes": 179, + "sha256": "3cf99c71a0e4e3046b791ad2c04e388adfe452959b315d8dd5df6d278a5aaf63" + }, + "package-a.mmsession/processing/jobs/retained-prior/params.json": { + "bytes": 252, + "sha256": "9c0e1ab18949727f29352f1a602ae65d74db48f8453a49faa72fbc95c518b35b" + }, + "package-a.mmsession/processing/jobs/retained-prior/reports/qc.html": { + "bytes": 1629, + "sha256": "db815562d270dc133bce019f0c0791bea4e9af52fc62ce7107a41ea6a8485d20" + }, + "package-a.mmsession/processing/jobs/retained-prior/reports/qc.json": { + "bytes": 1296, + "sha256": "2a1addc8accb001643f81a4b1061458f8fa27de6ffcc157fbed5ddb837c9cf27" + }, + "package-a.mmsession/sources/sim.emg.main/health/gaps.jsonl": { + "bytes": 0, + "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "package-a.mmsession/sources/sim.emg.main/source.json": { + "bytes": 112, + "sha256": "4e7626e51bfb804c27f83bf98ee186a47ec9f36fec0cbd7863ea8ecb1ecfbd10" + }, + "package-a.mmsession/sources/sim.emg.main/streams/sim.emg.main.batch/segments/000000.mcap": { + "bytes": 1095, + "sha256": "6f3b9bd4ce01238f122649a1139a290ea6193893938a95f3ac61dd61a447d997" + }, + "package-a.mmsession/sources/sim.emg.main/streams/sim.emg.main.batch/stream.json": { + "bytes": 224, + "sha256": "5307697f957309eaca816fa0e20c4799c900e2598a8acf66a59928aa83b305b2" + }, + "package-a.mmsession/sources/sim.imu.upper/source.json": { + "bytes": 118, + "sha256": "a6198f509edc557c1e1d8583a767a540962977751c80a1b6491e3d594b60c7a8" + }, + "package-a.mmsession/sources/sim.imu.upper/streams/sim.imu.upper.frames/segments/000000.mcap": { + "bytes": 1678, + "sha256": "c477a0e0865086fbb4154c977def4d93ea5fb38cc098a4862c45b21b966014c9" + }, + "package-a.mmsession/sources/sim.imu.upper/streams/sim.imu.upper.frames/stream.json": { + "bytes": 219, + "sha256": "ec39026bed1b833d4decb0ef7b0efb94c5557a5647bc50addc060bef3a30d50d" + }, + "package-b.mmsession/events/annotations.json": { + "bytes": 3, + "sha256": "37517e5f3dc66819f61f5a7bb8ace1921282415f10551d2defa5c3eb0985b570" + }, + "package-b.mmsession/events/checkpoints.json": { + "bytes": 3, + "sha256": "37517e5f3dc66819f61f5a7bb8ace1921282415f10551d2defa5c3eb0985b570" + }, + "package-b.mmsession/events/sync_anchors.json": { + "bytes": 3, + "sha256": "37517e5f3dc66819f61f5a7bb8ace1921282415f10551d2defa5c3eb0985b570" + }, + "package-b.mmsession/integrity.json": { + "bytes": 225, + "sha256": "2fb4194b22d4b1c373f25f9ecab51d0c80e14f42a52f53293fd727ce5418f140" + }, + "package-b.mmsession/manifest.json": { + "bytes": 250, + "sha256": "26ea1e6f375028575b0c72477dddff58248a6ab0f1d63a91c797c9c5d44c2af8" + }, + "package-b.mmsession/processing/jobs/foreign-directory": { + "symlink": "/dev/shm/hamon-401c5d17da79-capturesuite-receiving/fixtures/package-a.mmsession/processing/jobs/retained-prior" + }, + "package-b.mmsession/processing/jobs/foreign-session/job_manifest.json": { + "bytes": 4509, + "sha256": "95066d530c9a56380fd58679dae6680d6e3f678064405438c5985e37526aff7a" + }, + "package-b.mmsession/processing/jobs/malformed-manifest/job_manifest.json": { + "bytes": 9, + "sha256": "69cb18c1151284aa03aa4e6840be1940f366267b30a7e9a64330cd76c68d8bb4" + }, + "package-b.mmsession/processing/jobs/missing-manifest/params.json": { + "bytes": 3, + "sha256": "ca3d163bab055381827226140568f3bef7eaac187cebd76878e0b63e9e442356" + }, + "package-b.mmsession/processing/jobs/retained-prior/features/_schema.json": { + "bytes": 2880, + "sha256": "c80f7d1e05378bf2399098e9887fc463edda22e366236eab3e9b1b0526d1f0f0" + }, + "package-b.mmsession/processing/jobs/retained-prior/features/emg/sim.emg.main/windows.csv": { + "bytes": 504, + "sha256": "d7244bae8dab4e4e8ef00cf72cf387343720e31a25499c3f4741741209d1e9ad" + }, + "package-b.mmsession/processing/jobs/retained-prior/features/emg/sim.emg.main/windows.parquet": { + "bytes": 7411, + "sha256": "60858ced982730b51829ae8080bd4217f9289373b65b501cc28411fdd1d83af0" + }, + "package-b.mmsession/processing/jobs/retained-prior/features/imu/sim.imu.upper/windows.csv": { + "bytes": 628, + "sha256": "62212faf4179e9050c4d7a2e3530a461c70d0e56b227138e31b0c273bb21a277" + }, + "package-b.mmsession/processing/jobs/retained-prior/features/imu/sim.imu.upper/windows.parquet": { + "bytes": 7645, + "sha256": "ff4ca0fbfed45e13e95f73d03d8ba56ce0f8305868012ecb5101df277a449ba9" + }, + "package-b.mmsession/processing/jobs/retained-prior/figures/emg_sim.emg.main_channels.png": { + "bytes": 93063, + "sha256": "87a315c7e23f334c9c8065cdab60ca26b8af8b965bd0ebaf33645864d0048124" + }, + "package-b.mmsession/processing/jobs/retained-prior/figures/imu_sim.imu.upper_accel.png": { + "bytes": 24298, + "sha256": "8cc603bf604d8925ba13be2c77e0bd8d8f8efbce9529e7d459a449fd61e6a8a4" + }, + "package-b.mmsession/processing/jobs/retained-prior/figures/sync_dashboard.png": { + "bytes": 37408, + "sha256": "07ebc1ff60a592f2086dcdfe63652666946329dbadf29dece5b6c84f87dd6082" + }, + "package-b.mmsession/processing/jobs/retained-prior/figures/sync_dashboard_series.json": { + "bytes": 1964, + "sha256": "01cdce9f387ad77ac1ea7632cee3c1d84fc879671cbf46e195c64bf1ec4a8c52" + }, + "package-b.mmsession/processing/jobs/retained-prior/job_manifest.json": { + "bytes": 4508, + "sha256": "95acf1efa8439e47fc5b011813f2fc5313a92de692f25459e3d56e68533a0389" + }, + "package-b.mmsession/processing/jobs/retained-prior/logs/job.log": { + "bytes": 179, + "sha256": "f0c184fbf12257a9ad4e41329ab95a5578ca769ca5fb84d9b9a32a18df8d7f46" + }, + "package-b.mmsession/processing/jobs/retained-prior/params.json": { + "bytes": 252, + "sha256": "9c0e1ab18949727f29352f1a602ae65d74db48f8453a49faa72fbc95c518b35b" + }, + "package-b.mmsession/processing/jobs/retained-prior/reports/qc.html": { + "bytes": 1629, + "sha256": "93671b7b67b1bf290a50a7a8d69e6fee6968caa1e540bf0615add4d0d1127671" + }, + "package-b.mmsession/processing/jobs/retained-prior/reports/qc.json": { + "bytes": 1296, + "sha256": "0c3647238cffb1ae94177f950a9b1407a88e0730b4503cffd27118c4634bc706" + }, + "package-b.mmsession/processing/jobs/selected-before-missing/job_manifest.receiver-held.json": { + "bytes": 2400, + "sha256": "92e19a48f6c45e672d82c898f3827c8f353bf9e4a705c50f0012ddb033f2e845" + }, + "package-b.mmsession/processing/jobs/selected-before-missing/logs/job.log": { + "bytes": 187, + "sha256": "75632168a67884e1ae52815a3ea0d9d3826f2d57f6ea8c23f1fa3f72a7591938" + }, + "package-b.mmsession/processing/jobs/selected-before-missing/params.json": { + "bytes": 260, + "sha256": "564c6f9ab9fc6eed20ffe5a8de9fd55533f59d2783e38b1217cb65f88358b20a" + }, + "package-b.mmsession/processing/jobs/selected-before-missing/reports/qc.html": { + "bytes": 1629, + "sha256": "93671b7b67b1bf290a50a7a8d69e6fee6968caa1e540bf0615add4d0d1127671" + }, + "package-b.mmsession/processing/jobs/selected-before-missing/reports/qc.json": { + "bytes": 1296, + "sha256": "0c3647238cffb1ae94177f950a9b1407a88e0730b4503cffd27118c4634bc706" + }, + "package-b.mmsession/sources/sim.emg.main/health/gaps.jsonl": { + "bytes": 0, + "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "package-b.mmsession/sources/sim.emg.main/source.json": { + "bytes": 112, + "sha256": "4e7626e51bfb804c27f83bf98ee186a47ec9f36fec0cbd7863ea8ecb1ecfbd10" + }, + "package-b.mmsession/sources/sim.emg.main/streams/sim.emg.main.batch/segments/000000.mcap": { + "bytes": 1094, + "sha256": "9e997481c9b39b6a6b2d647df873fea26b04337c41571e77427a7f8ca9cda63b" + }, + "package-b.mmsession/sources/sim.emg.main/streams/sim.emg.main.batch/stream.json": { + "bytes": 224, + "sha256": "5307697f957309eaca816fa0e20c4799c900e2598a8acf66a59928aa83b305b2" + }, + "package-b.mmsession/sources/sim.imu.upper/source.json": { + "bytes": 118, + "sha256": "a6198f509edc557c1e1d8583a767a540962977751c80a1b6491e3d594b60c7a8" + }, + "package-b.mmsession/sources/sim.imu.upper/streams/sim.imu.upper.frames/segments/000000.mcap": { + "bytes": 1678, + "sha256": "c477a0e0865086fbb4154c977def4d93ea5fb38cc098a4862c45b21b966014c9" + }, + "package-b.mmsession/sources/sim.imu.upper/streams/sim.imu.upper.frames/stream.json": { + "bytes": 219, + "sha256": "ec39026bed1b833d4decb0ef7b0efb94c5557a5647bc50addc060bef3a30d50d" + } + }, + "fixture_path": "/dev/shm/hamon-401c5d17da79-capturesuite-receiving/fixtures-c0b5530-failure", + "harness_sha256": "b46094d3d823145aa07aa088371c6a63343ee7c5d8a06b254c6a4669f8c52da8", + "last_completed_assertion": "actual QThread QC result exists before deferred delivery", + "native_loop_control": "QApplication.exec control on same source passed 5 checks, exit 0, 0.249 s; this receipt does not claim a native application-loop failure", + "no_timeout_occurred": true, + "result": "manual-pump receiving process exited 139 after real result persistence and release; full candidate acceptance withheld", + "schema": "capturesuite.history.receiving.native-failure.v1" +} diff --git a/docs/evidence/analysis-history-401c5d17da79/independent/methods/receive_history.py b/docs/evidence/analysis-history-401c5d17da79/independent/methods/receive_history.py new file mode 100644 index 00000000..79c8393f --- /dev/null +++ b/docs/evidence/analysis-history-401c5d17da79/independent/methods/receive_history.py @@ -0,0 +1,437 @@ +# SPDX-License-Identifier: GPL-3.0-only +"""Independent real Qt receiving of saved-job/package lifetime boundaries. + +Uses the project's genuine analysis pipeline. Only return delivery is delayed for +one actual QThread QC result; the analysis algorithm and worker are unmodified. +All writable fixtures are confined to this receiver's unique RAM directory. +""" +from __future__ import annotations + +import argparse +import dataclasses +import hashlib +import importlib +import importlib.util +import json +import os +from pathlib import Path +import shutil +import sys +import threading +import time +import traceback + +ROOT = Path('/dev/shm/hamon-401c5d17da79-capturesuite-receiving') +DEFAULT_SOURCE = Path('/dev/shm/capturesuite-history-401c5d17da79/source') +BASE_COMMIT = '72c15d6b623e217291a824e4e4808a385df896a9' + + +def digest(path: Path) -> str: + return hashlib.sha256(path.read_bytes()).hexdigest() + + +def snapshot(path: Path) -> dict: + result = {} + for item in sorted(path.rglob('*')): + if item.is_symlink(): + result[str(item.relative_to(path))] = {'symlink': os.readlink(item)} + elif item.is_file(): + result[str(item.relative_to(path))] = {'bytes': item.stat().st_size, 'sha256': digest(item)} + return result + + +def save_json(path: Path, doc: dict) -> None: + path.write_text(json.dumps(doc, indent=2, sort_keys=True) + '\n') + + +def bootstrap(source: Path) -> None: + for part in ('tmp', 'mpl', 'evidence', 'pins'): + (ROOT / part).mkdir(parents=True, exist_ok=True) + os.environ['QT_QPA_PLATFORM'] = 'offscreen' + os.environ['PYTHONDONTWRITEBYTECODE'] = '1' + os.environ['TMPDIR'] = str(ROOT / 'tmp') + os.environ['MPLCONFIGDIR'] = str(ROOT / 'mpl') + os.environ['MPLBACKEND'] = 'Agg' + sys.dont_write_bytecode = True + sys.path[:0] = [str(source / rel) for rel in ( + 'desktop', 'libs/python/capture_analysis', 'libs/python/capture_session', + 'libs/python/capture_protocol')] + import capture_analysis, capture_session, capture_protocol, capture_desktop + for module in (capture_analysis, capture_session, capture_protocol, capture_desktop): + if not Path(module.__file__).resolve().is_relative_to(source): + raise AssertionError(f'Editable dependency escaped source: {module.__file__}') + + +def make_package(source: Path, dest: Path, session: str, amplitude: float) -> Path: + """The existing phase-B native fixture shape, without deleting placeholders.""" + import numpy as np + from mcap.writer import Writer + from capture_protocol.generated.capture.v1.data import emg_batch_pb2, imu_frame_pb2 + if dest.exists(): + raise RuntimeError(f'Refusing to replace existing fixture {dest}') + shutil.copytree(source / 'tests/fixtures/mini_session', dest, + ignore=shutil.ignore_patterns('*.mcap', 'processing', '__pycache__')) + manifest_path = dest / 'manifest.json' + manifest = json.loads(manifest_path.read_text()) + manifest['sessionId'] = session + save_json(manifest_path, manifest) + samples = (amplitude * np.sin(2 * np.pi * 40.0 * np.arange(400) / 2000.0)).astype(np.float32) + emg = emg_batch_pb2.EmgBatch() + emg.timing.session_time_ns = 0 + emg.timing.sequence_number = 1 + emg.first_sample_index = 0 + emg.sample_count = 400 + emg.channel_ids.extend(['ch0', 'ch1']) + emg.samples_f32_le = np.stack([samples, samples * 0.5]).astype(' None: + from capture_analysis import JobParams, run + fixture_root = ROOT / 'fixtures' + if fixture_root.exists(): + raise RuntimeError('Receiving fixtures already exist; use the saved receipt, do not regenerate.') + if shutil.disk_usage(ROOT).free < 2_000_000: + raise RuntimeError('Less than the bounded 2 MB fixture budget is available.') + fixture_root.mkdir() + result_doc = {'source_commit': BASE_COMMIT, 'fixtures': {}, 'method': + 'Real protobuf EMG/IMU MCAP, synchronous native all jobs, same job basename in distinct sessions.'} + for letter, amplitude in (('a', 1.5), ('b', 0.75)): + package = make_package(source, fixture_root / f'package-{letter}.mmsession', + f'receiving-{letter}-401c5d17da79', amplitude) + raw_before = snapshot(package) + result = run(package, JobParams(command='all', overwrite_job_id='retained-prior')) + assert result.status in ('completed', 'completed_with_warnings'), result.status + raw_after = {key: value for key, value in snapshot(package).items() if not key.startswith('processing/')} + assert raw_before == raw_after + figures = sorted((result.job_dir / 'figures').glob('*.png')) + assert len(figures) >= 2, 'Need genuine images beyond the linked Sync view' + series = json.loads((result.job_dir / 'figures/sync_dashboard_series.json').read_text()) + assert series.get('series'), 'Need genuine linked plot data' + result_doc['fixtures'][letter] = { + 'package': str(package), 'job_dir': str(result.job_dir), 'job_id': result.job_id, + 'status': result.status, 'session_id': f'receiving-{letter}-401c5d17da79', + 'figures': [p.name for p in figures], 'sync_series_count': len(series['series']), + 'raw_unchanged_by_analysis': True, 'files': snapshot(package), + } + print(f'Prepared real {letter} result: {len(figures)} PNGs, {len(series["series"])} linked series', flush=True) + # These intentionally unavailable rows are admitted only to our private fixture. + b = fixture_root / 'package-b.mmsession/processing/jobs' + (b / 'malformed-manifest').mkdir() + (b / 'malformed-manifest/job_manifest.json').write_text('{not JSON') + (b / 'missing-manifest').mkdir() + (b / 'missing-manifest/params.json').write_text('{}\n') + (b / 'foreign-session').mkdir() + foreign = json.loads((fixture_root / 'package-a.mmsession/processing/jobs/retained-prior/job_manifest.json').read_text()) + foreign['jobId'] = 'foreign-session' + save_json(b / 'foreign-session/job_manifest.json', foreign) + (b / 'foreign-directory').symlink_to(fixture_root / 'package-a.mmsession/processing/jobs/retained-prior', target_is_directory=True) + # A valid real QC result lets the UI hold a catalog row before its manifest is moved. + result = run(b.parents[1], JobParams(command='qc', overwrite_job_id='selected-before-missing')) + assert result.status in ('completed', 'completed_with_warnings') + result_doc['selected_before_missing'] = str(result.job_dir) + result_doc['fixture_files'] = snapshot(fixture_root) + result_doc['total_bytes'] = sum(row.get('bytes', 0) for row in result_doc['fixture_files'].values()) + result_doc['free_bytes_after'] = shutil.disk_usage(ROOT).free + save_json(ROOT / 'evidence/fixtures.json', result_doc) + print(json.dumps({key: result_doc[key] for key in ('total_bytes', 'free_bytes_after')}, sort_keys=True)) + + +def load_screen(mode: str, source: Path): + if mode == 'baseline': + name = 'capture_desktop.screen_analysis' + spec = importlib.util.spec_from_file_location(name, ROOT / 'pins/baseline-screen_analysis.py') + module = importlib.util.module_from_spec(spec) + sys.modules[name] = module + spec.loader.exec_module(module) + return module.AnalysisScreen + pins = json.loads((ROOT / 'pins/candidate-inputs.json').read_text()) + for rel, record in pins['inputs'].items(): + assert digest(source / rel) == record['sha256'], f'Candidate bytes changed: {rel}' + return importlib.import_module('capture_desktop.screen_analysis').AnalysisScreen + + +def receive(mode: str, source: Path) -> int: + from PySide6 import __version__ as qt_version + from PySide6.QtCore import QCoreApplication, QEvent, Qt + from PySide6.QtTest import QTest + from PySide6.QtWidgets import QApplication, QComboBox, QLabel, QMessageBox, QPushButton + import capture_analysis + from capture_desktop.state import CaptureState + Screen = load_screen(mode, source) + app = QApplication.instance() or QApplication([]) + a = ROOT / 'fixtures/package-a.mmsession' + b = ROOT / 'fixtures/package-b.mmsession' + job_a, job_b = (p / 'processing/jobs/retained-prior' for p in (a, b)) + receipt = {'mode': mode, 'source_commit': BASE_COMMIT, 'python': sys.version, + 'pyside6': qt_version, 'qt_platform': app.platformName(), 'checks': [], + 'screens': {}, 'dialog_errors': [], 'source_imports': {}} + for name in ('capture_analysis', 'capture_analysis.jobs', 'capture_desktop.screen_analysis', + 'capture_desktop.widgets_analysis_plots', 'capture_desktop.state'): + module = importlib.import_module(name) + receipt['source_imports'][name] = {'path': module.__file__, 'sha256': digest(Path(module.__file__))} + if mode == 'candidate': + receipt['candidate_inputs'] = json.loads((ROOT / 'pins/candidate-inputs.json').read_text()) + fixture_before = snapshot(ROOT / 'fixtures') + raw_before = {key: val for key, val in fixture_before.items() if '/processing/' not in key} + release, ready = threading.Event(), threading.Event() + holder = {} + real_run = capture_analysis.run + screen = Screen(CaptureState()) + screen.resize(1200, 900) + screen.show() + + def pump() -> None: + app.processEvents() + for widget in app.topLevelWidgets(): + if isinstance(widget, QMessageBox) and widget.isVisible(): + receipt['dialog_errors'].append(widget.text()) + widget.accept() + QTest.qWait(5) + + def until(predicate, message: str, seconds: float = 25.0) -> None: + deadline = time.monotonic() + seconds + while not predicate(): + if time.monotonic() > deadline: + raise AssertionError(message) + pump() + pump() + + def state() -> dict: + tabs = screen._gallery._tabs + png_count = 0 + for i in range(1, tabs.count()): + for label in tabs.widget(i).findChildren(QLabel): + image = label.pixmap() + if image is not None and not image.isNull(): + png_count += 1 + return {'package': screen._package, 'last_job_dir': screen._last_job_dir, + 'inspector': screen._inspector._meta.text(), + 'tabs': [tabs.tabText(i) for i in range(tabs.count())], + 'png_count': png_count, 'sync_title': screen._gallery._sync._title.text(), + 'linked_plot_count': len(screen._gallery._sync._linked), + 'history_loaded_job_id': screen._history.loaded_job_id if hasattr(screen, '_history') else None, + 'open_folder_enabled': screen._btn_open_job.isEnabled(), + 'open_report_enabled': screen._btn_open_report.isEnabled()} + + def check(name: str, condition: bool, evidence=None) -> None: + receipt['checks'].append({'name': name, 'pass': bool(condition), 'evidence': evidence}) + print(f'{mode}: {name}: {bool(condition)}', flush=True) + if not condition: + raise AssertionError(name) + + def open_history(job_id: str) -> None: + combo = screen.findChild(QComboBox, 'analysisHistoryJob') + button = screen.findChild(QPushButton, 'analysisHistoryOpen') + assert combo is not None and button is not None + matches = [i for i in range(combo.count()) if getattr(combo.itemData(i), 'job_id', None) == job_id] + assert len(matches) == 1, (job_id, matches) + combo.setCurrentIndex(matches[0]) + pump() + assert button.isEnabled(), f'Cannot open {job_id}' + QTest.mouseClick(button, Qt.MouseButton.LeftButton) + pump() + + try: + screen.set_package(str(a)) + pump() + if mode == 'candidate': + open_history('retained-prior') + loaded_a = state() + check('fresh screen reopens real prior A result into gallery and inspector', + loaded_a['last_job_dir'] == str(job_a) and str(job_a) in loaded_a['inspector'] + and loaded_a['png_count'] >= 1 and loaded_a['linked_plot_count'] >= 1 + and 'receiving-a-401c5d17da79' in loaded_a['sync_title'], loaded_a) + else: + # Baseline already lacks history. Bind the existing renderer directly as + # the established control, then challenge only package/lifetime behavior. + screen._gallery.load_job_dir(job_a) + screen._inspector.load_job_dir(job_a) + screen._last_job_dir = str(job_a) + pump() + receipt['screens']['initial_a'] = state() + if mode == 'candidate': + visual_path = ROOT / 'evidence/candidate-reopened-a.png' + assert screen.grab().save(str(visual_path)) + receipt['screens']['initial_a_screenshot'] = {'path': str(visual_path), 'sha256': digest(visual_path)} + screen.set_package(str(b)) + pump() + switched = state() + receipt['screens']['after_package_switch'] = switched + cleared = switched['last_job_dir'] == '' and switched['inspector'] == 'No job loaded' and switched['png_count'] == 0 and switched['linked_plot_count'] == 0 + if mode == 'candidate': + check('package switch clears prior package result and launch targets', + cleared and not switched['open_folder_enabled'] and not switched['open_report_enabled'], switched) + open_history('retained-prior') + loaded_b = state() + check('same basename in package B resolves only B saved figures and metadata', + loaded_b['last_job_dir'] == str(job_b) and str(job_b) in loaded_b['inspector'] + and loaded_b['png_count'] >= 1 and loaded_b['linked_plot_count'] >= 1 + and 'receiving-b-401c5d17da79' in loaded_b['sync_title'], loaded_b) + visual_path = ROOT / 'evidence/candidate-reopened-b.png' + assert screen.grab().save(str(visual_path)) + receipt['screens']['reopened_b_screenshot'] = {'path': str(visual_path), 'sha256': digest(visual_path)} + before_refusals = snapshot(ROOT / 'fixtures') + combo = screen.findChild(QComboBox, 'analysisHistoryJob') + button = screen.findChild(QPushButton, 'analysisHistoryOpen') + for bad_id in ('malformed-manifest', 'missing-manifest', 'foreign-session', 'foreign-directory'): + matches = [i for i in range(combo.count()) if getattr(combo.itemData(i), 'job_id', None) == bad_id] + check(f'{bad_id} is visibly unavailable', len(matches) == 1, matches) + combo.setCurrentIndex(matches[0]); pump() + disabled = not button.isEnabled() + QTest.mouseClick(button, Qt.MouseButton.LeftButton); pump() + check(f'{bad_id} refuses opening without replacing valid B view', disabled and state() == loaded_b, + {'status': screen._history._status.text(), 'view': state()}) + check('unavailable-row inspection leaves all saved bytes unchanged', snapshot(ROOT / 'fixtures') == before_refusals) + # Deliberate private fixture rename simulates a disappearing manifest + # after catalog selection. Keep the exact bytes, never delete them. + missing_id = 'selected-before-missing' + selected = [i for i in range(combo.count()) if getattr(combo.itemData(i), 'job_id', None) == missing_id] + assert len(selected) == 1 + combo.setCurrentIndex(selected[0]); pump() + assert button.isEnabled() + manifest = b / 'processing/jobs' / missing_id / 'job_manifest.json' + held = manifest.with_name('job_manifest.receiver-held.json') + assert not held.exists() + manifest.rename(held) + mutated_fixture = snapshot(ROOT / 'fixtures') + QTest.mouseClick(button, Qt.MouseButton.LeftButton); pump() + check('Open revalidates cached row when manifest disappears', + state() == loaded_b and 'Could not open' in screen._history._status.text(), + screen._history._status.text()) + check('failed Open preserves every persisted byte after controlled fixture rename', snapshot(ROOT / 'fixtures') == mutated_fixture) + else: + check('baseline reproduces stale A view after switching to B', not cleared and str(job_a) in switched['inspector'], switched) + + screen.set_package(str(a)); pump() + qc_index = screen._command.findData('qc') + assert qc_index >= 0 + screen._command.setCurrentIndex(qc_index) + late_id = f'late-{mode}-actual-qc' + assert not (a / 'processing/jobs' / late_id).exists() + + def held_real_run(package, params, **kwargs): + try: + actual_params = dataclasses.replace(params, overwrite_job_id=late_id) + result = real_run(package, actual_params, **kwargs) + holder['result'] = result + ready.set() + if not release.wait(30): + raise TimeoutError('Receiving completion gate not released') + return result + except BaseException as exc: + holder['error'] = repr(exc) + ready.set() + raise + + capture_analysis.run = held_real_run + screen._btn_run.click() + until(ready.is_set, 'Actual native QC never reached completion hold') + assert 'error' not in holder, holder.get('error') + actual = holder['result'] + check('actual QThread QC result exists before deferred delivery', + actual.status in ('completed', 'completed_with_warnings') and (actual.job_dir / 'job_manifest.json').is_file(), + {'job_dir': str(actual.job_dir), 'status': actual.status}) + persisted_at_hold = snapshot(ROOT / 'fixtures') + screen.set_package(str(b)); pump() + receipt['screens']['late_before_delivery'] = state() + release.set() + until(lambda: screen._thread is None, 'Native worker completion did not finish its Qt lifecycle') + late_state = state() + receipt['screens']['late_after_delivery'] = late_state + if mode == 'candidate': + check('prior-package real completion cannot bind current B gallery or inspector', + late_state['package'] == str(b) and late_state['last_job_dir'] == '' + and late_state['inspector'] == 'No job loaded' and late_state['png_count'] == 0 + and late_state['linked_plot_count'] == 0 and not late_state['open_folder_enabled'], late_state) + check('late result remains discoverable by explicit package selection', + 'Result saved for the previous package' in screen._log.toPlainText(), screen._log.toPlainText()) + open_history('retained-prior') + check('current B result reopens after native thread completion', state()['last_job_dir'] == str(job_b), state()) + screen.set_package(str(a)); pump() + open_history(late_id) + check('returning to A explicitly opens its genuine late saved QC', + state()['last_job_dir'] == str(actual.job_dir) and str(actual.job_dir) in state()['inspector'], state()) + else: + check('baseline reproduces foreign binding after late real completion', + late_state['package'] == str(b) and late_state['last_job_dir'] == str(actual.job_dir) + and str(actual.job_dir) in late_state['inspector'], late_state) + check('delivery and reopening perform no persisted writes', snapshot(ROOT / 'fixtures') == persisted_at_hold) + raw_after = {key: val for key, val in snapshot(ROOT / 'fixtures').items() if '/processing/' not in key} + check('all captured raw package bytes remain unchanged', raw_after == raw_before) + check('no Qt error dialogs or worker failures occurred', not receipt['dialog_errors'], receipt['dialog_errors']) + screenshot = ROOT / 'evidence' / f'{mode}-qt.png' + assert screen.grab().save(str(screenshot)) + receipt['screenshot'] = {'path': str(screenshot), 'sha256': digest(screenshot)} + receipt['result'] = 'expected baseline defects reproduced' if mode == 'baseline' else 'candidate independent receiving passed' + code = 0 + except BaseException: + receipt['result'] = 'receiving failure' + receipt['traceback'] = traceback.format_exc() + print(receipt['traceback'], flush=True) + code = 1 + finally: + release.set() + capture_analysis.run = real_run + if screen._thread is not None: + try: + until(lambda: screen._thread is None, 'Worker did not settle during receiving close', 10) + except BaseException: + receipt['close_error'] = traceback.format_exc() + receipt['harness_sha256'] = digest(Path(__file__)) + receipt['free_bytes_after'] = shutil.disk_usage(ROOT).free + save_json(ROOT / 'evidence' / f'{mode}-receipt.json', receipt) + screen.close() + app.processEvents() + print(json.dumps({'mode': mode, 'result': receipt['result'], 'checks': len(receipt['checks']), 'free_bytes': receipt['free_bytes_after']}), flush=True) + return code + + +def main() -> int: + parser = argparse.ArgumentParser() + parser.add_argument('mode', choices=('prepare', 'baseline', 'candidate')) + parser.add_argument('--source', type=Path, default=DEFAULT_SOURCE) + args = parser.parse_args() + bootstrap(args.source.resolve()) + if args.mode == 'prepare': + prepare(args.source.resolve()) + return 0 + return receive(args.mode, args.source.resolve()) + + +if __name__ == '__main__': + raise SystemExit(main()) diff --git a/docs/evidence/analysis-history-401c5d17da79/independent/methods/receive_history_native.py b/docs/evidence/analysis-history-401c5d17da79/independent/methods/receive_history_native.py new file mode 100644 index 00000000..72eae6b5 --- /dev/null +++ b/docs/evidence/analysis-history-401c5d17da79/independent/methods/receive_history_native.py @@ -0,0 +1,239 @@ +# SPDX-License-Identifier: GPL-3.0-only +"""Complete independent receiving in the real QApplication event loop. + +Actions advance from QTimer callbacks; no manual processEvents/qWait pumping, +no retained worker/thread references, no production source or worker edits. +""" +from __future__ import annotations +import dataclasses +import importlib.util +import json +from pathlib import Path +import sys +import threading +import time +import traceback + +ROOT = Path('/dev/shm/hamon-401c5d17da79-capturesuite-receiving') +FIXTURES = ROOT / 'fixtures-native' +spec = importlib.util.spec_from_file_location('receiving_helpers', ROOT / 'methods/receive_history.py') +helpers = importlib.util.module_from_spec(spec) +spec.loader.exec_module(helpers) +helpers.bootstrap(helpers.DEFAULT_SOURCE) +from PySide6 import __version__ as pyside_version +from PySide6.QtCore import QTimer +from PySide6.QtWidgets import QApplication, QComboBox, QLabel, QMessageBox, QPushButton +from capture_desktop.state import CaptureState +import capture_analysis + +Screen = helpers.load_screen('candidate', helpers.DEFAULT_SOURCE) +app = QApplication([]) +screen = Screen(CaptureState()) +screen.resize(1200, 900) +screen.show() +a, b = (FIXTURES / f'package-{letter}.mmsession' for letter in ('a','b')) +job_a, job_b = (p / 'processing/jobs/retained-prior' for p in (a,b)) +release, ready = threading.Event(), threading.Event() +holder = {} +real_run = capture_analysis.run +started = time.monotonic() +settling_failure = False +before = helpers.snapshot(FIXTURES) +raw_before = {key:value for key,value in before.items() if '/processing/' not in key} +receipt = {'schema':'capturesuite.history.independent-native-receiving.v1', + 'candidate':json.loads((ROOT / 'pins/candidate-inputs.json').read_text()), + 'runtime':{'python':sys.version,'pyside6':pyside_version,'qt_platform':app.platformName()}, + 'loop':'QApplication.exec; state-machine actions via QTimer; no manual processEvents, QTest.qWait, source edits, worker replacement, or retained worker/thread reference', + 'method_sha256':helpers.digest(Path(__file__)), 'helper_sha256':helpers.digest(ROOT / 'methods/receive_history.py'), + 'fixture_root':str(FIXTURES),'checks':[],'screens':{},'errors':[], 'source_imports':{}} +for module in (capture_analysis, sys.modules['capture_analysis.jobs'],sys.modules['capture_desktop.screen_analysis'],sys.modules['capture_desktop.widgets_analysis_plots']): + receipt['source_imports'][module.__name__] = {'path':module.__file__,'sha256':helpers.digest(Path(module.__file__))} + + +def persist(): + helpers.save_json(ROOT / 'evidence/native-candidate-receipt.json', receipt) + + +def check(name, condition, evidence=None): + receipt['checks'].append({'name':name,'pass':bool(condition),'evidence':evidence}) + persist() + print(name, bool(condition), flush=True) + if not condition: + raise AssertionError(name) + + +def view(): + tabs = screen._gallery._tabs + png_count = 0 + for index in range(1,tabs.count()): + for label in tabs.widget(index).findChildren(QLabel): + pixmap = label.pixmap() + if pixmap is not None and not pixmap.isNull(): png_count += 1 + return {'package':screen._package,'last_job_dir':screen._last_job_dir, + 'inspector':screen._inspector._meta.text(), + 'tabs':[tabs.tabText(i) for i in range(tabs.count())], + 'png_count':png_count,'linked_plot_count':len(screen._gallery._sync._linked), + 'sync_title':screen._gallery._sync._title.text(), + 'history_loaded_job_id':screen._history.loaded_job_id, + 'open_folder_enabled':screen._btn_open_job.isEnabled(), + 'open_report_enabled':screen._btn_open_report.isEnabled()} + + +def select(job_id): + combo = screen.findChild(QComboBox,'analysisHistoryJob') + matches = [i for i in range(combo.count()) if getattr(combo.itemData(i),'job_id',None) == job_id] + assert len(matches) == 1, (job_id,matches) + combo.setCurrentIndex(matches[0]) + return screen.findChild(QPushButton,'analysisHistoryOpen') + + +def open_saved(job_id): + button = select(job_id) + assert button.isEnabled(), job_id + button.click() + + +def capture(name): + path = ROOT / 'evidence' / name + assert screen.grab().save(str(path)) + return {'path':str(path),'sha256':helpers.digest(path)} + + +def held_actual_run(package, params, **kwargs): + try: + actual = real_run(package,dataclasses.replace(params,overwrite_job_id='late-native-candidate-qc'),**kwargs) + holder['result'] = actual + ready.set() + if not release.wait(30): raise TimeoutError('Receiving gate was not released') + return actual + except BaseException as exc: + holder['error'] = repr(exc) + ready.set() + raise + + +def flow(): + screen.set_package(str(a)); yield + open_saved('retained-prior'); yield + current = view() + check('fresh screen reopens real prior A result into native gallery and inspector', + current['last_job_dir']==str(job_a) and str(job_a) in current['inspector'] + and current['png_count']==2 and current['linked_plot_count']==2 + and 'receiving-a-401c5d17da79' in current['sync_title'],current) + receipt['screens']['reopened_a']=capture('native-reopened-a.png') + screen.set_package(str(b)); yield + current = view() + check('package switch clears prior result and both launch targets', + current['last_job_dir']=='' and current['inspector']=='No job loaded' + and current['png_count']==0 and current['linked_plot_count']==0 + and not current['open_folder_enabled'] and not current['open_report_enabled'],current) + open_saved('retained-prior'); yield + loaded_b = view() + check('same basename in B resolves B figures and metadata only', + loaded_b['last_job_dir']==str(job_b) and str(job_b) in loaded_b['inspector'] + and loaded_b['png_count']==2 and loaded_b['linked_plot_count']==2 + and 'receiving-b-401c5d17da79' in loaded_b['sync_title'],loaded_b) + receipt['screens']['reopened_b']=capture('native-reopened-b.png') + before_refusals=helpers.snapshot(FIXTURES) + for bad_id in ('malformed-manifest','missing-manifest','foreign-session','foreign-directory'): + button=select(bad_id); yield + disabled=not button.isEnabled() + button.click(); yield + check(f'{bad_id} is visibly unavailable and refuses Open without replacing B', + disabled and view()==loaded_b, + {'status':screen._history._status.text(),'view':view()}) + check('unavailable-row actions leave every saved byte unchanged',helpers.snapshot(FIXTURES)==before_refusals) + button=select('selected-before-missing'); yield + assert button.isEnabled() + manifest=b/'processing/jobs/selected-before-missing/job_manifest.json' + held=manifest.with_name('job_manifest.receiver-held.json') + assert not held.exists() + manifest.rename(held) + at_missing=helpers.snapshot(FIXTURES) + button.click(); yield + check('Open revalidates a cached row after its manifest disappears', + view()==loaded_b and 'Could not open' in screen._history._status.text(),screen._history._status.text()) + check('refused cached Open preserves all bytes after the controlled rename',helpers.snapshot(FIXTURES)==at_missing) + screen.set_package(str(a)); yield + screen._command.setCurrentIndex(screen._command.findData('qc')) + assert not (a/'processing/jobs/late-native-candidate-qc').exists() + capture_analysis.run=held_actual_run + screen._btn_run.click() + while not ready.is_set(): yield + assert 'error' not in holder,holder.get('error') + actual=holder['result'] + check('real QThread QC completed and persisted before receiving release', + actual.status in ('completed','completed_with_warnings') and (actual.job_dir/'job_manifest.json').is_file(), + {'job_dir':str(actual.job_dir),'status':actual.status}) + at_hold=helpers.snapshot(FIXTURES) + screen.set_package(str(b)); yield + receipt['screens']['before_late_delivery']=view() + release.set() + while screen._thread is not None: yield + current=view() + check('prior-package real completion cannot bind current B gallery or inspector', + current['package']==str(b) and current['last_job_dir']=='' + and current['inspector']=='No job loaded' and current['png_count']==0 + and current['linked_plot_count']==0 and not current['open_folder_enabled'],current) + check('prior-package result is explicitly retained for later inspection', + 'Result saved for the previous package' in screen._log.toPlainText(),screen._log.toPlainText()) + open_saved('retained-prior'); yield + check('current B saved result reopens after actual Qt thread completion',view()['last_job_dir']==str(job_b),view()) + screen.set_package(str(a)); yield + open_saved(actual.job_id); yield + check('returning to A explicitly opens the genuinely completed late QC', + view()['last_job_dir']==str(actual.job_dir) and str(actual.job_dir) in view()['inspector'],view()) + check('late delivery and later reopenings perform no persisted writes',helpers.snapshot(FIXTURES)==at_hold) + raw_after={key:value for key,value in helpers.snapshot(FIXTURES).items() if '/processing/' not in key} + check('all captured raw data remains unchanged',raw_before==raw_after) + check('no Qt error dialog or native worker failure',not receipt['errors'],receipt['errors']) + for rel,pin in receipt['candidate']['inputs'].items(): + assert helpers.digest(helpers.DEFAULT_SOURCE/rel)==pin['sha256'],rel+' changed during receiving' + check('frozen source bytes remained exact throughout native receiving',True) + receipt['screens']['late_qc']=capture('native-late-qc.png') + receipt['fixture_files_after']=helpers.snapshot(FIXTURES) + receipt['source_unchanged']=True + receipt['seconds']=time.monotonic()-started + receipt['pass']=True + receipt['result']='All independent native QApplication receiving checks passed on exact corrected candidate' + persist() + + +iterator=flow() + +def advance(): + global settling_failure + try: + for widget in app.topLevelWidgets(): + if isinstance(widget,QMessageBox) and widget.isVisible(): + receipt['errors'].append(widget.text());widget.accept() + if settling_failure: + if screen._thread is None:app.exit(1) + return + if time.monotonic()-started>35:raise TimeoutError('Native receiving exceeded its bounded deadline') + next(iterator) + except StopIteration: + app.exit(0) + except BaseException: + receipt['errors'].append(traceback.format_exc()) + receipt['pass']=False + receipt['result']='Independent native receiving failed' + release.set() + settling_failure=True + persist() + if screen._thread is None:app.exit(1) + + +timer=QTimer() +timer.setInterval(10) +timer.timeout.connect(advance) +timer.start() +persist() +code=app.exec() +release.set() +capture_analysis.run=real_run +screen.close() +receipt['process_return']=code +persist() +print(json.dumps({'pass':receipt.get('pass'),'checks':len(receipt['checks']),'seconds':receipt.get('seconds'),'code':code}),flush=True) +raise SystemExit(code) diff --git a/docs/evidence/analysis-history-401c5d17da79/independent/methods/receive_qt_eventloop.py b/docs/evidence/analysis-history-401c5d17da79/independent/methods/receive_qt_eventloop.py new file mode 100644 index 00000000..8c4dbe4a --- /dev/null +++ b/docs/evidence/analysis-history-401c5d17da79/independent/methods/receive_qt_eventloop.py @@ -0,0 +1,155 @@ +# SPDX-License-Identifier: GPL-3.0-only +"""One disjoint native QApplication.exec control of actual prior-package completion.""" +from __future__ import annotations +import dataclasses +import importlib.util +import json +from pathlib import Path +import sys +import threading +import time +import traceback + +root = Path('/dev/shm/hamon-401c5d17da79-capturesuite-receiving') +spec = importlib.util.spec_from_file_location('receiving_helpers', root / 'methods/receive_history.py') +helpers = importlib.util.module_from_spec(spec) +spec.loader.exec_module(helpers) +source = helpers.DEFAULT_SOURCE +helpers.bootstrap(source) +from PySide6.QtCore import QTimer +from PySide6.QtWidgets import QApplication, QComboBox, QMessageBox, QPushButton +from capture_desktop.state import CaptureState +import capture_analysis +Screen = helpers.load_screen('candidate', source) +app = QApplication([]) +screen = Screen(CaptureState()) +screen.resize(1200, 900) +screen.show() +a = root / 'fixtures/package-a.mmsession' +b = root / 'fixtures/package-b.mmsession' +ready, release = threading.Event(), threading.Event() +holder = {} +real_run = capture_analysis.run +started = time.monotonic() +phase = 'starting' +receipt = {'schema':'capturesuite.history.native-eventloop-control.v1', + 'candidate':json.loads((root / 'pins/candidate-inputs.json').read_text()), + 'method_sha256':helpers.digest(Path(__file__)), + 'loop':'QApplication.exec with QTimer; no manual processEvents or QTest.qWait', + 'events':[], 'checks':[], 'errors':[]} + + +def persist(): + helpers.save_json(root / 'evidence/eventloop-receipt.json', receipt) + + +def check(label, ok, detail=None): + receipt['checks'].append({'label':label,'pass':bool(ok),'detail':detail}) + persist() + print(label, bool(ok), flush=True) + if not ok: + raise AssertionError(label) + + +def held_run(package, params, **kwargs): + try: + actual = real_run(package, dataclasses.replace(params, overwrite_job_id='late-eventloop-actual-qc'), **kwargs) + holder['result'] = actual + ready.set() + if not release.wait(30): + raise TimeoutError('Receiving completion gate was not released') + return actual + except BaseException as exc: + holder['error'] = repr(exc) + ready.set() + raise + + +def start(): + global phase + try: + screen.set_package(str(a)) + combo = screen.findChild(QComboBox, 'analysisHistoryJob') + matches = [i for i in range(combo.count()) if getattr(combo.itemData(i),'job_id',None) == 'retained-prior'] + assert len(matches) == 1 + combo.setCurrentIndex(matches[0]) + screen.findChild(QPushButton,'analysisHistoryOpen').click() + assert screen._last_job_dir == str(a / 'processing/jobs/retained-prior') + assert len(screen._gallery._sync._linked) == 2 + screen.set_package(str(b)) + screen.set_package(str(a)) + assert not (a / 'processing/jobs/late-eventloop-actual-qc').exists() + screen._command.setCurrentIndex(screen._command.findData('qc')) + capture_analysis.run = held_run + screen._btn_run.click() + phase = 'awaiting_result' + receipt['events'].append('actual QThread started in native application loop') + persist() + except BaseException: + fail() + + +def fail(): + global phase + receipt['errors'].append(traceback.format_exc()) + receipt['pass'] = False + release.set() + phase = 'failed_settling' + persist() + if screen._thread is None: + app.exit(1) + + +def tick(): + global phase + try: + for widget in app.topLevelWidgets(): + if isinstance(widget, QMessageBox) and widget.isVisible(): + receipt['errors'].append(widget.text()) + widget.accept() + if phase == 'awaiting_result' and ready.is_set(): + assert 'error' not in holder, holder.get('error') + actual = holder['result'] + check('real QC was persisted before release', (actual.job_dir / 'job_manifest.json').is_file(), + {'job_dir':str(actual.job_dir),'status':actual.status}) + holder['at_hold'] = helpers.snapshot(root / 'fixtures') + screen.set_package(str(b)) + check('selected B is unbound before A completion', screen._package == str(b) and screen._last_job_dir == '' and screen._inspector._meta.text() == 'No job loaded') + phase = 'awaiting_thread_finish' + receipt['events'].append('selected B, released real A completion') + persist() + release.set() + elif phase == 'awaiting_thread_finish' and screen._thread is None: + check('native event loop settles without binding previous-package result', + screen._package == str(b) and screen._last_job_dir == '' and screen._inspector._meta.text() == 'No job loaded', + {'package':screen._package,'last_job_dir':screen._last_job_dir,'inspector':screen._inspector._meta.text()}) + check('completion preserves all bytes after actual job persistence', helpers.snapshot(root / 'fixtures') == holder['at_hold']) + check('no native error dialogs', not receipt['errors'], receipt['errors']) + receipt['seconds'] = time.monotonic() - started + receipt['pass'] = True + receipt['events'].append('native event loop accepted exact completion boundary') + persist() + phase = 'done' + app.exit(0) + elif phase == 'failed_settling' and screen._thread is None: + app.exit(1) + elif time.monotonic() - started > 35 and phase not in ('done', 'failed_settling'): + raise TimeoutError('Native event-loop control exceeded its bounded completion deadline') + except BaseException: + fail() + + +timer = QTimer() +timer.setInterval(10) +timer.timeout.connect(tick) +timer.start() +QTimer.singleShot(0, start) +persist() +code = app.exec() +capture_analysis.run = real_run +release.set() +screen.close() +receipt['process_return'] = code +persist() +print(json.dumps({'pass':receipt.get('pass'),'checks':len(receipt['checks']),'seconds':receipt.get('seconds'),'code':code}),flush=True) +raise SystemExit(code) diff --git a/docs/evidence/analysis-history-401c5d17da79/independent/native-candidate-receipt.json b/docs/evidence/analysis-history-401c5d17da79/independent/native-candidate-receipt.json new file mode 100644 index 00000000..7348a89e --- /dev/null +++ b/docs/evidence/analysis-history-401c5d17da79/independent/native-candidate-receipt.json @@ -0,0 +1,653 @@ +{ + "candidate": { + "baseline": "72c15d6b623e217291a824e4e4808a385df896a9", + "commit": "37443f0d4d5ffa684b5423d58501856cadbe0655", + "correction": "Refresh failed retained jobs in the failure slot; successful completion already refreshes there. Restore original thread-finished cleanup, eliminating added filesystem work after releasing worker references. Native worker and signal wiring are unchanged.", + "focused_and_retained_tests": "14 passed in3.21s; no skips", + "inputs": { + "desktop/capture_desktop/analysis_history.py": { + "bytes": 6375, + "sha256": "2e0db8cee59ef268d3c91ea0beac7d761d83a3003862841cc9d7f1782fd3543c" + }, + "desktop/capture_desktop/screen_analysis.py": { + "bytes": 16407, + "sha256": "98a704e31b14497e012fe5618ad47cc8a772bd2d59775826d71a5bdf41533211" + }, + "desktop/capture_desktop/widgets_analysis_history.py": { + "bytes": 8458, + "sha256": "a3b77c87483c1412b50de7ddde1498f6bfd3968002fc3ac3bfa474a2477d9bc4" + }, + "tests/ui/test_analysis_history.py": { + "bytes": 10465, + "sha256": "48175547922125c308fa49bbb84149e3dac8903902e7cc64fa7c15b4ca40eccd" + } + }, + "previous_candidate": "c0b5530c03cce3e42a0430e5411cddf1df716e19", + "runtime": "/workspace/scratch/234cae4aee53/capturesuite-venv/bin/python", + "tree": "3b3184b931a2aaf91beec36c953bff909a77f2f5", + "worker_and_thread_cleanup_ast_identical_to_baseline": true + }, + "checks": [ + { + "evidence": { + "history_loaded_job_id": "retained-prior", + "inspector": "job_id=retained-prior\nstatus=completed\ngap_policy=mask\nplugin_manifest=1.0.0\npath=/dev/shm/hamon-401c5d17da79-capturesuite-receiving/fixtures-native/package-a.mmsession/processing/jobs/retained-prior", + "last_job_dir": "/dev/shm/hamon-401c5d17da79-capturesuite-receiving/fixtures-native/package-a.mmsession/processing/jobs/retained-prior", + "linked_plot_count": 2, + "open_folder_enabled": true, + "open_report_enabled": true, + "package": "/dev/shm/hamon-401c5d17da79-capturesuite-receiving/fixtures-native/package-a.mmsession", + "png_count": 2, + "sync_title": "receiving-a-401c5d17da79 \u00b7 gap_policy=mask", + "tabs": [ + "Sync", + "emg sim.emg.main channel", + "imu sim.imu.upper accel" + ] + }, + "name": "fresh screen reopens real prior A result into native gallery and inspector", + "pass": true + }, + { + "evidence": { + "history_loaded_job_id": "", + "inspector": "No job loaded", + "last_job_dir": "", + "linked_plot_count": 0, + "open_folder_enabled": false, + "open_report_enabled": false, + "package": "/dev/shm/hamon-401c5d17da79-capturesuite-receiving/fixtures-native/package-b.mmsession", + "png_count": 0, + "sync_title": "Sync dashboard", + "tabs": [ + "Sync" + ] + }, + "name": "package switch clears prior result and both launch targets", + "pass": true + }, + { + "evidence": { + "history_loaded_job_id": "retained-prior", + "inspector": "job_id=retained-prior\nstatus=completed\ngap_policy=mask\nplugin_manifest=1.0.0\npath=/dev/shm/hamon-401c5d17da79-capturesuite-receiving/fixtures-native/package-b.mmsession/processing/jobs/retained-prior", + "last_job_dir": "/dev/shm/hamon-401c5d17da79-capturesuite-receiving/fixtures-native/package-b.mmsession/processing/jobs/retained-prior", + "linked_plot_count": 2, + "open_folder_enabled": true, + "open_report_enabled": true, + "package": "/dev/shm/hamon-401c5d17da79-capturesuite-receiving/fixtures-native/package-b.mmsession", + "png_count": 2, + "sync_title": "receiving-b-401c5d17da79 \u00b7 gap_policy=mask", + "tabs": [ + "Sync", + "emg sim.emg.main channel", + "imu sim.imu.upper accel" + ] + }, + "name": "same basename in B resolves B figures and metadata only", + "pass": true + }, + { + "evidence": { + "status": "malformed-manifest: Expecting property name enclosed in double quotes: line 1 column 2 (char 1)", + "view": { + "history_loaded_job_id": "retained-prior", + "inspector": "job_id=retained-prior\nstatus=completed\ngap_policy=mask\nplugin_manifest=1.0.0\npath=/dev/shm/hamon-401c5d17da79-capturesuite-receiving/fixtures-native/package-b.mmsession/processing/jobs/retained-prior", + "last_job_dir": "/dev/shm/hamon-401c5d17da79-capturesuite-receiving/fixtures-native/package-b.mmsession/processing/jobs/retained-prior", + "linked_plot_count": 2, + "open_folder_enabled": true, + "open_report_enabled": true, + "package": "/dev/shm/hamon-401c5d17da79-capturesuite-receiving/fixtures-native/package-b.mmsession", + "png_count": 2, + "sync_title": "receiving-b-401c5d17da79 \u00b7 gap_policy=mask", + "tabs": [ + "Sync", + "emg sim.emg.main channel", + "imu sim.imu.upper accel" + ] + } + }, + "name": "malformed-manifest is visibly unavailable and refuses Open without replacing B", + "pass": true + }, + { + "evidence": { + "status": "missing-manifest: Saved file is unavailable: job_manifest.json", + "view": { + "history_loaded_job_id": "retained-prior", + "inspector": "job_id=retained-prior\nstatus=completed\ngap_policy=mask\nplugin_manifest=1.0.0\npath=/dev/shm/hamon-401c5d17da79-capturesuite-receiving/fixtures-native/package-b.mmsession/processing/jobs/retained-prior", + "last_job_dir": "/dev/shm/hamon-401c5d17da79-capturesuite-receiving/fixtures-native/package-b.mmsession/processing/jobs/retained-prior", + "linked_plot_count": 2, + "open_folder_enabled": true, + "open_report_enabled": true, + "package": "/dev/shm/hamon-401c5d17da79-capturesuite-receiving/fixtures-native/package-b.mmsession", + "png_count": 2, + "sync_title": "receiving-b-401c5d17da79 \u00b7 gap_policy=mask", + "tabs": [ + "Sync", + "emg sim.emg.main channel", + "imu sim.imu.upper accel" + ] + } + }, + "name": "missing-manifest is visibly unavailable and refuses Open without replacing B", + "pass": true + }, + { + "evidence": { + "status": "foreign-session: Saved job belongs to a different session.", + "view": { + "history_loaded_job_id": "retained-prior", + "inspector": "job_id=retained-prior\nstatus=completed\ngap_policy=mask\nplugin_manifest=1.0.0\npath=/dev/shm/hamon-401c5d17da79-capturesuite-receiving/fixtures-native/package-b.mmsession/processing/jobs/retained-prior", + "last_job_dir": "/dev/shm/hamon-401c5d17da79-capturesuite-receiving/fixtures-native/package-b.mmsession/processing/jobs/retained-prior", + "linked_plot_count": 2, + "open_folder_enabled": true, + "open_report_enabled": true, + "package": "/dev/shm/hamon-401c5d17da79-capturesuite-receiving/fixtures-native/package-b.mmsession", + "png_count": 2, + "sync_title": "receiving-b-401c5d17da79 \u00b7 gap_policy=mask", + "tabs": [ + "Sync", + "emg sim.emg.main channel", + "imu sim.imu.upper accel" + ] + } + }, + "name": "foreign-session is visibly unavailable and refuses Open without replacing B", + "pass": true + }, + { + "evidence": { + "status": "foreign-directory: Saved analysis paths must stay inside this package: /dev/shm/hamon-401c5d17da79-capturesuite-receiving/fixtures-native/package-b.mmsession/processing/jobs/foreign-directory", + "view": { + "history_loaded_job_id": "retained-prior", + "inspector": "job_id=retained-prior\nstatus=completed\ngap_policy=mask\nplugin_manifest=1.0.0\npath=/dev/shm/hamon-401c5d17da79-capturesuite-receiving/fixtures-native/package-b.mmsession/processing/jobs/retained-prior", + "last_job_dir": "/dev/shm/hamon-401c5d17da79-capturesuite-receiving/fixtures-native/package-b.mmsession/processing/jobs/retained-prior", + "linked_plot_count": 2, + "open_folder_enabled": true, + "open_report_enabled": true, + "package": "/dev/shm/hamon-401c5d17da79-capturesuite-receiving/fixtures-native/package-b.mmsession", + "png_count": 2, + "sync_title": "receiving-b-401c5d17da79 \u00b7 gap_policy=mask", + "tabs": [ + "Sync", + "emg sim.emg.main channel", + "imu sim.imu.upper accel" + ] + } + }, + "name": "foreign-directory is visibly unavailable and refuses Open without replacing B", + "pass": true + }, + { + "evidence": null, + "name": "unavailable-row actions leave every saved byte unchanged", + "pass": true + }, + { + "evidence": "Could not open selected-before-missing: Saved file is unavailable: job_manifest.json. Refresh the job list.", + "name": "Open revalidates a cached row after its manifest disappears", + "pass": true + }, + { + "evidence": null, + "name": "refused cached Open preserves all bytes after the controlled rename", + "pass": true + }, + { + "evidence": { + "job_dir": "/dev/shm/hamon-401c5d17da79-capturesuite-receiving/fixtures-native/package-a.mmsession/processing/jobs/late-native-candidate-qc", + "status": "completed" + }, + "name": "real QThread QC completed and persisted before receiving release", + "pass": true + }, + { + "evidence": { + "history_loaded_job_id": "", + "inspector": "No job loaded", + "last_job_dir": "", + "linked_plot_count": 0, + "open_folder_enabled": false, + "open_report_enabled": false, + "package": "/dev/shm/hamon-401c5d17da79-capturesuite-receiving/fixtures-native/package-b.mmsession", + "png_count": 0, + "sync_title": "Sync dashboard", + "tabs": [ + "Sync" + ] + }, + "name": "prior-package real completion cannot bind current B gallery or inspector", + "pass": true + }, + { + "evidence": "Starting qc on /dev/shm/hamon-401c5d17da79-capturesuite-receiving/fixtures-native/package-a.mmsession\nstart (0%)\nqc (15%)\nwrite_qc (25%)\nmanifest (90%)\ndone (100%)\nDone status=completed job_id=late-native-candidate-qc\ndir=/dev/shm/hamon-401c5d17da79-capturesuite-receiving/fixtures-native/package-a.mmsession/processing/jobs/late-native-candidate-qc\nResult saved for the previous package; select that package to inspect it.", + "name": "prior-package result is explicitly retained for later inspection", + "pass": true + }, + { + "evidence": { + "history_loaded_job_id": "retained-prior", + "inspector": "job_id=retained-prior\nstatus=completed\ngap_policy=mask\nplugin_manifest=1.0.0\npath=/dev/shm/hamon-401c5d17da79-capturesuite-receiving/fixtures-native/package-b.mmsession/processing/jobs/retained-prior", + "last_job_dir": "/dev/shm/hamon-401c5d17da79-capturesuite-receiving/fixtures-native/package-b.mmsession/processing/jobs/retained-prior", + "linked_plot_count": 2, + "open_folder_enabled": true, + "open_report_enabled": true, + "package": "/dev/shm/hamon-401c5d17da79-capturesuite-receiving/fixtures-native/package-b.mmsession", + "png_count": 2, + "sync_title": "receiving-b-401c5d17da79 \u00b7 gap_policy=mask", + "tabs": [ + "Sync", + "emg sim.emg.main channel", + "imu sim.imu.upper accel" + ] + }, + "name": "current B saved result reopens after actual Qt thread completion", + "pass": true + }, + { + "evidence": { + "history_loaded_job_id": "late-native-candidate-qc", + "inspector": "job_id=late-native-candidate-qc\nstatus=completed\ngap_policy=mask\nplugin_manifest=1.0.0\npath=/dev/shm/hamon-401c5d17da79-capturesuite-receiving/fixtures-native/package-a.mmsession/processing/jobs/late-native-candidate-qc", + "last_job_dir": "/dev/shm/hamon-401c5d17da79-capturesuite-receiving/fixtures-native/package-a.mmsession/processing/jobs/late-native-candidate-qc", + "linked_plot_count": 0, + "open_folder_enabled": true, + "open_report_enabled": true, + "package": "/dev/shm/hamon-401c5d17da79-capturesuite-receiving/fixtures-native/package-a.mmsession", + "png_count": 0, + "sync_title": "Sync dashboard", + "tabs": [ + "Sync" + ] + }, + "name": "returning to A explicitly opens the genuinely completed late QC", + "pass": true + }, + { + "evidence": null, + "name": "late delivery and later reopenings perform no persisted writes", + "pass": true + }, + { + "evidence": null, + "name": "all captured raw data remains unchanged", + "pass": true + }, + { + "evidence": [], + "name": "no Qt error dialog or native worker failure", + "pass": true + }, + { + "evidence": null, + "name": "frozen source bytes remained exact throughout native receiving", + "pass": true + } + ], + "errors": [], + "fixture_files_after": { + "package-a.mmsession/events/annotations.json": { + "bytes": 3, + "sha256": "37517e5f3dc66819f61f5a7bb8ace1921282415f10551d2defa5c3eb0985b570" + }, + "package-a.mmsession/events/checkpoints.json": { + "bytes": 3, + "sha256": "37517e5f3dc66819f61f5a7bb8ace1921282415f10551d2defa5c3eb0985b570" + }, + "package-a.mmsession/events/sync_anchors.json": { + "bytes": 3, + "sha256": "37517e5f3dc66819f61f5a7bb8ace1921282415f10551d2defa5c3eb0985b570" + }, + "package-a.mmsession/integrity.json": { + "bytes": 225, + "sha256": "2fb4194b22d4b1c373f25f9ecab51d0c80e14f42a52f53293fd727ce5418f140" + }, + "package-a.mmsession/manifest.json": { + "bytes": 250, + "sha256": "6cc54886cc63fa1263a4077fec322454fdfa133a408836a75451fd77eb7c5243" + }, + "package-a.mmsession/processing/jobs/late-baseline-actual-qc/job_manifest.json": { + "bytes": 2400, + "sha256": "bbb88191cb522d3314139b6ebcb4cd2e6b8aa6c6b7df362d0653a0a75dcba7bc" + }, + "package-a.mmsession/processing/jobs/late-baseline-actual-qc/logs/job.log": { + "bytes": 187, + "sha256": "59f307f1af8f7e20fe908e17afdf3047f6d7eda3d04d2d7e5153f258b6377d37" + }, + "package-a.mmsession/processing/jobs/late-baseline-actual-qc/params.json": { + "bytes": 260, + "sha256": "88f55fe8dddb0794c98f693dd21fdd7764a6bac45203e11ba52eab3ebaa40fc3" + }, + "package-a.mmsession/processing/jobs/late-baseline-actual-qc/reports/qc.html": { + "bytes": 1629, + "sha256": "db815562d270dc133bce019f0c0791bea4e9af52fc62ce7107a41ea6a8485d20" + }, + "package-a.mmsession/processing/jobs/late-baseline-actual-qc/reports/qc.json": { + "bytes": 1296, + "sha256": "2a1addc8accb001643f81a4b1061458f8fa27de6ffcc157fbed5ddb837c9cf27" + }, + "package-a.mmsession/processing/jobs/late-candidate-actual-qc/job_manifest.json": { + "bytes": 2401, + "sha256": "d63428766698ba71d56f9797340cc2e4f870cded0e04708b98ee991200e5d88e" + }, + "package-a.mmsession/processing/jobs/late-candidate-actual-qc/logs/job.log": { + "bytes": 188, + "sha256": "c2b223c3686c245380c6b3788d45deb8f4a56ca9d420039af2ff598f6eb66cc1" + }, + "package-a.mmsession/processing/jobs/late-candidate-actual-qc/params.json": { + "bytes": 261, + "sha256": "9aad1ac26d07fdbf51e882ad70c97ae15942b3057755083b0a8b063506d23fe8" + }, + "package-a.mmsession/processing/jobs/late-candidate-actual-qc/reports/qc.html": { + "bytes": 1629, + "sha256": "db815562d270dc133bce019f0c0791bea4e9af52fc62ce7107a41ea6a8485d20" + }, + "package-a.mmsession/processing/jobs/late-candidate-actual-qc/reports/qc.json": { + "bytes": 1296, + "sha256": "2a1addc8accb001643f81a4b1061458f8fa27de6ffcc157fbed5ddb837c9cf27" + }, + "package-a.mmsession/processing/jobs/late-native-candidate-qc/job_manifest.json": { + "bytes": 2408, + "sha256": "995796fd6b5f52e89ea25a0c45fd769b6352b5f2b1d8984b250971c691ad8658" + }, + "package-a.mmsession/processing/jobs/late-native-candidate-qc/logs/job.log": { + "bytes": 195, + "sha256": "b9c0d4a5e6fc748c0a4b60187926f7e9885a2a386a7ed8e85c37a261e053a87d" + }, + "package-a.mmsession/processing/jobs/late-native-candidate-qc/params.json": { + "bytes": 261, + "sha256": "e09345ba9ebd7b6f59a9b70cff3af7406c1424237cb5e27a05a80f755b270cb9" + }, + "package-a.mmsession/processing/jobs/late-native-candidate-qc/reports/qc.html": { + "bytes": 1636, + "sha256": "2917196a7446847355f7443ab5bde8be96dbc71e2b48927f4e60fe064affce6e" + }, + "package-a.mmsession/processing/jobs/late-native-candidate-qc/reports/qc.json": { + "bytes": 1303, + "sha256": "2d98f837e78a3866402a3f4f9dc765a262168f36d8fe8b2235e02ee17efd3551" + }, + "package-a.mmsession/processing/jobs/retained-prior/features/_schema.json": { + "bytes": 2880, + "sha256": "c80f7d1e05378bf2399098e9887fc463edda22e366236eab3e9b1b0526d1f0f0" + }, + "package-a.mmsession/processing/jobs/retained-prior/features/emg/sim.emg.main/windows.csv": { + "bytes": 501, + "sha256": "0c9b8016e1295976eb10eabdb913efff752cf9936bf4a7cab1d3107a85ca97ff" + }, + "package-a.mmsession/processing/jobs/retained-prior/features/emg/sim.emg.main/windows.parquet": { + "bytes": 7411, + "sha256": "c5d6d1727acd151ca0b1430eecb0dd0491fe2863a9f7c163d7524bfed584e60f" + }, + "package-a.mmsession/processing/jobs/retained-prior/features/imu/sim.imu.upper/windows.csv": { + "bytes": 628, + "sha256": "62212faf4179e9050c4d7a2e3530a461c70d0e56b227138e31b0c273bb21a277" + }, + "package-a.mmsession/processing/jobs/retained-prior/features/imu/sim.imu.upper/windows.parquet": { + "bytes": 7645, + "sha256": "ff4ca0fbfed45e13e95f73d03d8ba56ce0f8305868012ecb5101df277a449ba9" + }, + "package-a.mmsession/processing/jobs/retained-prior/figures/emg_sim.emg.main_channels.png": { + "bytes": 91869, + "sha256": "4c7a4aee76c4895cf99e38874de271e83a52c0e7389093c14a93344e9dc43853" + }, + "package-a.mmsession/processing/jobs/retained-prior/figures/imu_sim.imu.upper_accel.png": { + "bytes": 24298, + "sha256": "8cc603bf604d8925ba13be2c77e0bd8d8f8efbce9529e7d459a449fd61e6a8a4" + }, + "package-a.mmsession/processing/jobs/retained-prior/figures/sync_dashboard.png": { + "bytes": 37253, + "sha256": "bda125c256b17dbd688ec825c2a5b9b8542f346ce95209faf15efadad5c78d48" + }, + "package-a.mmsession/processing/jobs/retained-prior/figures/sync_dashboard_series.json": { + "bytes": 1963, + "sha256": "ba1181c30b0a3ab1b26b716e56bf0787f2e67aa4178cd511f0106486d04aa8e6" + }, + "package-a.mmsession/processing/jobs/retained-prior/job_manifest.json": { + "bytes": 4508, + "sha256": "21471f1ee0cae441202b4b704c6cd1359558ac1bf27f077668508eb1368ae6e7" + }, + "package-a.mmsession/processing/jobs/retained-prior/logs/job.log": { + "bytes": 179, + "sha256": "3cf99c71a0e4e3046b791ad2c04e388adfe452959b315d8dd5df6d278a5aaf63" + }, + "package-a.mmsession/processing/jobs/retained-prior/params.json": { + "bytes": 252, + "sha256": "9c0e1ab18949727f29352f1a602ae65d74db48f8453a49faa72fbc95c518b35b" + }, + "package-a.mmsession/processing/jobs/retained-prior/reports/qc.html": { + "bytes": 1629, + "sha256": "db815562d270dc133bce019f0c0791bea4e9af52fc62ce7107a41ea6a8485d20" + }, + "package-a.mmsession/processing/jobs/retained-prior/reports/qc.json": { + "bytes": 1296, + "sha256": "2a1addc8accb001643f81a4b1061458f8fa27de6ffcc157fbed5ddb837c9cf27" + }, + "package-a.mmsession/sources/sim.emg.main/health/gaps.jsonl": { + "bytes": 0, + "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "package-a.mmsession/sources/sim.emg.main/source.json": { + "bytes": 112, + "sha256": "4e7626e51bfb804c27f83bf98ee186a47ec9f36fec0cbd7863ea8ecb1ecfbd10" + }, + "package-a.mmsession/sources/sim.emg.main/streams/sim.emg.main.batch/segments/000000.mcap": { + "bytes": 1095, + "sha256": "6f3b9bd4ce01238f122649a1139a290ea6193893938a95f3ac61dd61a447d997" + }, + "package-a.mmsession/sources/sim.emg.main/streams/sim.emg.main.batch/stream.json": { + "bytes": 224, + "sha256": "5307697f957309eaca816fa0e20c4799c900e2598a8acf66a59928aa83b305b2" + }, + "package-a.mmsession/sources/sim.imu.upper/source.json": { + "bytes": 118, + "sha256": "a6198f509edc557c1e1d8583a767a540962977751c80a1b6491e3d594b60c7a8" + }, + "package-a.mmsession/sources/sim.imu.upper/streams/sim.imu.upper.frames/segments/000000.mcap": { + "bytes": 1678, + "sha256": "c477a0e0865086fbb4154c977def4d93ea5fb38cc098a4862c45b21b966014c9" + }, + "package-a.mmsession/sources/sim.imu.upper/streams/sim.imu.upper.frames/stream.json": { + "bytes": 219, + "sha256": "ec39026bed1b833d4decb0ef7b0efb94c5557a5647bc50addc060bef3a30d50d" + }, + "package-b.mmsession/events/annotations.json": { + "bytes": 3, + "sha256": "37517e5f3dc66819f61f5a7bb8ace1921282415f10551d2defa5c3eb0985b570" + }, + "package-b.mmsession/events/checkpoints.json": { + "bytes": 3, + "sha256": "37517e5f3dc66819f61f5a7bb8ace1921282415f10551d2defa5c3eb0985b570" + }, + "package-b.mmsession/events/sync_anchors.json": { + "bytes": 3, + "sha256": "37517e5f3dc66819f61f5a7bb8ace1921282415f10551d2defa5c3eb0985b570" + }, + "package-b.mmsession/integrity.json": { + "bytes": 225, + "sha256": "2fb4194b22d4b1c373f25f9ecab51d0c80e14f42a52f53293fd727ce5418f140" + }, + "package-b.mmsession/manifest.json": { + "bytes": 250, + "sha256": "26ea1e6f375028575b0c72477dddff58248a6ab0f1d63a91c797c9c5d44c2af8" + }, + "package-b.mmsession/processing/jobs/foreign-directory": { + "symlink": "/dev/shm/hamon-401c5d17da79-capturesuite-receiving/fixtures/package-a.mmsession/processing/jobs/retained-prior" + }, + "package-b.mmsession/processing/jobs/foreign-session/job_manifest.json": { + "bytes": 4509, + "sha256": "95066d530c9a56380fd58679dae6680d6e3f678064405438c5985e37526aff7a" + }, + "package-b.mmsession/processing/jobs/malformed-manifest/job_manifest.json": { + "bytes": 9, + "sha256": "69cb18c1151284aa03aa4e6840be1940f366267b30a7e9a64330cd76c68d8bb4" + }, + "package-b.mmsession/processing/jobs/missing-manifest/params.json": { + "bytes": 3, + "sha256": "ca3d163bab055381827226140568f3bef7eaac187cebd76878e0b63e9e442356" + }, + "package-b.mmsession/processing/jobs/retained-prior/features/_schema.json": { + "bytes": 2880, + "sha256": "c80f7d1e05378bf2399098e9887fc463edda22e366236eab3e9b1b0526d1f0f0" + }, + "package-b.mmsession/processing/jobs/retained-prior/features/emg/sim.emg.main/windows.csv": { + "bytes": 504, + "sha256": "d7244bae8dab4e4e8ef00cf72cf387343720e31a25499c3f4741741209d1e9ad" + }, + "package-b.mmsession/processing/jobs/retained-prior/features/emg/sim.emg.main/windows.parquet": { + "bytes": 7411, + "sha256": "60858ced982730b51829ae8080bd4217f9289373b65b501cc28411fdd1d83af0" + }, + "package-b.mmsession/processing/jobs/retained-prior/features/imu/sim.imu.upper/windows.csv": { + "bytes": 628, + "sha256": "62212faf4179e9050c4d7a2e3530a461c70d0e56b227138e31b0c273bb21a277" + }, + "package-b.mmsession/processing/jobs/retained-prior/features/imu/sim.imu.upper/windows.parquet": { + "bytes": 7645, + "sha256": "ff4ca0fbfed45e13e95f73d03d8ba56ce0f8305868012ecb5101df277a449ba9" + }, + "package-b.mmsession/processing/jobs/retained-prior/figures/emg_sim.emg.main_channels.png": { + "bytes": 93063, + "sha256": "87a315c7e23f334c9c8065cdab60ca26b8af8b965bd0ebaf33645864d0048124" + }, + "package-b.mmsession/processing/jobs/retained-prior/figures/imu_sim.imu.upper_accel.png": { + "bytes": 24298, + "sha256": "8cc603bf604d8925ba13be2c77e0bd8d8f8efbce9529e7d459a449fd61e6a8a4" + }, + "package-b.mmsession/processing/jobs/retained-prior/figures/sync_dashboard.png": { + "bytes": 37408, + "sha256": "07ebc1ff60a592f2086dcdfe63652666946329dbadf29dece5b6c84f87dd6082" + }, + "package-b.mmsession/processing/jobs/retained-prior/figures/sync_dashboard_series.json": { + "bytes": 1964, + "sha256": "01cdce9f387ad77ac1ea7632cee3c1d84fc879671cbf46e195c64bf1ec4a8c52" + }, + "package-b.mmsession/processing/jobs/retained-prior/job_manifest.json": { + "bytes": 4508, + "sha256": "95acf1efa8439e47fc5b011813f2fc5313a92de692f25459e3d56e68533a0389" + }, + "package-b.mmsession/processing/jobs/retained-prior/logs/job.log": { + "bytes": 179, + "sha256": "f0c184fbf12257a9ad4e41329ab95a5578ca769ca5fb84d9b9a32a18df8d7f46" + }, + "package-b.mmsession/processing/jobs/retained-prior/params.json": { + "bytes": 252, + "sha256": "9c0e1ab18949727f29352f1a602ae65d74db48f8453a49faa72fbc95c518b35b" + }, + "package-b.mmsession/processing/jobs/retained-prior/reports/qc.html": { + "bytes": 1629, + "sha256": "93671b7b67b1bf290a50a7a8d69e6fee6968caa1e540bf0615add4d0d1127671" + }, + "package-b.mmsession/processing/jobs/retained-prior/reports/qc.json": { + "bytes": 1296, + "sha256": "0c3647238cffb1ae94177f950a9b1407a88e0730b4503cffd27118c4634bc706" + }, + "package-b.mmsession/processing/jobs/selected-before-missing/job_manifest.receiver-held.json": { + "bytes": 2400, + "sha256": "92e19a48f6c45e672d82c898f3827c8f353bf9e4a705c50f0012ddb033f2e845" + }, + "package-b.mmsession/processing/jobs/selected-before-missing/logs/job.log": { + "bytes": 187, + "sha256": "75632168a67884e1ae52815a3ea0d9d3826f2d57f6ea8c23f1fa3f72a7591938" + }, + "package-b.mmsession/processing/jobs/selected-before-missing/params.json": { + "bytes": 260, + "sha256": "564c6f9ab9fc6eed20ffe5a8de9fd55533f59d2783e38b1217cb65f88358b20a" + }, + "package-b.mmsession/processing/jobs/selected-before-missing/reports/qc.html": { + "bytes": 1629, + "sha256": "93671b7b67b1bf290a50a7a8d69e6fee6968caa1e540bf0615add4d0d1127671" + }, + "package-b.mmsession/processing/jobs/selected-before-missing/reports/qc.json": { + "bytes": 1296, + "sha256": "0c3647238cffb1ae94177f950a9b1407a88e0730b4503cffd27118c4634bc706" + }, + "package-b.mmsession/sources/sim.emg.main/health/gaps.jsonl": { + "bytes": 0, + "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "package-b.mmsession/sources/sim.emg.main/source.json": { + "bytes": 112, + "sha256": "4e7626e51bfb804c27f83bf98ee186a47ec9f36fec0cbd7863ea8ecb1ecfbd10" + }, + "package-b.mmsession/sources/sim.emg.main/streams/sim.emg.main.batch/segments/000000.mcap": { + "bytes": 1094, + "sha256": "9e997481c9b39b6a6b2d647df873fea26b04337c41571e77427a7f8ca9cda63b" + }, + "package-b.mmsession/sources/sim.emg.main/streams/sim.emg.main.batch/stream.json": { + "bytes": 224, + "sha256": "5307697f957309eaca816fa0e20c4799c900e2598a8acf66a59928aa83b305b2" + }, + "package-b.mmsession/sources/sim.imu.upper/source.json": { + "bytes": 118, + "sha256": "a6198f509edc557c1e1d8583a767a540962977751c80a1b6491e3d594b60c7a8" + }, + "package-b.mmsession/sources/sim.imu.upper/streams/sim.imu.upper.frames/segments/000000.mcap": { + "bytes": 1678, + "sha256": "c477a0e0865086fbb4154c977def4d93ea5fb38cc098a4862c45b21b966014c9" + }, + "package-b.mmsession/sources/sim.imu.upper/streams/sim.imu.upper.frames/stream.json": { + "bytes": 219, + "sha256": "ec39026bed1b833d4decb0ef7b0efb94c5557a5647bc50addc060bef3a30d50d" + } + }, + "fixture_root": "/dev/shm/hamon-401c5d17da79-capturesuite-receiving/fixtures-native", + "helper_sha256": "b46094d3d823145aa07aa088371c6a63343ee7c5d8a06b254c6a4669f8c52da8", + "loop": "QApplication.exec; state-machine actions via QTimer; no manual processEvents, QTest.qWait, source edits, worker replacement, or retained worker/thread reference", + "method_sha256": "cb2e6486fc13e6e180fc6e8f83d690f3b3cab84faffce6a7c7b0e3fde791a3cd", + "pass": true, + "process_return": 0, + "result": "All independent native QApplication receiving checks passed on exact corrected candidate", + "runtime": { + "pyside6": "6.11.2", + "python": "3.12.14 (main, Aug 25 2026, 14:00:49) [Clang 22.1.3 ]", + "qt_platform": "offscreen" + }, + "schema": "capturesuite.history.independent-native-receiving.v1", + "screens": { + "before_late_delivery": { + "history_loaded_job_id": "", + "inspector": "No job loaded", + "last_job_dir": "", + "linked_plot_count": 0, + "open_folder_enabled": false, + "open_report_enabled": false, + "package": "/dev/shm/hamon-401c5d17da79-capturesuite-receiving/fixtures-native/package-b.mmsession", + "png_count": 0, + "sync_title": "Sync dashboard", + "tabs": [ + "Sync" + ] + }, + "late_qc": { + "path": "/dev/shm/hamon-401c5d17da79-capturesuite-receiving/evidence/native-late-qc.png", + "sha256": "eea35e5b9fa6babf0971927bbb6d4365847d7181d55ec2b99334fe56b4ab5131" + }, + "reopened_a": { + "path": "/dev/shm/hamon-401c5d17da79-capturesuite-receiving/evidence/native-reopened-a.png", + "sha256": "3250ff333afde60db4195c0a3df7132008cd74601d5e52ae66acbb5c7da9396e" + }, + "reopened_b": { + "path": "/dev/shm/hamon-401c5d17da79-capturesuite-receiving/evidence/native-reopened-b.png", + "sha256": "810766243e7848e2aa966a588c1c4e2245ad74526870a810232ce89db56635e8" + } + }, + "seconds": 0.9143500069985748, + "source_imports": { + "capture_analysis": { + "path": "/dev/shm/capturesuite-history-401c5d17da79/source/libs/python/capture_analysis/capture_analysis/__init__.py", + "sha256": "14cfe6dccd33a0bda74fac3c9339e1a37a3538b2110a8ae6e307801b776eb43a" + }, + "capture_analysis.jobs": { + "path": "/dev/shm/capturesuite-history-401c5d17da79/source/libs/python/capture_analysis/capture_analysis/jobs.py", + "sha256": "e7e9dda44eb014d18192563f1e2c0ae78cece850fbc853b0be3919daaf5ee276" + }, + "capture_desktop.screen_analysis": { + "path": "/dev/shm/capturesuite-history-401c5d17da79/source/desktop/capture_desktop/screen_analysis.py", + "sha256": "98a704e31b14497e012fe5618ad47cc8a772bd2d59775826d71a5bdf41533211" + }, + "capture_desktop.widgets_analysis_plots": { + "path": "/dev/shm/capturesuite-history-401c5d17da79/source/desktop/capture_desktop/widgets_analysis_plots.py", + "sha256": "85c73f881ee7d60ef2f868f7ff73fc57c0a4ef99a717f7f5015534db23e1ab86" + } + }, + "source_unchanged": true +} diff --git a/docs/evidence/analysis-history-401c5d17da79/independent/native-candidate.log b/docs/evidence/analysis-history-401c5d17da79/independent/native-candidate.log new file mode 100644 index 00000000..ee6a1fb8 --- /dev/null +++ b/docs/evidence/analysis-history-401c5d17da79/independent/native-candidate.log @@ -0,0 +1,23 @@ +This plugin does not support propagateSizeHints() +fresh screen reopens real prior A result into native gallery and inspector True +package switch clears prior result and both launch targets True +This plugin does not support propagateSizeHints() +same basename in B resolves B figures and metadata only True +malformed-manifest is visibly unavailable and refuses Open without replacing B True +missing-manifest is visibly unavailable and refuses Open without replacing B True +foreign-session is visibly unavailable and refuses Open without replacing B True +foreign-directory is visibly unavailable and refuses Open without replacing B True +unavailable-row actions leave every saved byte unchanged True +Open revalidates a cached row after its manifest disappears True +refused cached Open preserves all bytes after the controlled rename True +This plugin does not support propagateSizeHints() +real QThread QC completed and persisted before receiving release True +prior-package real completion cannot bind current B gallery or inspector True +prior-package result is explicitly retained for later inspection True +current B saved result reopens after actual Qt thread completion True +returning to A explicitly opens the genuinely completed late QC True +late delivery and later reopenings perform no persisted writes True +all captured raw data remains unchanged True +no Qt error dialog or native worker failure True +frozen source bytes remained exact throughout native receiving True +{"pass": true, "checks": 19, "seconds": 0.9143500069985748, "code": 0} diff --git a/docs/evidence/analysis-history-401c5d17da79/publication-composition.json b/docs/evidence/analysis-history-401c5d17da79/publication-composition.json new file mode 100644 index 00000000..d80c118f --- /dev/null +++ b/docs/evidence/analysis-history-401c5d17da79/publication-composition.json @@ -0,0 +1,469 @@ +{ + "schema": "hamon.current-source-composition.v1", + "repository": "Jacob-Met/CaptureSuite", + "canonical_parent": "3e3ecc5ecc1cfc79c79901eb5cffe10b0ec5852e", + "canonical_tree": "18e97093f04de23de5e9878fd22c1f5ed986d5f3", + "author_base": "72c15d6b623e217291a824e4e4808a385df896a9", + "author_final": "495b8d45b0b9aa2231bccb315bd68e762a240143", + "author_tree": "08a4a99b6c7556be50d77bb4d5368fa484802b1c", + "original_accepted_runtime": "37443f0d4d5ffa684b5423d58501856cadbe0655", + "current_qualified_runtime_tree": "167bbac3bba862cc1532d954fe2d503e561a00df", + "current_screen_blob": "6893f119593f8ff6551167efcb1939d014a081e6", + "current_screen_sha256": "1475764b8453ed870174fcaf98bc02370db76b5001c4175feb93263ad33d5b70", + "merge": { + "canonical_parent": "3e3ecc5ecc1cfc79c79901eb5cffe10b0ec5852e", + "author_parent": "495b8d45b0b9aa2231bccb315bd68e762a240143", + "base": "72c15d6b623e217291a824e4e4808a385df896a9", + "returncode": 1, + "stdout": "355c4353dc72525d6b2955818b8016588d411953\n100644 ef608ddb93c86c0d0c057b703e40b897e16f8a4a 1\tdesktop/capture_desktop/screen_analysis.py\n100644 78905bbde5de536dad125b6e4e48a475e9b14272 2\tdesktop/capture_desktop/screen_analysis.py\n100644 966f89f8cfad679a4a461900569365c50476581b 3\tdesktop/capture_desktop/screen_analysis.py\n100644 b62d86046bd072f09fc2d3c9df4f77b711a8a214 1\tdocs/design/research/PROGRESS.md\n100644 99c812ac6b3776c41e3244a90f46f2e9f366be08 2\tdocs/design/research/PROGRESS.md\n100644 0be69fb4f408dfa93e0f39364c6702c4fe9646e2 3\tdocs/design/research/PROGRESS.md\n\nAuto-merging desktop/capture_desktop/screen_analysis.py\nCONFLICT (content): Merge conflict in desktop/capture_desktop/screen_analysis.py\nAuto-merging docs/design/research/PROGRESS.md\nCONFLICT (content): Merge conflict in docs/design/research/PROGRESS.md\n", + "stderr": "", + "conflict_paths": [ + "desktop/capture_desktop/screen_analysis.py", + "docs/design/research/PROGRESS.md" + ], + "screen_resolution": "Preserve the current scope owner's normalized identity, conditional reset, summary/enabled refresh and package_loaded signal; pass the same resolved path to history.", + "additional_runtime_change": "After the concrete startup negative, treat a retained _thread handle as busy until unchanged cleanup clears it.", + "progress_resolution": "Prepend the new receiving entry and exact original 25-line author entry to the complete current PROGRESS bytes." + }, + "runtime_boundary": [ + "desktop/capture_desktop/analysis_history.py", + "desktop/capture_desktop/widgets_analysis_history.py", + "desktop/capture_desktop/screen_analysis.py" + ], + "unchanged_current_scope_hooks": [ + "_AnalysisWorker", + "_on_thread_finished", + "set_scope", + "_scope_error", + "refresh_from_state", + "_refresh_summary" + ], + "authored_history_modules_and_test_bytes_unchanged": true, + "progress": { + "author_entry_lines": 25, + "author_entry_sha256": "cfc83c07fdcc381d7997bf2ccd5d413498ce03500cb6ee2f6f76c29ae05f562e", + "receiving_entry_sha256": "05d12052347587b051f4dff32b4e38ddf8bcfa055936078dbe735ee035a9e79d", + "complete_current_bytes": 41867, + "complete_current_sha256": "67ac05cfb502beeeb48bbaf89952426a5cd389c3c0529dcdb6e1669ba72e72ec", + "current_is_exact_suffix": true, + "merged_sha256": "02a1b11ba531c2093107dead9e6472bb516ff3863e294234c2da122d061a13af" + }, + "qualification": { + "author_and_retained_tests": { + "source": "37443f0d4d5ffa684b5423d58501856cadbe0655", + "base": "72c15d6b623e217291a824e4e4808a385df896a9", + "passed": 14, + "skipped": 0 + }, + "independent_native_history": { + "source": "37443f0d4d5ffa684b5423d58501856cadbe0655", + "base": "72c15d6b623e217291a824e4e4808a385df896a9", + "checks_passed": 19 + }, + "historical_qc2_successor": { + "parent": "e43da3b855475c8aacf815c201fa03eddaeec0f1", + "runtime_tree": "ba5b4b925b00ecb17895a8c8ad29410e787f97dc", + "checks_passed": 14 + }, + "current_scope_history": { + "schema": "hamon.current-scope-history-receiving.v1", + "canonical_parent": "3e3ecc5ecc1cfc79c79901eb5cffe10b0ec5852e", + "runtime_tree": "167bbac3bba862cc1532d954fe2d503e561a00df", + "screen_git_blob": "6893f119593f8ff6551167efcb1939d014a081e6", + "screen_sha256": "1475764b8453ed870174fcaf98bc02370db76b5001c4175feb93263ad33d5b70", + "receiver_sha256": "c45eb2b2b02b8c9423565d811ae7782eff576b1313bf5cef366c4af8bf4e3802", + "process_exit_code": 0, + "seconds": 3.534, + "checks_passed": 24, + "checks_failed": 0, + "source_files": 142, + "source_bytes_unchanged": true, + "raw_package_bytes_unchanged": true, + "frame_sha256": "c8ec0afb810a76da3254e035cdac3a5e0ec46097976743e1917e672441a550f5", + "visual_review": "The current native scope picker and saved-history row are legible together. The very long private package path wraps and clips in the existing narrow left control column; this is not a complete layout or Windows MainWindow acceptance.", + "startup_control": { + "source_blob": "ee2db9acacdc92d3aa8ba0bfe12f638e9418f9b4", + "runtime_tree": "07d78241dca691015bb3e4d8d260b109672b7de0", + "method_sha256": "44c24508e4e4aa9d14d1771be486bb953f8b3719652183c2e9d7c3bb81ac2b17", + "passed_before_stop": 2, + "failed": 1, + "receipt": "startup-negative/receipt.json" + }, + "receiver_adjustments": [ + "Accept the existing completed_with_warnings status only with both exact expected fixture metadata warnings and exact saved range.", + "Explicitly verify Run/history controls restore after each completed worker.", + "Emit complete receipt and native PNG in stdout so artifact transport is independent of the native journey." + ], + "nonaccepting_continuation": { + "method_sha256": "1f7029cb84c999feed1b5b636d65551a75938f5875d09bbff20065aa9d1cc0b2", + "cause": "ENOSPC while writing frame/receipt and supervisor artifacts", + "receipt_bytes": 0, + "native_outcome": "not accepted; no complete result claimed" + }, + "qualification_limits": "Original 14 tests / 19 checks remain on 37443 and 72c15; QC/2 remains e43; current numeric nested-gallery limitation remains separate. No full Windows, MainWindow, daemon, hardware or installed-release acceptance." + }, + "current_numeric_gallery_limit": "The existing top-level PNG discovery gap is preserved at its exact 0ed+history input. Root assigned its separate gallery repair to production_discovery; no gallery source is edited here.", + "not_claimed": "Full Windows MainWindow, full suite, daemon, hardware, installed release or complete latest d43 main acceptance" + }, + "ownership": { + "history": "estate-401c5d17da79/production_discovery; issue #55", + "independent_original_history_receiver": "estate-401c5d17da79/estate_coordination", + "current_parent_composition_and_receiver": "estate-401c5d17da79/integration_discovery", + "scope_picker": "Merged PR #58 / issue #53; every current scope hook and unrelated byte preserved", + "gallery": "Separate production_discovery repair; unchanged in this source" + }, + "freshness": { + "schema": "hamon.capture-history-publication-freshness.v1", + "repository": "Jacob-Met/CaptureSuite", + "qualified_parent": "3e3ecc5ecc1cfc79c79901eb5cffe10b0ec5852e", + "latest_observed_main": "d43bdea867d6198a707a5f55e29216c76054517e", + "source_url": "https://api.github.com/repos/Jacob-Met/CaptureSuite/compare/3e3ecc5ecc1cfc79c79901eb5cffe10b0ec5852e...d43bdea867d6198a707a5f55e29216c76054517e", + "compare_html_url": "https://github.com/Jacob-Met/CaptureSuite/compare/3e3ecc5ecc1cfc79c79901eb5cffe10b0ec5852e...d43bdea867d6198a707a5f55e29216c76054517e", + "base_commit": "3e3ecc5ecc1cfc79c79901eb5cffe10b0ec5852e", + "merge_base_commit": "3e3ecc5ecc1cfc79c79901eb5cffe10b0ec5852e", + "status": "ahead", + "ahead_by": 3, + "behind_by": 0, + "total_commits": 3, + "commits": [ + { + "sha": "0dd591b41bea35ce0639bba312d6f56b77f68088", + "parents": [ + "e43da3b855475c8aacf815c201fa03eddaeec0f1" + ], + "message": "Preserve missing pose evidence in kinematic labels\n\nMask non-simulated landmarks by each joint's required finite geometry and confidence instead of selecting synthetic fallback angles. Retain independent limb validity and NaN velocity/AFR values at invalid frames, with unchanged complete-geometry and explicit-sim Parquet bytes.\n\nReceive the frozen 21-test native author result, independent four-workflow/36-assertion CLI review, and one current-QC/report CLI composition check. Preserve all 777 unrelated current-main leaves and the complete current progress log. Existing supported Windows CI remains required before merge.\n\nCloses #56" + }, + { + "sha": "711e8ec22d462b7588e52727cf3d6524d7524c7a", + "parents": [ + "0dd591b41bea35ce0639bba312d6f56b77f68088", + "284d168d7614e2465bafba1092d8cbe4b6e13b40" + ], + "message": "Merge current main and retain both kinematics and storage progress entries\n\nPreserve all37 frozen non-PROGRESS contribution leaves and all815 unrelated current-main leaves. Resolve only the concurrent PROGRESS prepend, retaining the exact current log plus the original1527-byte entry. Runtime, regression tests and receiving evidence are unchanged." + }, + { + "sha": "d43bdea867d6198a707a5f55e29216c76054517e", + "parents": [ + "3e3ecc5ecc1cfc79c79901eb5cffe10b0ec5852e", + "711e8ec22d462b7588e52727cf3d6524d7524c7a" + ], + "message": "Preserve missing pose evidence in kinematic labels\n\nKeep absent or invalid non-simulated pose geometry masked independently for each elbow and shoulder. Preserve complete-input and explicit-simulation math; only explicit sim_ models select fixture equations.\n\nQualified source head 711e8ec22d462b7588e52727cf3d6524d7524c7a with the current desktop scope and Windows atomic-write changes in actual CI checkout dc9ab33f4b3f3aefbb6308bbffb4e3f041d4b524, tree fea0e03773742d330963b89e0ceb72a22c7ad495. Windows run 37786404581 passed 400 Python tests with six missing-daemon skips, all 30 CTests, and all six separate native daemon/recovery cases without skips. All existing workflow gates remain unchanged.\n\nIndependent real CLI receiving passed 4/4 cases and36 assertions; baseline complete geometry and explicit sim Parquet bytes remain exact. All37 non-progress contribution leaves, all current unrelated leaves and the complete prior progress log were received from current3e3ecc5e. Original negative evidence and both CI generations are preserved. No installed release or physical measurement claim.\n\nCloses #56." + } + ], + "files": [ + { + "filename": "docs/design/KINEMATICS_PIPELINE.md", + "status": "modified", + "sha": "4206818b8834c56db530ca939b04cfe59e73aff6", + "additions": 24, + "deletions": 0, + "changes": 24 + }, + { + "filename": "docs/design/research/PROGRESS.md", + "status": "modified", + "sha": "36b05b80604935e3c70d1f076be5150e8639c164", + "additions": 24, + "deletions": 0, + "changes": 24 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/author/README.md", + "status": "added", + "sha": "5eee94afdfc2af12ad806fb816c3a9bf7f56f480", + "additions": 113, + "deletions": 0, + "changes": 113 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/author/author-receipt.json", + "status": "added", + "sha": "c51c2acc07ef57aae579c908f1fe3c31bb4b472c", + "additions": 60, + "deletions": 0, + "changes": 60 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/author/baseline-native-readback.json", + "status": "added", + "sha": "2110facf1a59ad9c1656aed76a09fad3cf8496cf", + "additions": 7, + "deletions": 0, + "changes": 7 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/author/baseline-runtime.tar.gz", + "status": "added", + "sha": "e973cff1bb0a0bffd768bf9fcef5400834ab2280", + "additions": 0, + "deletions": 0, + "changes": 0 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/author/baseline-source-manifest.json", + "status": "added", + "sha": "90416594a540a5227a70071b7597c87b291ff8de", + "additions": 812, + "deletions": 0, + "changes": 812 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/author/baseline-tests.json", + "status": "added", + "sha": "dc03cfdffaabb0209fd855482e78abb21179a658", + "additions": 298, + "deletions": 0, + "changes": 298 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/author/baseline-tests.log", + "status": "added", + "sha": "16860275d5331b2398cf48b0a2dca14601534df8", + "additions": 289, + "deletions": 0, + "changes": 289 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/author/baseline-tests.xml", + "status": "added", + "sha": "ed4db6467dd4d1410cc51e45097269ced09ef5c6", + "additions": 232, + "deletions": 0, + "changes": 232 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/author/candidate-native-readback.json", + "status": "added", + "sha": "369ab414496f49d86b28afa8a7a78b6b1e7a4e92", + "additions": 12, + "deletions": 0, + "changes": 12 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/author/candidate-source-manifest.json", + "status": "added", + "sha": "4fb157009d615aef9c7e000355df2d1750d56392", + "additions": 35, + "deletions": 0, + "changes": 35 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/author/candidate-tests.json", + "status": "added", + "sha": "15e3c7ebfc9af89e52f7d9ad5c31aaac0bf22d9f", + "additions": 301, + "deletions": 0, + "changes": 301 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/author/candidate-tests.log", + "status": "added", + "sha": "c124b9b2ffcbebd9cc3e5f87ac061017abf78741", + "additions": 12, + "deletions": 0, + "changes": 12 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/author/candidate-tests.xml", + "status": "added", + "sha": "6c202590a276a097c6b037d7939dce273fc5aaf2", + "additions": 1, + "deletions": 0, + "changes": 1 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/author/environment.json", + "status": "added", + "sha": "345664d3eb842ccc52018d36bd81cd9e892463ff", + "additions": 19, + "deletions": 0, + "changes": 19 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/author/manifest.json", + "status": "added", + "sha": "e96529b2c4475276c8483ca62414875ff049b596", + "additions": 100, + "deletions": 0, + "changes": 100 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/author/product.patch", + "status": "added", + "sha": "5f5581fb530ed1ee5f45ae89116dd772b2c00ca8", + "additions": 430, + "deletions": 0, + "changes": 430 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/author/static-checks.json", + "status": "added", + "sha": "fb1093707700a5fbbc746d7fcb3d4d6a29f6f0c6", + "additions": 28, + "deletions": 0, + "changes": 28 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/author/test-artifact-manifest.json", + "status": "added", + "sha": "b84b3cbc9bc474efa700cc7e1d632b162628ef1a", + "additions": 1665, + "deletions": 0, + "changes": 1665 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/author/test-artifacts.tar.gz", + "status": "added", + "sha": "692f10a8452e12ef0060177a89648ba0e247e9fc", + "additions": 0, + "deletions": 0, + "changes": 0 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/author/test_kinematics_validity.py", + "status": "added", + "sha": "7cf66857bcbeb9b72851ad53ce7c08f97d528fc8", + "additions": 202, + "deletions": 0, + "changes": 202 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/current/README.md", + "status": "added", + "sha": "5e3b6e546922665e6639b3a4f49c837983fc56f5", + "additions": 43, + "deletions": 0, + "changes": 43 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/current/junit.xml", + "status": "added", + "sha": "e574c6fab6ed3890ac856040421e2a576f385607", + "additions": 1, + "deletions": 0, + "changes": 1 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/current/manifest.json", + "status": "added", + "sha": "741306eabe2798bdc0927e34773cf9f7478b312a", + "additions": 51, + "deletions": 0, + "changes": 51 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/current/process.log", + "status": "added", + "sha": "7e1ead8287c87a8d972a2cf50390981926c5dd1a", + "additions": 12, + "deletions": 0, + "changes": 12 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/current/receipt.json", + "status": "added", + "sha": "75d0d3aee60e47679da6672ee3e9c8ec07b16d8f", + "additions": 300, + "deletions": 0, + "changes": 300 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/current/receive-current-seam.cjs", + "status": "added", + "sha": "cdc7717acd47e6776ca9c1afc100e429cc6e5ea9", + "additions": 16, + "deletions": 0, + "changes": 16 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/current/source-manifest.json", + "status": "added", + "sha": "6cb4dfce021abbeaff5e7e1b36f10c5822c9cdb6", + "additions": 818, + "deletions": 0, + "changes": 818 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/current/test-artifact-manifest.json", + "status": "added", + "sha": "4747226f7cb788048bdf0593ad3f82911da0b4eb", + "additions": 130, + "deletions": 0, + "changes": 130 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/current/test-artifacts.tar.gz", + "status": "added", + "sha": "30a23f4ce7066ac1db085ea21179b763f3ad0829", + "additions": 0, + "deletions": 0, + "changes": 0 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/independent/README.md", + "status": "added", + "sha": "355804bd71cd836250a57126b3fee28a47f233be", + "additions": 13, + "deletions": 0, + "changes": 13 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/independent/independent-cli-artifacts.tar.gz", + "status": "added", + "sha": "739fc581cae5561014b45049f225a2d4abdc2a6f", + "additions": 0, + "deletions": 0, + "changes": 0 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/independent/manifest.json", + "status": "added", + "sha": "b58ee77faebd30f53581475d4f4a931cf54c64e6", + "additions": 30, + "deletions": 0, + "changes": 30 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/independent/receiving.json", + "status": "added", + "sha": "4e63e2efd9e71728329abf66fe283597ee8ee815", + "additions": 59, + "deletions": 0, + "changes": 59 + }, + { + "filename": "docs/evidence/kinematics-validity-20261008-406d0fb04c43/independent/source-review.json", + "status": "added", + "sha": "bbfb3c062188f4287388741cfd526d07249f5177", + "additions": 26, + "deletions": 0, + "changes": 26 + }, + { + "filename": "libs/python/capture_analysis/capture_analysis/kinematics/compute.py", + "status": "modified", + "sha": "fb8be59b00e15d9c264aad0983cf75a757c9e210", + "additions": 53, + "deletions": 43, + "changes": 96 + }, + { + "filename": "tests/analysis/test_kinematics_validity.py", + "status": "added", + "sha": "7cf66857bcbeb9b72851ad53ce7c08f97d528fc8", + "additions": 202, + "deletions": 0, + "changes": 202 + } + ], + "decision": "Retain the qualified actual 3e3 parent. This later merge changes only the kinematics compute implementation, its tests/design/evidence and shared progress. The accepted 24-check native journey exercised numeric features; no desktop/history/scope or numeric-feature source changed. These receipts do not claim complete d43 acceptance." + }, + "prior_0ed_composition": "Preserved immutable in its own durable source packet; its 57-file payload and receipts are not relabelled as current 3e3 acceptance.", + "publication": "Prepared source handoff only. The final actual tree/parents are recorded by the external publication manifest; no GitHub acceptance or installed state is inferred.", + "current_start_job_hook": { + "difference": "The authored history integration replaces the two direct gallery/inspector clears with _clear_result_view().", + "proof": "The entire current _start_job AST equals the qualified one after only that explicit two-statement-to-helper substitution. The method is exact between the initial composition and the busy correction.", + "worker_and_cleanup": "The current worker class and thread cleanup ASTs are exact." + }, + "documentation_precision": "Correct the initial prepared packet wording about _start_job before publication. The qualified runtime and every native method and receipt remain exact." +} diff --git a/docs/evidence/analysis-history-401c5d17da79/publication-license-check.json b/docs/evidence/analysis-history-401c5d17da79/publication-license-check.json new file mode 100644 index 00000000..b74620ab --- /dev/null +++ b/docs/evidence/analysis-history-401c5d17da79/publication-license-check.json @@ -0,0 +1,11 @@ +{ + "command": [ + "/workspace/scratch/234cae4aee53/capturesuite-venv/bin/python", + "tools/check_licenses.py", + "--enforce-spdx" + ], + "exit": 0, + "observed_stdout": "license check OK\n", + "runtime_changes": false, + "correction": "Only two copied evidence scripts received required GPL-3.0-only SPDX headers; original tested bytes are preserved in1ce96118 and recorded separately." +} diff --git a/docs/evidence/analysis-history-401c5d17da79/publication-method-adjustments.json b/docs/evidence/analysis-history-401c5d17da79/publication-method-adjustments.json new file mode 100644 index 00000000..5cb192a5 --- /dev/null +++ b/docs/evidence/analysis-history-401c5d17da79/publication-method-adjustments.json @@ -0,0 +1,20 @@ +{ + "schema": "capturesuite.history.evidence-publication-adjustments.v1", + "original_methods_preserved_in_commit_and_durable_packet": "1ce96118aac40f6747b75d39ff7d72e8693c8946", + "changes": [ + { + "path": "visual/details-visual.py", + "original_commit": "1ce96118aac40f6747b75d39ff7d72e8693c8946", + "original_sha256": "f934e4db27257eb5e66c1dbb341a4b0949a3c3fd15cdaaf144493d7df7ad55d9", + "publication_sha256": "c747bcb5bf519b765186e93b4689666148f6bae1b4c45014adda424371c694ab", + "difference": "Prepend only the GPL-3.0-only SPDX comment required by the unchanged repository license gate; executable bytes otherwise unchanged." + }, + { + "path": "author/baseline-history.py", + "original_commit": "1ce96118aac40f6747b75d39ff7d72e8693c8946", + "original_sha256": "0425023978d39e9bfd1dd3765781220962328d6a309be3005c9a2f1fd3f5214b", + "publication_sha256": "ae3d803367e60939f9b777f2196bd4e59e0e2ed169929b1260ec391279f66538", + "difference": "Prepend only the GPL-3.0-only SPDX comment required by the unchanged repository license gate; executable bytes otherwise unchanged." + } + ] +} diff --git a/docs/evidence/analysis-history-401c5d17da79/visual/details-log.png b/docs/evidence/analysis-history-401c5d17da79/visual/details-log.png new file mode 100644 index 00000000..9ef1136c Binary files /dev/null and b/docs/evidence/analysis-history-401c5d17da79/visual/details-log.png differ diff --git a/docs/evidence/analysis-history-401c5d17da79/visual/details-parameters.png b/docs/evidence/analysis-history-401c5d17da79/visual/details-parameters.png new file mode 100644 index 00000000..2ea38b17 Binary files /dev/null and b/docs/evidence/analysis-history-401c5d17da79/visual/details-parameters.png differ diff --git a/docs/evidence/analysis-history-401c5d17da79/visual/details-visual-receipt.json b/docs/evidence/analysis-history-401c5d17da79/visual/details-visual-receipt.json new file mode 100644 index 00000000..7e60b946 --- /dev/null +++ b/docs/evidence/analysis-history-401c5d17da79/visual/details-visual-receipt.json @@ -0,0 +1,13 @@ +{ + "source_commit": "37443f0d4d5ffa684b5423d58501856cadbe0655", + "saved_fixture_author": "independent current-main QC/2 receiver", + "package": "/dev/shm/hamon-401c5d17da79-capture-history-pr/current-boundary/current-run/current QC saved.mmsession", + "qt_platform": "offscreen", + "screens": { + "details-parameters.png": "b5bb8407c06e29a89f47739358c8492d211be803a20e2ef164b00b70e3953484", + "details-log.png": "b33e93d0026b163744737283234116d9332c4790dffc3cfd0caecad2d4935686" + }, + "saved_bytes_unchanged": true, + "no_worker_started": true, + "result": "Native details visually captured; read-only boundaries passed." +} diff --git a/docs/evidence/analysis-history-401c5d17da79/visual/details-visual.py b/docs/evidence/analysis-history-401c5d17da79/visual/details-visual.py new file mode 100644 index 00000000..8ee20ba3 --- /dev/null +++ b/docs/evidence/analysis-history-401c5d17da79/visual/details-visual.py @@ -0,0 +1,97 @@ +# SPDX-License-Identifier: GPL-3.0-only +"""Read-only native visual check of the frozen saved-job details window.""" +from __future__ import annotations + +import hashlib +import json +import os +from pathlib import Path +import sys +import traceback + +ROOT = Path('/dev/shm/capturesuite-history-401c5d17da79') +SOURCE = ROOT / 'source' +PACKAGE = Path('/dev/shm/hamon-401c5d17da79-capture-history-pr/current-boundary/current-run/current QC saved.mmsession') +os.environ.update(QT_QPA_PLATFORM='offscreen', PYTHONDONTWRITEBYTECODE='1') +sys.dont_write_bytecode = True +sys.path[:0] = [str(SOURCE / part) for part in ( + 'desktop', 'libs/python/capture_analysis', 'libs/python/capture_session', + 'libs/python/capture_protocol')] + +from PySide6.QtCore import QTimer +from PySide6.QtWidgets import QApplication, QPlainTextEdit, QTabWidget +from capture_desktop import theme +from capture_desktop.screen_analysis import AnalysisScreen +from capture_desktop.state import CaptureState + + +def hashes(): + return {str(path.relative_to(PACKAGE)): hashlib.sha256(path.read_bytes()).hexdigest() + for path in PACKAGE.rglob('*') if path.is_file()} + + +before = hashes() +app = QApplication([]) +theme.apply_theme(app, setting='dark') +screen = AnalysisScreen(CaptureState()) +screen.resize(1220, 900) +receipt = {'source_commit': '37443f0d4d5ffa684b5423d58501856cadbe0655', + 'saved_fixture_author': 'independent current-main QC/2 receiver', + 'package': str(PACKAGE), 'qt_platform': app.platformName(), 'screens': {}} + + +def finish(): + try: + dialog = screen._history._dialog + image = ROOT / 'evidence/details-log.png' + assert dialog.grab().save(str(image)) + receipt['screens'][image.name] = hashlib.sha256(image.read_bytes()).hexdigest() + receipt['saved_bytes_unchanged'] = hashes() == before + receipt['no_worker_started'] = screen._thread is None + assert receipt['saved_bytes_unchanged'] and receipt['no_worker_started'] + receipt['result'] = 'Native details visually captured; read-only boundaries passed.' + except BaseException: + receipt['failure'] = traceback.format_exc() + finally: + (ROOT / 'evidence/details-visual-receipt.json').write_text(json.dumps(receipt, indent=2) + '\n') + if screen._history._dialog is not None: + screen._history._dialog.close() + screen.close() + app.quit() + + +def capture(): + try: + dialog = screen._history._dialog + assert dialog is not None and dialog.isVisible() + params = dialog.findChild(QPlainTextEdit, 'analysisHistoryParameters') + assert params.isReadOnly() and json.loads(params.toPlainText())['command'] == 'qc' + image = ROOT / 'evidence/details-parameters.png' + assert dialog.grab().save(str(image)) + receipt['screens'][image.name] = hashlib.sha256(image.read_bytes()).hexdigest() + dialog.findChild(QTabWidget).setCurrentIndex(1) + QTimer.singleShot(20, finish) + except BaseException: + receipt['failure'] = traceback.format_exc() + finish() + + +def start(): + try: + screen.set_package(str(PACKAGE)) + combo = screen._history._jobs + index = next(i for i in range(combo.count()) if combo.itemData(i).job_id == 'current-qc') + combo.setCurrentIndex(index) + screen.show() + screen._history._open.click() + screen._history._details.click() + QTimer.singleShot(30, capture) + except BaseException: + receipt['failure'] = traceback.format_exc() + finish() + + +QTimer.singleShot(0, start) +app.exec() +print(json.dumps(receipt, indent=2)) +raise SystemExit(1 if 'failure' in receipt else 0) diff --git a/docs/evidence/analysis-history-401c5d17da79/visual/native-reopened-b.png b/docs/evidence/analysis-history-401c5d17da79/visual/native-reopened-b.png new file mode 100644 index 00000000..6d63100a Binary files /dev/null and b/docs/evidence/analysis-history-401c5d17da79/visual/native-reopened-b.png differ diff --git a/docs/evidence/nested-figure-gallery-401c5d17da79/README.md b/docs/evidence/nested-figure-gallery-401c5d17da79/README.md new file mode 100644 index 00000000..6274f6ec --- /dev/null +++ b/docs/evidence/nested-figure-gallery-401c5d17da79/README.md @@ -0,0 +1,58 @@ +# Nested numeric figures in the saved analysis gallery + +Issue [64](https://github.com/Jacob-Met/CaptureSuite/issues/64) repairs the desktop reader for the nested PNG layout already emitted by merged numeric-analysis [PR 49](https://github.com/Jacob-Met/CaptureSuite/pull/49). A retained real numeric job had two valid channel PNGs, but both direct gallery loading and saved-job reopening showed only the Sync tab. The original negative receipt is preserved in `qualification/baseline-numeric-receipt.json`. + +## Result and source boundary + +The only production change is inside `FigureGallery.load_job_dir` in `desktop/capture_desktop/widgets_analysis_plots.py`. Discovery includes PNG descendants of the selected figures directory. Numeric source/stream directory identities use their existing UTF-8 hex encoding to produce readable source / stream / channel tab labels; exact relative paths remain available as tooltips. Unknown nested layouts retain their relative path labels. Legacy flat labels retain their original 24-character behavior, and only the root `sync_dashboard.png` is suppressed in favor of the existing linked dashboard. + +Directories named `*.png` and file candidates that resolve outside the real figures directory are excluded while valid siblings remain visible. An unreadable PNG retains the existing explanatory image placeholder. This is a bounded saved-file reader check, not a claim about adversarial concurrent filesystem changes. + +The gallery constructor, clear method, loaded-job/export ownership, SyncDashboardView, JobInspector, numeric handlers, analysis history and writer formats are unchanged. Shared-file coordination with the selected-export owner is recorded in [issue 59 comment 6061378807](https://github.com/Jacob-Met/CaptureSuite/issues/59#issuecomment-6061378807). + +## Exact qualification + +The genuine authored parent is `3e3ecc5ecc1cfc79c79901eb5cffe10b0ec5852e`. Runtime/test commit `f2c8b88f16f82517bd8fce118bacf63704b0a1f5` has tree `6c72934c1369cd9ccd4c466c3c0fb18038fb1cce`. The publication successor adds only this evidence and an additive PROGRESS entry. + +| Observation | Exact scope | Result | +| --- | --- | --- | +| Independent real numeric baseline | Existing gallery blob `bb6c3033b5e4ed96a2e08857d38715b836926bf5`, current numeric pipeline plus saved-history receiver | Two saved nested PNGs; gallery only Sync; 6 positive checks and 1 presentation failure | +| Initial native author suite | Gallery SHA-256 `852c9059d01fac9ba38edbe228e0920e8cf3298bb8e1a9d6610b148f6d1e7ffb` | 6 passed | +| Initial retained-output receiving | Same initial gallery bytes | 15 checks passed; this predates the containment correction | +| Added containment challenge | Same initial gallery bytes, new external-PNG symlink and directory fixtures | 1 expected failure: the foreign PNG appeared as an extra tab | +| Final native author suite | Gallery SHA-256 `c3837c72285b37e486be38933ad73950ae91ba10d335ff5e1c3f37ef5d08aa26` | 7 passed, 0 skipped | +| Final real retained-output receiving | Same final gallery bytes, unchanged receiving method | 15 checks passed, process exit 0 | +| Static checks | Final production module and focused test | Ruff and whitespace passed | + +The final retained-output run uses QApplication.exec with QTimer scheduling on the existing Linux Python 3.12.14 / PySide6 6.11.2 runtime. It does not generate new jobs or use manual event pumping. It verifies both actual numeric PNGs pixel-for-pixel against their saved files, exact source/stream/channel identities, the retained numeric linked series, the two older flat EMG/IMU figures and their two linked series, package switching, and every raw/saved package hash before and after reading. It also checks the executed source bytes. The five standard offscreen `propagateSizeHints()` notices are retained in the process receipt; there are no exceptions or failed checks. + +The exact executed method is `methods/receive_retained_gallery.py`, SHA-256 `a83e1abed7c773b2692d7983873d9aa852603548e9c6870d85ea27ad19fb9b3a`. Final receipt `qualification/retained-final-receipt.json` has SHA-256 `d65d3bbea6ce187feb5c6aa8af97c65141c12a11419caa5e6cdb0133ee879ccd`. The seven-test source hash is `727340556a0d8e4178b62157ba9680a59d1c43158abb1bf979b21be8c98c591f`. + +## Native presentation review + +The three 1200 × 820 native widget captures in `visual/` were inspected after event-loop layout and paint. Numeric channel identities remain distinct and visible; the original PNG and legacy figure retain native resolution and horizontal scrolling. The linked legacy traces and their labels remain visible. The original PNG width is 1650 pixels, so these images show a scrollable viewport rather than claiming the full curve fits at that window size. Final captures are byte-identical to the initial reviewed frames. + +## Reproduction and boundaries + +With the project's native Qt dependencies available, run the focused suite from the full source checkout: + +```sh +QT_QPA_PLATFORM=offscreen PYTHONDONTWRITEBYTECODE=1 python -m pytest tests/ui/test_analysis_nested_gallery.py -q -ra -p no:cacheprovider +``` + +The symlink fixture reports an explicit skip only when the platform cannot create a symbolic link; no such skip occurred in the recorded Linux run. The source change and receipt do not claim Windows, physical capture, or a complete product acceptance result. + +The durable author packet contains the exact retained numeric and legacy packages under `fixtures/`. The receiving method accepts explicit paths so they can be replayed without reconstructing analysis output: + +```sh +QT_QPA_PLATFORM=offscreen PYTHONDONTWRITEBYTECODE=1 python methods/receive_retained_gallery.py \ + --source-root /absolute/source \ + --numeric-job /absolute/packet/fixtures/numeric.mmsession/processing/jobs/retained-numeric \ + --legacy-job /absolute/packet/fixtures/legacy.mmsession/processing/jobs/retained-prior +``` + +The method writes its receipt and native PNG frames as JSON to stdout; redirect that output to a new owned file when replaying. No dependency installation was performed. Original selected package paths and all read hashes remain in the receipts. + +The source graph is explicitly shallow at the preserved canonical input; no historical ancestry was invented. The later main `d43bdea` kinematics merge was checked separately and changed no gallery, desktop scope or numeric-feature bytes. The qualified 3e3 parent is retained, and current publication integration remains with the lead. The local SPDX check is limited to the materialized source/evidence and exact required license structure in this sparse checkout; the full existing hosted gate remains required. + +`artifact-manifest.json` inventories the evidence bytes. Initial source custody, the final source-preserving Git bundle, binary patch, retained packages and native read-back hashes are sealed separately in the durable author packet. diff --git a/docs/evidence/nested-figure-gallery-401c5d17da79/artifact-manifest.json b/docs/evidence/nested-figure-gallery-401c5d17da79/artifact-manifest.json new file mode 100644 index 00000000..d1055c54 --- /dev/null +++ b/docs/evidence/nested-figure-gallery-401c5d17da79/artifact-manifest.json @@ -0,0 +1,96 @@ +{ + "canonical_base": "3e3ecc5ecc1cfc79c79901eb5cffe10b0ec5852e", + "runtime_commit": "f2c8b88f16f82517bd8fce118bacf63704b0a1f5", + "files": [ + { + "path": "README.md", + "bytes": 6889, + "sha256": "c6a9f5b7d451f03f48c4f54cec7b03d60ff3032e2df3eabfab2cfcb604072e00" + }, + { + "path": "methods/receive_retained_gallery.py", + "bytes": 6731, + "sha256": "a83e1abed7c773b2692d7983873d9aa852603548e9c6870d85ea27ad19fb9b3a" + }, + { + "path": "qualification/baseline-numeric-receipt.json", + "bytes": 8521, + "sha256": "8e9f7cb7a8ce219b4fea8090cff5e1c602b6d4fb100a6d011983594206e3ef29" + }, + { + "path": "qualification/containment-before-process.json", + "bytes": 673, + "sha256": "851c7b999ddd25e48b0a6d22331b3faee7a2e6b192c71e558b36ed40b4a06305" + }, + { + "path": "qualification/containment-before.log", + "bytes": 1714, + "sha256": "9fd91209a85b67b353c2612935a7f63714ee0af61e1339b1b3bd3e951e87f7b9" + }, + { + "path": "qualification/license-sparse-process.json", + "bytes": 511, + "sha256": "5d0bee53999ec8db51dd2795bbf5144a28905168bcad00be5731c05941917999" + }, + { + "path": "qualification/native-final-process.json", + "bytes": 565, + "sha256": "62bcd05fccbc28aa445e7c16428c1645f8bb4afb0176bf9ea3d4918839f225e5" + }, + { + "path": "qualification/native-final.log", + "bytes": 98, + "sha256": "0ffb40a7e62bd6693371ecb7ae3f0f55144cadcc2b7f232fab52e0168e397b14" + }, + { + "path": "qualification/native-initial-process.json", + "bytes": 575, + "sha256": "af1439171aaea7e19df7ba9ca98088ae68116294b9d3c3eab6c4ed8016e6f861" + }, + { + "path": "qualification/native-initial.log", + "bytes": 98, + "sha256": "3000927c23fb697a948f80ed8a877aab76ee6ed4d52d4ad2dda14c7fa0e10692" + }, + { + "path": "qualification/retained-final-process.json", + "bytes": 945, + "sha256": "796690c8451c32918da55e7db11c1d6401c3409dcd19bfb3f20d5986b68f84e1" + }, + { + "path": "qualification/retained-final-receipt.json", + "bytes": 11542, + "sha256": "d65d3bbea6ce187feb5c6aa8af97c65141c12a11419caa5e6cdb0133ee879ccd" + }, + { + "path": "qualification/retained-initial-process.json", + "bytes": 436, + "sha256": "51c6073a4e8b1f9342114efbc9adca236c704d162423136c875fa1f719f66725" + }, + { + "path": "qualification/retained-initial-receipt.json", + "bytes": 11542, + "sha256": "1d7fd41d984c4c62e302afc9f3050481985363408b8ddf6e3debf23cf9ed1ecd" + }, + { + "path": "source-input.json", + "bytes": 928, + "sha256": "35355ac0c22a65b264bbe4985a6a52d2fb783513ee840b70cec612e6f92dc206" + }, + { + "path": "visual/legacy-flat-figure.png", + "bytes": 27026, + "sha256": "b6431cac7a7ec09e4f53e476274ada0f6a92e1e400f9ca4fe6e920ddaac612c5" + }, + { + "path": "visual/legacy-linked-plots.png", + "bytes": 50152, + "sha256": "ebb6d1914c041ef2717f4498203635350d37a84a369b996bb24360b5e7d8352b" + }, + { + "path": "visual/numeric-channel.png", + "bytes": 39590, + "sha256": "24dc1f0a7372d5faa63bfaf63b3d3c78ef623f06129958391016893f3f2dfc82" + } + ] +} diff --git a/docs/evidence/nested-figure-gallery-401c5d17da79/current-main70.json b/docs/evidence/nested-figure-gallery-401c5d17da79/current-main70.json new file mode 100644 index 00000000..fd22a838 --- /dev/null +++ b/docs/evidence/nested-figure-gallery-401c5d17da79/current-main70.json @@ -0,0 +1,73 @@ +{ + "current_parent": "70f34e3b982523b544a9370d2316a1b69d79bd70", + "current_tree": "1537621f793d5d5c9b331f3c4d37a79a4af824b7", + "original_author_head": "ca4009e9154c60bcaa7a7447a74010735bbbf99d", + "original_runtime_head": "f2c8b88f16f82517bd8fce118bacf63704b0a1f5", + "merge_base": "3e3ecc5ecc1cfc79c79901eb5cffe10b0ec5852e", + "merge_method": "Native git merge-tree with explicitly verified canonical merge base; true current and authored commits remain the merge parents.", + "merge_base_verification": { + "source": "GitHub compare 3e3ecc5...70f34e3", + "status": "ahead", + "ahead_by": 11, + "behind_by": 0, + "merge_base_commit": "3e3ecc5ecc1cfc79c79901eb5cffe10b0ec5852e" + }, + "shallow_boundaries": [ + "3e3ecc5ecc1cfc79c79901eb5cffe10b0ec5852e", + "70f34e3b982523b544a9370d2316a1b69d79bd70" + ], + "conflicts_resolved": [ + { + "path": "docs/design/research/PROGRESS.md", + "rule": "Preserve the entire current document byte-for-byte, then append the exact owned entry.", + "current_blob": "80a94151bf978fb077bc323dfdf223a91dbe3254", + "resolved_blob": "b39d239a7e2262d268f7881c375e2d87652b78c9", + "owned_entry_sha256": "f47036c03099077053fa8502677d1246217840e7afa6bc3b8da493e91d09880b" + } + ], + "gallery": { + "current_blob": "2d6cbf65e20a9ec813254f380b51cebe203647b4", + "authored_blob": "3a7291ccd69d94d3b93402ab33d96639f2847149", + "combined_blob": "28e907de7c7c9a7945249796b61b325853f6de88", + "combined_sha256": "002327b8e6303412269c0ca8c4a105d9e8eeb96491eec0836e39ce199e2c18fd", + "preserved_export_additions": 5 + }, + "unchanged_export_modules": { + "desktop/capture_desktop/analysis_figure_export.py": "3c7b5c2be3639b6086551eb8d2dda18aa1507b44", + "desktop/capture_desktop/widgets_figure_export.py": "de619492f9b360608c58ecd04002def52be5f7a0" + }, + "original_receipts": "Original 7 native tests, 15 retained-output checks and 10 independent history checks remain pinned to c3837c72 on their recorded pre-export inputs; they are not relabeled as current-composition acceptance.", + "current_receiving": { + "qualified_runtime_tree": "fc62b7c016d6be53dd017094a99f6c89cca8a172", + "gallery_candidate_head": "75445bc38e0f3287691772d43d5ce392c90a1883", + "history_published_commit": "6cfe01672fd66b5b598cf73eb4502456ec333b35", + "history_screen_blob": "6893f119593f8ff6551167efcb1939d014a081e6", + "passed": 14, + "failed": 0, + "exit_code": 0, + "method": "QApplication.exec/QTimer, two real Saved analysis Open clicks around the existing result-clear hook, actual current gallery/export classes and original PNG pixels; no pipeline, export write or fixture creation", + "limits": "Changed current export/gallery constructor, load and clear composition only; no export write, numerical/pipeline computation, owner direct-gallery suite, complete history/scope suite, Windows MainWindow or installed-product result. This is an actual Linux Qt component run.", + "runtime": { + "python": "3.12.14 (main, Aug 25 2026, 14:00:49) [Clang 22.1.3 ]", + "pyside6": "6.11.2" + }, + "durable_packet": "/Users/me/hamon/estate-401c5d17da79/capturesuite-gallery-current70-independent", + "exact_files": { + "receipt.json": "2c98e64001176a3fc913ebd0379ef7e7412d0a4d1f4dd03b72efeb4bebef9db0", + "receive_history_gallery_current_final.py": "7cad1bbcfc46239137366a3a6fc3e26d4c3419e4d544eed057c06f6e2ad4da5d", + "current-module-inputs-sealed.json": "502c6065bb866b385476f15657f16ce7b081067c5457128c6e35eedae0330401", + "CHECKPOINT.json": "6d2b586a833e3bd9d76b14a9b4a67bef1e09c29f82476e68cd7ecdfbaa13da0f" + }, + "reviewed_frame": { + "history-numeric-current-export.png": { + "bytes": 202367, + "height": 820, + "sha256": "943128f143e6348c9bb1c59d5f329c36486f249bf78d5ad64157ebdc71613fb2", + "width": 1280 + } + }, + "source_note": "This metadata-only successor preserves every qualified runtime and test byte. Current acceptance belongs to the recorded effective runtime tree, including the separate PR71 history input." + }, + "source_tree_before_metadata": "38a94b0817d8976ad4b8f19665f85c68f753e237", + "receiving_candidate_head": "75445bc38e0f3287691772d43d5ce392c90a1883" +} diff --git a/docs/evidence/nested-figure-gallery-401c5d17da79/methods/receive_retained_gallery.py b/docs/evidence/nested-figure-gallery-401c5d17da79/methods/receive_retained_gallery.py new file mode 100644 index 00000000..dc89ef00 --- /dev/null +++ b/docs/evidence/nested-figure-gallery-401c5d17da79/methods/receive_retained_gallery.py @@ -0,0 +1,187 @@ +# SPDX-License-Identifier: GPL-3.0-only +"""Receive the gallery against retained real analysis outputs, without generating jobs.""" + +from __future__ import annotations + +import argparse +import base64 +import hashlib +import json +import resource +import sys +import time +import traceback +from pathlib import Path + +parser = argparse.ArgumentParser(description=__doc__) +parser.add_argument("--source-root", type=Path, required=True) +parser.add_argument("--numeric-job", type=Path, required=True) +parser.add_argument("--legacy-job", type=Path, required=True) +args = parser.parse_args() +resource.setrlimit(resource.RLIMIT_CORE, (0, 0)) +sys.path.insert(0, str(args.source_root / "desktop")) + +from PySide6 import __version__ as qt_version +from PySide6.QtCore import QBuffer, QIODevice, QTimer +from PySide6.QtGui import QImage +from PySide6.QtWidgets import QApplication + +from capture_desktop import theme +from capture_desktop.widgets_analysis_plots import FigureGallery + +started = time.monotonic() +checks = [] +frames = {} +failures = [] + + +def hashes(root): + return { + path.relative_to(root).as_posix(): hashlib.sha256(path.read_bytes()).hexdigest() + for path in sorted(root.rglob("*")) if path.is_file() + } + + +def check(name, condition): + checks.append({"name": name, "passed": bool(condition)}) + if not condition: + raise AssertionError(name) + + +def pixels(image): + image = image.convertToFormat(QImage.Format.Format_RGBA8888) + return (image.width(), image.height(), bytes(image.constBits())) + + +packages = {name: job.parents[2] for name, job in + (("numeric", args.numeric_job), ("legacy", args.legacy_job))} +before_packages = {name: hashes(path) for name, path in packages.items()} +source_paths = [args.source_root / relative for relative in ( + "desktop/capture_desktop/widgets_analysis_plots.py", + "desktop/capture_desktop/theme.py", + "tests/ui/test_analysis_nested_gallery.py", +)] +before_sources = {str(path): hashlib.sha256(path.read_bytes()).hexdigest() + for path in source_paths} +app = QApplication([]) +theme.apply_theme(app, setting="dark") +gallery = FigureGallery() +gallery.resize(1200, 820) +gallery.setWindowTitle("CaptureSuite saved analysis gallery") +gallery.show() +observed = {} + + +def invoke(callback): + try: + callback() + except Exception: + failures.append(traceback.format_exc()) + app.exit(1) + + +def later(callback): + QTimer.singleShot(100, lambda: invoke(callback)) + + +def snapshot(name): + image = gallery.grab().toImage() + buffer = QBuffer() + buffer.open(QIODevice.OpenModeFlag.WriteOnly) + if not image.save(buffer, "PNG"): + raise AssertionError("Native widget frame encoding failed") + data = bytes(buffer.data()) + frames[name] = { + "png_base64": base64.b64encode(data).decode(), + "bytes": len(data), "sha256": hashlib.sha256(data).hexdigest(), + "width": image.width(), "height": image.height(), + } + + +def receive_job(name, job, expected_titles): + tabs = gallery._tabs + titles = [tabs.tabText(i) for i in range(tabs.count())] + tips = [tabs.tabToolTip(i) for i in range(1, tabs.count())] + check(f"{name}: exact saved figure tabs", titles == ["Sync", *expected_titles]) + pngs = sorted(path for path in (job / "figures").rglob("*.png") + if path.relative_to(job / "figures") != Path("sync_dashboard.png")) + check(f"{name}: exact path identity", tips == [ + path.relative_to(job / "figures").as_posix() for path in pngs]) + check(f"{name}: all native image pixels equal saved PNGs", all( + pixels(tabs.widget(i).widget().pixmap().toImage()) == pixels(QImage(str(path))) + for i, path in enumerate(pngs, 1))) + doc = json.loads((job / "figures/sync_dashboard_series.json").read_text()) + plots = gallery._sync._linked + check(f"{name}: native linked series count", len(plots) == len(doc["series"])) + check(f"{name}: saved plot samples remain exact", all( + plot.listDataItems()[0].getData()[1].tolist() == row["y"] + for plot, row in zip(plots, doc["series"], strict=True))) + observed[name] = { + "job": str(job), "tabs": titles, "tooltips": tips, + "linked_series_count": len(plots), + "saved_png_sizes": [[QImage(str(p)).width(), QImage(str(p)).height()] for p in pngs], + } + + +def numeric_loaded(): + receive_job("numeric", args.numeric_job, [ + "lsl / numeric.stream / channel 0", "lsl / numeric.stream / channel 1"]) + gallery._tabs.setCurrentIndex(1) + later(numeric_visible) + + +def numeric_visible(): + check("numeric: selected native PNG is visible", + gallery._tabs.currentWidget().widget().isVisible()) + snapshot("numeric-channel.png") + gallery.load_job_dir(args.legacy_job) + gallery._tabs.setCurrentIndex(0) + later(legacy_loaded) + + +def legacy_loaded(): + receive_job("legacy", args.legacy_job, [ + "emg sim.emg.main channels"[:24], "imu sim.imu.upper accel"[:24]]) + check("legacy: both linked plot widgets are visible", + all(plot.isVisible() for plot in gallery._sync._linked)) + snapshot("legacy-linked-plots.png") + gallery._tabs.setCurrentIndex(2) + later(legacy_visible) + + +def legacy_visible(): + check("legacy: selected flat PNG is visible", + gallery._tabs.currentWidget().widget().isVisible()) + snapshot("legacy-flat-figure.png") + check("all saved and raw package bytes remain exact", + {name: hashes(path) for name, path in packages.items()} == before_packages) + check("all executed gallery/source bytes remain exact", { + str(path): hashlib.sha256(path.read_bytes()).hexdigest() + for path in source_paths + } == before_sources) + app.quit() + + +def begin(): + gallery.load_job_dir(args.numeric_job) + later(numeric_loaded) + + +QTimer.singleShot(0, lambda: invoke(begin)) +QTimer.singleShot(15_000, lambda: invoke(lambda: check("native event-loop deadline", False))) +exit_code = app.exec() +gallery.close() +receipt = { + "method": "QApplication.exec with QTimer scheduling; retained real jobs; no writer or pipeline runs", + "canonical_base": "3e3ecc5ecc1cfc79c79901eb5cffe10b0ec5852e", + "python": sys.version, "pyside6": qt_version, + "exit": exit_code, "elapsed_seconds": round(time.monotonic() - started, 3), + "checks": checks, "passed": sum(row["passed"] for row in checks), + "failures": failures, "observed": observed, + "source_hashes": before_sources, + "package_hashes_before_and_after": before_packages, + "frames": {name: {key: value for key, value in frame.items() if key != "png_base64"} + for name, frame in frames.items()}, +} +print(json.dumps({"receipt": receipt, "frames": frames})) +sys.exit(exit_code or bool(failures)) diff --git a/docs/evidence/nested-figure-gallery-401c5d17da79/qualification/baseline-numeric-receipt.json b/docs/evidence/nested-figure-gallery-401c5d17da79/qualification/baseline-numeric-receipt.json new file mode 100644 index 00000000..bae5c434 --- /dev/null +++ b/docs/evidence/nested-figure-gallery-401c5d17da79/qualification/baseline-numeric-receipt.json @@ -0,0 +1,214 @@ +{ + "canonical_main": "0ed1ccaa023a5327495565d59e1dd0b28b2ee5bd", + "author_source": "37443f0d4d5ffa684b5423d58501856cadbe0655", + "runtime_tree": "210832e8a07ccc6dff8ead12e9bf45dde3b31652", + "checks": [ + { + "name": "current accepted numeric pipeline creates two real channel figures", + "passed": true + }, + { + "name": "history explicitly selects the retained numeric job", + "passed": true + }, + { + "name": "inspector receives that saved manifest", + "passed": true + }, + { + "name": "history gallery presents both existing numeric channel figures", + "passed": false + }, + { + "name": "unchanged direct gallery reproduces the same omitted numeric figures", + "passed": true + }, + { + "name": "native history browsing starts no computation thread", + "passed": true + }, + { + "name": "native viewing preserves every generated and captured byte", + "passed": true + } + ], + "errors": [], + "method_sha256": "c6d9c3aaf73e1cfef62c86dc36491440d3d6c6001996f149e2b978c97e2959d8", + "source_inputs_sha256": "2c9e35a372b29e6f4d93e5dd7a844b09fe49129fbf89a5c6e569f984aedaee6b", + "figure_paths": [ + "figures/numeric/source-6c736c/stream-6e756d657269632e73747265616d/channel_0.png", + "figures/numeric/source-6c736c/stream-6e756d657269632e73747265616d/channel_1.png" + ], + "job_manifest": { + "analysisGrids": [], + "captureAnalysisVersion": "0.1.0", + "createdUtc": "2026-10-08T13:22:43Z", + "errors": [], + "evalWindowCount": null, + "featureTables": [ + { + "featureSchemaVersion": 1, + "relativePath": "features/numeric/source-6c736c/stream-6e756d657269632e73747265616d/windows.parquet", + "rows": 3 + } + ], + "gapPolicy": "mask", + "gapSummary": { + "closed": 0, + "maskedNs": 0, + "open": 0, + "validFraction": null + }, + "jobId": "retained-numeric", + "kinematicsRows": null, + "manifestSha256": "399b408a7bcb1cbee8062a926f52b2ceff553fdbf4504d92a629b83898eb4b60", + "mlBundleWindowCount": null, + "modalities": [ + "eeg" + ], + "outputs": [ + { + "bytes": 254, + "kind": "params", + "relativePath": "params.json", + "sha256": "962d5067fb396fca7a5d207bae2aeff4ea16f3218396824de0da670f16b67dc3" + }, + { + "bytes": 1127, + "kind": "qc_json", + "relativePath": "reports/qc.json", + "sha256": "6a7e1c4191f43ce87c04344f81d4b4ffa61b2fa383de413650bdcc02a21b3ba2" + }, + { + "bytes": 2214, + "kind": "qc_html", + "relativePath": "reports/qc.html", + "sha256": "43b9cfbc29c185464e85873ac6c4bfd45a0fa3d45f259d7ea59dcae9464625e5" + }, + { + "bytes": 5358, + "kind": "feature_parquet", + "relativePath": "features/numeric/source-6c736c/stream-6e756d657269632e73747265616d/windows.parquet", + "sha256": "b25e995662e343e5660be848fac61eac15dd63d904ea1fa8d4b58fe66dc68b84" + }, + { + "bytes": 307, + "kind": "feature_csv", + "relativePath": "features/numeric/source-6c736c/stream-6e756d657269632e73747265616d/windows.csv", + "sha256": "9cae194fe5eabbdd3d804b734e609ea732d05f9b5885f6e51dcea9f5840230fe" + }, + { + "bytes": 38048, + "kind": "figure", + "relativePath": "figures/numeric/source-6c736c/stream-6e756d657269632e73747265616d/channel_0.png", + "sha256": "255a352977baf12c5714f71c327cac9ec6fe96377378e7d789433de6335bc73a" + }, + { + "bytes": 38330, + "kind": "figure", + "relativePath": "figures/numeric/source-6c736c/stream-6e756d657269632e73747265616d/channel_1.png", + "sha256": "ae7fd0d484e1dd7756a3a0c599de8aea09ede34d0ad1644775c0b95bce3f6195" + }, + { + "bytes": 2691, + "kind": "feature_schema", + "relativePath": "features/_schema.json", + "sha256": "ea7b96fa667e83b0379515745ee23e659bd640497378b04c267da593d584e264" + }, + { + "bytes": 32213, + "kind": "figure", + "relativePath": "figures/sync_dashboard.png", + "sha256": "e801135335d3a6e50353d82b039a14217f7fe6f931a1f9daa1f37de3ab0e6b02" + }, + { + "bytes": 540, + "kind": "sync_series", + "relativePath": "figures/sync_dashboard_series.json", + "sha256": "1bc0a860646508a6001aed0d312d42338f8b2e9c93592cf5adc7dbeab2277554" + }, + { + "bytes": 4166, + "kind": "manifest", + "relativePath": "job_manifest.json", + "sha256": "a3fa5a3115667361cbaa2ad0b701b50f37a9096b8f5391f9bd7f846bce2447ae" + } + ], + "packagePath": "/dev/shm/hamon-401c5d17da79-capture-history-pr/latest-boundary/numeric-run/numeric.mmsession", + "packageState": "sealed", + "paramsDigest": "fbbd87f4d0bdf05be752987d8e20dfb29df32e3da588706e698f21aa5567f604", + "pluginIds": [ + "emg.envelope.v1", + "imu.kinematics.v1", + "radar.rd_energy.v1", + "radar_doppler.mag.v1", + "video.timing_qc.v1", + "numeric.basic.v1", + "test.dummy.feature.v1" + ], + "pluginManifestVersion": "1.0.0", + "poseJobId": null, + "poseModelId": null, + "poseTables": [], + "schemaId": "capture.analysis_job/1", + "sessionId": "history.numeric.current", + "sourcesSelected": [ + "lsl" + ], + "status": "completed_with_warnings", + "syncAnchorsApplied": { + "anchors": [], + "applied": false + }, + "timeRange": { + "checkpointIds": [], + "endSessionNs": 4611686018427387903, + "mode": "full", + "startSessionNs": -4611686018427387903 + }, + "tooling": { + "captureAnalysis": "0.1.0", + "matplotlib": "3.11.2", + "numpy": "2.5.3", + "pandas": "3.0.6", + "platform": "Linux-6.18.44-x86_64-with-glibc2.39", + "python": "3.12.14", + "scipy": "1.18.1" + }, + "warnings": [ + "package state is 'sealed' (prefer finalized)", + "package duration_ns is unknown/zero \u2014 analysis uses an open time window (integrity entries lack endSessionTimeNs)" + ] + }, + "history_gallery_tabs": [ + "Sync" + ], + "direct_gallery_tabs": [ + "Sync" + ], + "event_loop_exit": 0, + "pyside6": "6.11.2", + "python": "3.12.14 (main, Aug 25 2026, 14:00:49) [Clang 22.1.3 ]", + "package_hashes": { + "manifest.json": "399b408a7bcb1cbee8062a926f52b2ceff553fdbf4504d92a629b83898eb4b60", + "processing/jobs/retained-numeric/features/_schema.json": "ea7b96fa667e83b0379515745ee23e659bd640497378b04c267da593d584e264", + "processing/jobs/retained-numeric/features/numeric/source-6c736c/stream-6e756d657269632e73747265616d/windows.csv": "9cae194fe5eabbdd3d804b734e609ea732d05f9b5885f6e51dcea9f5840230fe", + "processing/jobs/retained-numeric/features/numeric/source-6c736c/stream-6e756d657269632e73747265616d/windows.parquet": "b25e995662e343e5660be848fac61eac15dd63d904ea1fa8d4b58fe66dc68b84", + "processing/jobs/retained-numeric/figures/numeric/source-6c736c/stream-6e756d657269632e73747265616d/channel_0.png": "255a352977baf12c5714f71c327cac9ec6fe96377378e7d789433de6335bc73a", + "processing/jobs/retained-numeric/figures/numeric/source-6c736c/stream-6e756d657269632e73747265616d/channel_1.png": "ae7fd0d484e1dd7756a3a0c599de8aea09ede34d0ad1644775c0b95bce3f6195", + "processing/jobs/retained-numeric/figures/sync_dashboard.png": "e801135335d3a6e50353d82b039a14217f7fe6f931a1f9daa1f37de3ab0e6b02", + "processing/jobs/retained-numeric/figures/sync_dashboard_series.json": "1bc0a860646508a6001aed0d312d42338f8b2e9c93592cf5adc7dbeab2277554", + "processing/jobs/retained-numeric/job_manifest.json": "32dd2883bc55717ef813f36930eed5598124f27fa2a9a7a9817e750cd59bcb6d", + "processing/jobs/retained-numeric/logs/job.log": "7edc38094b8619545017aa8f12c4d0179ab43474343e25d483918f32d48b778a", + "processing/jobs/retained-numeric/params.json": "962d5067fb396fca7a5d207bae2aeff4ea16f3218396824de0da670f16b67dc3", + "processing/jobs/retained-numeric/reports/qc.html": "43b9cfbc29c185464e85873ac6c4bfd45a0fa3d45f259d7ea59dcae9464625e5", + "processing/jobs/retained-numeric/reports/qc.json": "6a7e1c4191f43ce87c04344f81d4b4ffa61b2fa383de413650bdcc02a21b3ba2", + "sources/lsl/streams/numeric/segments/000000.mcap": "f3df8e3cc95f76462c502935aad5abafd4392ed3224c239775650c5b49bcd18f", + "sources/lsl/streams/numeric/stream.json": "1adfb22cb81843c0e5bef319c9c2268ea2746e930232f6d89e154d133e0fa885" + }, + "fixture_helper_sha256": "43369bd0fea48d2c8b7dee1d8128b3bb131b508b7b0a14512fc457fcfdb0ba3c", + "source_unchanged": true, + "exit_code": 1, + "passed": 6, + "failed": 1 +} diff --git a/docs/evidence/nested-figure-gallery-401c5d17da79/qualification/containment-before-process.json b/docs/evidence/nested-figure-gallery-401c5d17da79/qualification/containment-before-process.json new file mode 100644 index 00000000..6ff626be --- /dev/null +++ b/docs/evidence/nested-figure-gallery-401c5d17da79/qualification/containment-before-process.json @@ -0,0 +1,18 @@ +{ + "command": [ + "/workspace/scratch/234cae4aee53/capturesuite-venv/bin/python", + "-m", + "pytest", + "tests/ui/test_analysis_nested_gallery.py::test_png_discovery_refuses_external_file_links_and_directories", + "-q", + "-ra", + "-p", + "no:cacheprovider", + "--basetemp=/dev/shm/capturesuite-gallery-401c5d17da79/tmp/containment-before" + ], + "exit": 1, + "seconds": 1.357, + "gallery_sha256": "852c9059d01fac9ba38edbe228e0920e8cf3298bb8e1a9d6610b148f6d1e7ffb", + "test_sha256": "727340556a0d8e4178b62157ba9680a59d1c43158abb1bf979b21be8c98c591f", + "expected_failure": "External PNG symlink still appears; directory named PNG is already excluded." +} diff --git a/docs/evidence/nested-figure-gallery-401c5d17da79/qualification/containment-before.log b/docs/evidence/nested-figure-gallery-401c5d17da79/qualification/containment-before.log new file mode 100644 index 00000000..d78c4d49 --- /dev/null +++ b/docs/evidence/nested-figure-gallery-401c5d17da79/qualification/containment-before.log @@ -0,0 +1,34 @@ +F [100%] +=================================== FAILURES =================================== +________ test_png_discovery_refuses_external_file_links_and_directories ________ + +qapp = +tmp_path = PosixPath('/dev/shm/capturesuite-gallery-401c5d17da79/tmp/containment-before/test_png_discovery_refuses_ext0') + + def test_png_discovery_refuses_external_file_links_and_directories(qapp, tmp_path): + from capture_desktop.widgets_analysis_plots import FigureGallery + + job = tmp_path / "job" + outside = tmp_path / "external.png" + _png(outside, "#aa1122") + _png(job / "figures/nested/good.png", "#22aa55") + foreign = job / "figures/foreign.png" + try: + foreign.symlink_to(outside) + except OSError as exc: + pytest.skip(f"This filesystem cannot create the symlink fixture: {exc}") + (job / "figures/not_a_file.png").mkdir() + before = _hashes(tmp_path) + gallery = FigureGallery() + gallery.load_job_dir(job) +> assert _titles(gallery) == ["Sync", "nested / good"] +E AssertionError: assert ['Sync', 'for...ested / good'] == ['Sync', 'nested / good'] +E +E At index 1 diff: 'foreign' != 'nested / good' +E Left contains one more item: 'nested / good' +E Use -v to get more diff + +tests/ui/test_analysis_nested_gallery.py:173: AssertionError +=========================== short test summary info ============================ +FAILED tests/ui/test_analysis_nested_gallery.py::test_png_discovery_refuses_external_file_links_and_directories +1 failed in 0.87s diff --git a/docs/evidence/nested-figure-gallery-401c5d17da79/qualification/license-sparse-process.json b/docs/evidence/nested-figure-gallery-401c5d17da79/qualification/license-sparse-process.json new file mode 100644 index 00000000..fa9027df --- /dev/null +++ b/docs/evidence/nested-figure-gallery-401c5d17da79/qualification/license-sparse-process.json @@ -0,0 +1,12 @@ +{ + "command": [ + "/Applications/Xcode.app/Contents/Developer/usr/bin/python3", + "tools/check_licenses.py", + "--enforce-spdx" + ], + "exit": 0, + "stdout": "license check OK\n", + "stderr": "", + "scope": "Exact required license structure and all materialized source/evidence in this sparse author checkout; not the complete canonical repository.", + "runtime_qualification": "Previously frozen Linux Qt tests and receiving only; this Mac step seals source and runs the bounded static license gate." +} diff --git a/docs/evidence/nested-figure-gallery-401c5d17da79/qualification/native-final-process.json b/docs/evidence/nested-figure-gallery-401c5d17da79/qualification/native-final-process.json new file mode 100644 index 00000000..56c8f088 --- /dev/null +++ b/docs/evidence/nested-figure-gallery-401c5d17da79/qualification/native-final-process.json @@ -0,0 +1,18 @@ +{ + "command": [ + "/workspace/scratch/234cae4aee53/capturesuite-venv/bin/python", + "-m", + "pytest", + "tests/ui/test_analysis_nested_gallery.py", + "-q", + "-ra", + "-p", + "no:cacheprovider", + "--basetemp=/dev/shm/capturesuite-gallery-401c5d17da79/tmp/native-final" + ], + "exit": 0, + "seconds": 1.373, + "canonical_base": "3e3ecc5ecc1cfc79c79901eb5cffe10b0ec5852e", + "gallery_sha256": "c3837c72285b37e486be38933ad73950ae91ba10d335ff5e1c3f37ef5d08aa26", + "test_sha256": "727340556a0d8e4178b62157ba9680a59d1c43158abb1bf979b21be8c98c591f" +} diff --git a/docs/evidence/nested-figure-gallery-401c5d17da79/qualification/native-final.log b/docs/evidence/nested-figure-gallery-401c5d17da79/qualification/native-final.log new file mode 100644 index 00000000..71d35589 --- /dev/null +++ b/docs/evidence/nested-figure-gallery-401c5d17da79/qualification/native-final.log @@ -0,0 +1,2 @@ +....... [100%] +7 passed in 0.80s diff --git a/docs/evidence/nested-figure-gallery-401c5d17da79/qualification/native-initial-process.json b/docs/evidence/nested-figure-gallery-401c5d17da79/qualification/native-initial-process.json new file mode 100644 index 00000000..d52754ea --- /dev/null +++ b/docs/evidence/nested-figure-gallery-401c5d17da79/qualification/native-initial-process.json @@ -0,0 +1,18 @@ +{ + "command": [ + "/workspace/scratch/234cae4aee53/capturesuite-venv/bin/python", + "-m", + "pytest", + "tests/ui/test_analysis_nested_gallery.py", + "-q", + "-ra", + "-p", + "no:cacheprovider", + "--basetemp=/dev/shm/capturesuite-gallery-401c5d17da79/tmp/native-focused" + ], + "exit": 0, + "elapsed_seconds": 1.186, + "canonical_base": "3e3ecc5ecc1cfc79c79901eb5cffe10b0ec5852e", + "gallery_sha256": "852c9059d01fac9ba38edbe228e0920e8cf3298bb8e1a9d6610b148f6d1e7ffb", + "test_sha256": "90477416f3efc70b436759eb56348d600b2b5b84f2f7f46ec6b4129c690b9d0a" +} diff --git a/docs/evidence/nested-figure-gallery-401c5d17da79/qualification/native-initial.log b/docs/evidence/nested-figure-gallery-401c5d17da79/qualification/native-initial.log new file mode 100644 index 00000000..20ada105 --- /dev/null +++ b/docs/evidence/nested-figure-gallery-401c5d17da79/qualification/native-initial.log @@ -0,0 +1,2 @@ +...... [100%] +6 passed in 0.79s diff --git a/docs/evidence/nested-figure-gallery-401c5d17da79/qualification/retained-final-process.json b/docs/evidence/nested-figure-gallery-401c5d17da79/qualification/retained-final-process.json new file mode 100644 index 00000000..34fee1f7 --- /dev/null +++ b/docs/evidence/nested-figure-gallery-401c5d17da79/qualification/retained-final-process.json @@ -0,0 +1,16 @@ +{ + "command": [ + "/workspace/scratch/234cae4aee53/capturesuite-venv/bin/python", + "/dev/shm/capturesuite-gallery-401c5d17da79/methods/receive_retained_gallery.py", + "--source-root", + "/dev/shm/capturesuite-gallery-401c5d17da79/source", + "--numeric-job", + "/dev/shm/hamon-401c5d17da79-capture-history-pr/latest-boundary/numeric-run/numeric.mmsession/processing/jobs/retained-numeric", + "--legacy-job", + "/dev/shm/hamon-401c5d17da79-capturesuite-receiving/fixtures-native/package-a.mmsession/processing/jobs/retained-prior" + ], + "process_exit": 0, + "process_seconds": 2.071, + "stderr": "This plugin does not support propagateSizeHints()\nThis plugin does not support propagateSizeHints()\nThis plugin does not support propagateSizeHints()\nThis plugin does not support propagateSizeHints()\nThis plugin does not support propagateSizeHints()\n", + "stdout_format": "JSON receipt and PNG frames, preserved separately" +} diff --git a/docs/evidence/nested-figure-gallery-401c5d17da79/qualification/retained-final-receipt.json b/docs/evidence/nested-figure-gallery-401c5d17da79/qualification/retained-final-receipt.json new file mode 100644 index 00000000..b32c9927 --- /dev/null +++ b/docs/evidence/nested-figure-gallery-401c5d17da79/qualification/retained-final-receipt.json @@ -0,0 +1,207 @@ +{ + "method": "QApplication.exec with QTimer scheduling; retained real jobs; no writer or pipeline runs", + "canonical_base": "3e3ecc5ecc1cfc79c79901eb5cffe10b0ec5852e", + "python": "3.12.14 (main, Aug 25 2026, 14:00:49) [Clang 22.1.3 ]", + "pyside6": "6.11.2", + "exit": 0, + "elapsed_seconds": 1.023, + "checks": [ + { + "name": "numeric: exact saved figure tabs", + "passed": true + }, + { + "name": "numeric: exact path identity", + "passed": true + }, + { + "name": "numeric: all native image pixels equal saved PNGs", + "passed": true + }, + { + "name": "numeric: native linked series count", + "passed": true + }, + { + "name": "numeric: saved plot samples remain exact", + "passed": true + }, + { + "name": "numeric: selected native PNG is visible", + "passed": true + }, + { + "name": "legacy: exact saved figure tabs", + "passed": true + }, + { + "name": "legacy: exact path identity", + "passed": true + }, + { + "name": "legacy: all native image pixels equal saved PNGs", + "passed": true + }, + { + "name": "legacy: native linked series count", + "passed": true + }, + { + "name": "legacy: saved plot samples remain exact", + "passed": true + }, + { + "name": "legacy: both linked plot widgets are visible", + "passed": true + }, + { + "name": "legacy: selected flat PNG is visible", + "passed": true + }, + { + "name": "all saved and raw package bytes remain exact", + "passed": true + }, + { + "name": "all executed gallery/source bytes remain exact", + "passed": true + } + ], + "passed": 15, + "failures": [], + "observed": { + "numeric": { + "job": "/dev/shm/hamon-401c5d17da79-capture-history-pr/latest-boundary/numeric-run/numeric.mmsession/processing/jobs/retained-numeric", + "tabs": [ + "Sync", + "lsl / numeric.stream / channel 0", + "lsl / numeric.stream / channel 1" + ], + "tooltips": [ + "numeric/source-6c736c/stream-6e756d657269632e73747265616d/channel_0.png", + "numeric/source-6c736c/stream-6e756d657269632e73747265616d/channel_1.png" + ], + "linked_series_count": 1, + "saved_png_sizes": [ + [ + 1650, + 420 + ], + [ + 1650, + 420 + ] + ] + }, + "legacy": { + "job": "/dev/shm/hamon-401c5d17da79-capturesuite-receiving/fixtures-native/package-a.mmsession/processing/jobs/retained-prior", + "tabs": [ + "Sync", + "emg sim.emg.main channel", + "imu sim.imu.upper accel" + ], + "tooltips": [ + "emg_sim.emg.main_channels.png", + "imu_sim.imu.upper_accel.png" + ], + "linked_series_count": 2, + "saved_png_sizes": [ + [ + 1650, + 540 + ], + [ + 1650, + 450 + ] + ] + } + }, + "source_hashes": { + "/dev/shm/capturesuite-gallery-401c5d17da79/source/desktop/capture_desktop/widgets_analysis_plots.py": "c3837c72285b37e486be38933ad73950ae91ba10d335ff5e1c3f37ef5d08aa26", + "/dev/shm/capturesuite-gallery-401c5d17da79/source/desktop/capture_desktop/theme.py": "c77f24e1afeb06400385bd0d535800f13dc15d972891e1ff8af504cbe5c818f3", + "/dev/shm/capturesuite-gallery-401c5d17da79/source/tests/ui/test_analysis_nested_gallery.py": "727340556a0d8e4178b62157ba9680a59d1c43158abb1bf979b21be8c98c591f" + }, + "package_hashes_before_and_after": { + "numeric": { + "manifest.json": "399b408a7bcb1cbee8062a926f52b2ceff553fdbf4504d92a629b83898eb4b60", + "processing/jobs/retained-numeric/features/_schema.json": "ea7b96fa667e83b0379515745ee23e659bd640497378b04c267da593d584e264", + "processing/jobs/retained-numeric/features/numeric/source-6c736c/stream-6e756d657269632e73747265616d/windows.csv": "9cae194fe5eabbdd3d804b734e609ea732d05f9b5885f6e51dcea9f5840230fe", + "processing/jobs/retained-numeric/features/numeric/source-6c736c/stream-6e756d657269632e73747265616d/windows.parquet": "b25e995662e343e5660be848fac61eac15dd63d904ea1fa8d4b58fe66dc68b84", + "processing/jobs/retained-numeric/figures/numeric/source-6c736c/stream-6e756d657269632e73747265616d/channel_0.png": "255a352977baf12c5714f71c327cac9ec6fe96377378e7d789433de6335bc73a", + "processing/jobs/retained-numeric/figures/numeric/source-6c736c/stream-6e756d657269632e73747265616d/channel_1.png": "ae7fd0d484e1dd7756a3a0c599de8aea09ede34d0ad1644775c0b95bce3f6195", + "processing/jobs/retained-numeric/figures/sync_dashboard.png": "e801135335d3a6e50353d82b039a14217f7fe6f931a1f9daa1f37de3ab0e6b02", + "processing/jobs/retained-numeric/figures/sync_dashboard_series.json": "1bc0a860646508a6001aed0d312d42338f8b2e9c93592cf5adc7dbeab2277554", + "processing/jobs/retained-numeric/job_manifest.json": "32dd2883bc55717ef813f36930eed5598124f27fa2a9a7a9817e750cd59bcb6d", + "processing/jobs/retained-numeric/logs/job.log": "7edc38094b8619545017aa8f12c4d0179ab43474343e25d483918f32d48b778a", + "processing/jobs/retained-numeric/params.json": "962d5067fb396fca7a5d207bae2aeff4ea16f3218396824de0da670f16b67dc3", + "processing/jobs/retained-numeric/reports/qc.html": "43b9cfbc29c185464e85873ac6c4bfd45a0fa3d45f259d7ea59dcae9464625e5", + "processing/jobs/retained-numeric/reports/qc.json": "6a7e1c4191f43ce87c04344f81d4b4ffa61b2fa383de413650bdcc02a21b3ba2", + "sources/lsl/streams/numeric/segments/000000.mcap": "f3df8e3cc95f76462c502935aad5abafd4392ed3224c239775650c5b49bcd18f", + "sources/lsl/streams/numeric/stream.json": "1adfb22cb81843c0e5bef319c9c2268ea2746e930232f6d89e154d133e0fa885" + }, + "legacy": { + "events/annotations.json": "37517e5f3dc66819f61f5a7bb8ace1921282415f10551d2defa5c3eb0985b570", + "events/checkpoints.json": "37517e5f3dc66819f61f5a7bb8ace1921282415f10551d2defa5c3eb0985b570", + "events/sync_anchors.json": "37517e5f3dc66819f61f5a7bb8ace1921282415f10551d2defa5c3eb0985b570", + "integrity.json": "2fb4194b22d4b1c373f25f9ecab51d0c80e14f42a52f53293fd727ce5418f140", + "manifest.json": "6cc54886cc63fa1263a4077fec322454fdfa133a408836a75451fd77eb7c5243", + "processing/jobs/late-baseline-actual-qc/job_manifest.json": "bbb88191cb522d3314139b6ebcb4cd2e6b8aa6c6b7df362d0653a0a75dcba7bc", + "processing/jobs/late-baseline-actual-qc/logs/job.log": "59f307f1af8f7e20fe908e17afdf3047f6d7eda3d04d2d7e5153f258b6377d37", + "processing/jobs/late-baseline-actual-qc/params.json": "88f55fe8dddb0794c98f693dd21fdd7764a6bac45203e11ba52eab3ebaa40fc3", + "processing/jobs/late-baseline-actual-qc/reports/qc.html": "db815562d270dc133bce019f0c0791bea4e9af52fc62ce7107a41ea6a8485d20", + "processing/jobs/late-baseline-actual-qc/reports/qc.json": "2a1addc8accb001643f81a4b1061458f8fa27de6ffcc157fbed5ddb837c9cf27", + "processing/jobs/late-candidate-actual-qc/job_manifest.json": "d63428766698ba71d56f9797340cc2e4f870cded0e04708b98ee991200e5d88e", + "processing/jobs/late-candidate-actual-qc/logs/job.log": "c2b223c3686c245380c6b3788d45deb8f4a56ca9d420039af2ff598f6eb66cc1", + "processing/jobs/late-candidate-actual-qc/params.json": "9aad1ac26d07fdbf51e882ad70c97ae15942b3057755083b0a8b063506d23fe8", + "processing/jobs/late-candidate-actual-qc/reports/qc.html": "db815562d270dc133bce019f0c0791bea4e9af52fc62ce7107a41ea6a8485d20", + "processing/jobs/late-candidate-actual-qc/reports/qc.json": "2a1addc8accb001643f81a4b1061458f8fa27de6ffcc157fbed5ddb837c9cf27", + "processing/jobs/late-native-candidate-qc/job_manifest.json": "995796fd6b5f52e89ea25a0c45fd769b6352b5f2b1d8984b250971c691ad8658", + "processing/jobs/late-native-candidate-qc/logs/job.log": "b9c0d4a5e6fc748c0a4b60187926f7e9885a2a386a7ed8e85c37a261e053a87d", + "processing/jobs/late-native-candidate-qc/params.json": "e09345ba9ebd7b6f59a9b70cff3af7406c1424237cb5e27a05a80f755b270cb9", + "processing/jobs/late-native-candidate-qc/reports/qc.html": "2917196a7446847355f7443ab5bde8be96dbc71e2b48927f4e60fe064affce6e", + "processing/jobs/late-native-candidate-qc/reports/qc.json": "2d98f837e78a3866402a3f4f9dc765a262168f36d8fe8b2235e02ee17efd3551", + "processing/jobs/retained-prior/features/_schema.json": "c80f7d1e05378bf2399098e9887fc463edda22e366236eab3e9b1b0526d1f0f0", + "processing/jobs/retained-prior/features/emg/sim.emg.main/windows.csv": "0c9b8016e1295976eb10eabdb913efff752cf9936bf4a7cab1d3107a85ca97ff", + "processing/jobs/retained-prior/features/emg/sim.emg.main/windows.parquet": "c5d6d1727acd151ca0b1430eecb0dd0491fe2863a9f7c163d7524bfed584e60f", + "processing/jobs/retained-prior/features/imu/sim.imu.upper/windows.csv": "62212faf4179e9050c4d7a2e3530a461c70d0e56b227138e31b0c273bb21a277", + "processing/jobs/retained-prior/features/imu/sim.imu.upper/windows.parquet": "ff4ca0fbfed45e13e95f73d03d8ba56ce0f8305868012ecb5101df277a449ba9", + "processing/jobs/retained-prior/figures/emg_sim.emg.main_channels.png": "4c7a4aee76c4895cf99e38874de271e83a52c0e7389093c14a93344e9dc43853", + "processing/jobs/retained-prior/figures/imu_sim.imu.upper_accel.png": "8cc603bf604d8925ba13be2c77e0bd8d8f8efbce9529e7d459a449fd61e6a8a4", + "processing/jobs/retained-prior/figures/sync_dashboard.png": "bda125c256b17dbd688ec825c2a5b9b8542f346ce95209faf15efadad5c78d48", + "processing/jobs/retained-prior/figures/sync_dashboard_series.json": "ba1181c30b0a3ab1b26b716e56bf0787f2e67aa4178cd511f0106486d04aa8e6", + "processing/jobs/retained-prior/job_manifest.json": "21471f1ee0cae441202b4b704c6cd1359558ac1bf27f077668508eb1368ae6e7", + "processing/jobs/retained-prior/logs/job.log": "3cf99c71a0e4e3046b791ad2c04e388adfe452959b315d8dd5df6d278a5aaf63", + "processing/jobs/retained-prior/params.json": "9c0e1ab18949727f29352f1a602ae65d74db48f8453a49faa72fbc95c518b35b", + "processing/jobs/retained-prior/reports/qc.html": "db815562d270dc133bce019f0c0791bea4e9af52fc62ce7107a41ea6a8485d20", + "processing/jobs/retained-prior/reports/qc.json": "2a1addc8accb001643f81a4b1061458f8fa27de6ffcc157fbed5ddb837c9cf27", + "sources/sim.emg.main/health/gaps.jsonl": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "sources/sim.emg.main/source.json": "4e7626e51bfb804c27f83bf98ee186a47ec9f36fec0cbd7863ea8ecb1ecfbd10", + "sources/sim.emg.main/streams/sim.emg.main.batch/segments/000000.mcap": "6f3b9bd4ce01238f122649a1139a290ea6193893938a95f3ac61dd61a447d997", + "sources/sim.emg.main/streams/sim.emg.main.batch/stream.json": "5307697f957309eaca816fa0e20c4799c900e2598a8acf66a59928aa83b305b2", + "sources/sim.imu.upper/source.json": "a6198f509edc557c1e1d8583a767a540962977751c80a1b6491e3d594b60c7a8", + "sources/sim.imu.upper/streams/sim.imu.upper.frames/segments/000000.mcap": "c477a0e0865086fbb4154c977def4d93ea5fb38cc098a4862c45b21b966014c9", + "sources/sim.imu.upper/streams/sim.imu.upper.frames/stream.json": "ec39026bed1b833d4decb0ef7b0efb94c5557a5647bc50addc060bef3a30d50d" + } + }, + "frames": { + "numeric-channel.png": { + "bytes": 39590, + "sha256": "24dc1f0a7372d5faa63bfaf63b3d3c78ef623f06129958391016893f3f2dfc82", + "width": 1200, + "height": 820 + }, + "legacy-linked-plots.png": { + "bytes": 50152, + "sha256": "ebb6d1914c041ef2717f4498203635350d37a84a369b996bb24360b5e7d8352b", + "width": 1200, + "height": 820 + }, + "legacy-flat-figure.png": { + "bytes": 27026, + "sha256": "b6431cac7a7ec09e4f53e476274ada0f6a92e1e400f9ca4fe6e920ddaac612c5", + "width": 1200, + "height": 820 + } + } +} diff --git a/docs/evidence/nested-figure-gallery-401c5d17da79/qualification/retained-initial-process.json b/docs/evidence/nested-figure-gallery-401c5d17da79/qualification/retained-initial-process.json new file mode 100644 index 00000000..4c318507 --- /dev/null +++ b/docs/evidence/nested-figure-gallery-401c5d17da79/qualification/retained-initial-process.json @@ -0,0 +1,6 @@ +{ + "process_exit": 0, + "process_seconds": 1.676, + "stderr": "This plugin does not support propagateSizeHints()\nThis plugin does not support propagateSizeHints()\nThis plugin does not support propagateSizeHints()\nThis plugin does not support propagateSizeHints()\nThis plugin does not support propagateSizeHints()\n", + "stdout_format": "JSON receipt and PNG frames, parsed without edits; receipt and frames preserved separately" +} diff --git a/docs/evidence/nested-figure-gallery-401c5d17da79/qualification/retained-initial-receipt.json b/docs/evidence/nested-figure-gallery-401c5d17da79/qualification/retained-initial-receipt.json new file mode 100644 index 00000000..8976597b --- /dev/null +++ b/docs/evidence/nested-figure-gallery-401c5d17da79/qualification/retained-initial-receipt.json @@ -0,0 +1,207 @@ +{ + "method": "QApplication.exec with QTimer scheduling; retained real jobs; no writer or pipeline runs", + "canonical_base": "3e3ecc5ecc1cfc79c79901eb5cffe10b0ec5852e", + "python": "3.12.14 (main, Aug 25 2026, 14:00:49) [Clang 22.1.3 ]", + "pyside6": "6.11.2", + "exit": 0, + "elapsed_seconds": 0.836, + "checks": [ + { + "name": "numeric: exact saved figure tabs", + "passed": true + }, + { + "name": "numeric: exact path identity", + "passed": true + }, + { + "name": "numeric: all native image pixels equal saved PNGs", + "passed": true + }, + { + "name": "numeric: native linked series count", + "passed": true + }, + { + "name": "numeric: saved plot samples remain exact", + "passed": true + }, + { + "name": "numeric: selected native PNG is visible", + "passed": true + }, + { + "name": "legacy: exact saved figure tabs", + "passed": true + }, + { + "name": "legacy: exact path identity", + "passed": true + }, + { + "name": "legacy: all native image pixels equal saved PNGs", + "passed": true + }, + { + "name": "legacy: native linked series count", + "passed": true + }, + { + "name": "legacy: saved plot samples remain exact", + "passed": true + }, + { + "name": "legacy: both linked plot widgets are visible", + "passed": true + }, + { + "name": "legacy: selected flat PNG is visible", + "passed": true + }, + { + "name": "all saved and raw package bytes remain exact", + "passed": true + }, + { + "name": "all executed gallery/source bytes remain exact", + "passed": true + } + ], + "passed": 15, + "failures": [], + "observed": { + "numeric": { + "job": "/dev/shm/hamon-401c5d17da79-capture-history-pr/latest-boundary/numeric-run/numeric.mmsession/processing/jobs/retained-numeric", + "tabs": [ + "Sync", + "lsl / numeric.stream / channel 0", + "lsl / numeric.stream / channel 1" + ], + "tooltips": [ + "numeric/source-6c736c/stream-6e756d657269632e73747265616d/channel_0.png", + "numeric/source-6c736c/stream-6e756d657269632e73747265616d/channel_1.png" + ], + "linked_series_count": 1, + "saved_png_sizes": [ + [ + 1650, + 420 + ], + [ + 1650, + 420 + ] + ] + }, + "legacy": { + "job": "/dev/shm/hamon-401c5d17da79-capturesuite-receiving/fixtures-native/package-a.mmsession/processing/jobs/retained-prior", + "tabs": [ + "Sync", + "emg sim.emg.main channel", + "imu sim.imu.upper accel" + ], + "tooltips": [ + "emg_sim.emg.main_channels.png", + "imu_sim.imu.upper_accel.png" + ], + "linked_series_count": 2, + "saved_png_sizes": [ + [ + 1650, + 540 + ], + [ + 1650, + 450 + ] + ] + } + }, + "source_hashes": { + "/dev/shm/capturesuite-gallery-401c5d17da79/source/desktop/capture_desktop/widgets_analysis_plots.py": "852c9059d01fac9ba38edbe228e0920e8cf3298bb8e1a9d6610b148f6d1e7ffb", + "/dev/shm/capturesuite-gallery-401c5d17da79/source/desktop/capture_desktop/theme.py": "c77f24e1afeb06400385bd0d535800f13dc15d972891e1ff8af504cbe5c818f3", + "/dev/shm/capturesuite-gallery-401c5d17da79/source/tests/ui/test_analysis_nested_gallery.py": "90477416f3efc70b436759eb56348d600b2b5b84f2f7f46ec6b4129c690b9d0a" + }, + "package_hashes_before_and_after": { + "numeric": { + "manifest.json": "399b408a7bcb1cbee8062a926f52b2ceff553fdbf4504d92a629b83898eb4b60", + "processing/jobs/retained-numeric/features/_schema.json": "ea7b96fa667e83b0379515745ee23e659bd640497378b04c267da593d584e264", + "processing/jobs/retained-numeric/features/numeric/source-6c736c/stream-6e756d657269632e73747265616d/windows.csv": "9cae194fe5eabbdd3d804b734e609ea732d05f9b5885f6e51dcea9f5840230fe", + "processing/jobs/retained-numeric/features/numeric/source-6c736c/stream-6e756d657269632e73747265616d/windows.parquet": "b25e995662e343e5660be848fac61eac15dd63d904ea1fa8d4b58fe66dc68b84", + "processing/jobs/retained-numeric/figures/numeric/source-6c736c/stream-6e756d657269632e73747265616d/channel_0.png": "255a352977baf12c5714f71c327cac9ec6fe96377378e7d789433de6335bc73a", + "processing/jobs/retained-numeric/figures/numeric/source-6c736c/stream-6e756d657269632e73747265616d/channel_1.png": "ae7fd0d484e1dd7756a3a0c599de8aea09ede34d0ad1644775c0b95bce3f6195", + "processing/jobs/retained-numeric/figures/sync_dashboard.png": "e801135335d3a6e50353d82b039a14217f7fe6f931a1f9daa1f37de3ab0e6b02", + "processing/jobs/retained-numeric/figures/sync_dashboard_series.json": "1bc0a860646508a6001aed0d312d42338f8b2e9c93592cf5adc7dbeab2277554", + "processing/jobs/retained-numeric/job_manifest.json": "32dd2883bc55717ef813f36930eed5598124f27fa2a9a7a9817e750cd59bcb6d", + "processing/jobs/retained-numeric/logs/job.log": "7edc38094b8619545017aa8f12c4d0179ab43474343e25d483918f32d48b778a", + "processing/jobs/retained-numeric/params.json": "962d5067fb396fca7a5d207bae2aeff4ea16f3218396824de0da670f16b67dc3", + "processing/jobs/retained-numeric/reports/qc.html": "43b9cfbc29c185464e85873ac6c4bfd45a0fa3d45f259d7ea59dcae9464625e5", + "processing/jobs/retained-numeric/reports/qc.json": "6a7e1c4191f43ce87c04344f81d4b4ffa61b2fa383de413650bdcc02a21b3ba2", + "sources/lsl/streams/numeric/segments/000000.mcap": "f3df8e3cc95f76462c502935aad5abafd4392ed3224c239775650c5b49bcd18f", + "sources/lsl/streams/numeric/stream.json": "1adfb22cb81843c0e5bef319c9c2268ea2746e930232f6d89e154d133e0fa885" + }, + "legacy": { + "events/annotations.json": "37517e5f3dc66819f61f5a7bb8ace1921282415f10551d2defa5c3eb0985b570", + "events/checkpoints.json": "37517e5f3dc66819f61f5a7bb8ace1921282415f10551d2defa5c3eb0985b570", + "events/sync_anchors.json": "37517e5f3dc66819f61f5a7bb8ace1921282415f10551d2defa5c3eb0985b570", + "integrity.json": "2fb4194b22d4b1c373f25f9ecab51d0c80e14f42a52f53293fd727ce5418f140", + "manifest.json": "6cc54886cc63fa1263a4077fec322454fdfa133a408836a75451fd77eb7c5243", + "processing/jobs/late-baseline-actual-qc/job_manifest.json": "bbb88191cb522d3314139b6ebcb4cd2e6b8aa6c6b7df362d0653a0a75dcba7bc", + "processing/jobs/late-baseline-actual-qc/logs/job.log": "59f307f1af8f7e20fe908e17afdf3047f6d7eda3d04d2d7e5153f258b6377d37", + "processing/jobs/late-baseline-actual-qc/params.json": "88f55fe8dddb0794c98f693dd21fdd7764a6bac45203e11ba52eab3ebaa40fc3", + "processing/jobs/late-baseline-actual-qc/reports/qc.html": "db815562d270dc133bce019f0c0791bea4e9af52fc62ce7107a41ea6a8485d20", + "processing/jobs/late-baseline-actual-qc/reports/qc.json": "2a1addc8accb001643f81a4b1061458f8fa27de6ffcc157fbed5ddb837c9cf27", + "processing/jobs/late-candidate-actual-qc/job_manifest.json": "d63428766698ba71d56f9797340cc2e4f870cded0e04708b98ee991200e5d88e", + "processing/jobs/late-candidate-actual-qc/logs/job.log": "c2b223c3686c245380c6b3788d45deb8f4a56ca9d420039af2ff598f6eb66cc1", + "processing/jobs/late-candidate-actual-qc/params.json": "9aad1ac26d07fdbf51e882ad70c97ae15942b3057755083b0a8b063506d23fe8", + "processing/jobs/late-candidate-actual-qc/reports/qc.html": "db815562d270dc133bce019f0c0791bea4e9af52fc62ce7107a41ea6a8485d20", + "processing/jobs/late-candidate-actual-qc/reports/qc.json": "2a1addc8accb001643f81a4b1061458f8fa27de6ffcc157fbed5ddb837c9cf27", + "processing/jobs/late-native-candidate-qc/job_manifest.json": "995796fd6b5f52e89ea25a0c45fd769b6352b5f2b1d8984b250971c691ad8658", + "processing/jobs/late-native-candidate-qc/logs/job.log": "b9c0d4a5e6fc748c0a4b60187926f7e9885a2a386a7ed8e85c37a261e053a87d", + "processing/jobs/late-native-candidate-qc/params.json": "e09345ba9ebd7b6f59a9b70cff3af7406c1424237cb5e27a05a80f755b270cb9", + "processing/jobs/late-native-candidate-qc/reports/qc.html": "2917196a7446847355f7443ab5bde8be96dbc71e2b48927f4e60fe064affce6e", + "processing/jobs/late-native-candidate-qc/reports/qc.json": "2d98f837e78a3866402a3f4f9dc765a262168f36d8fe8b2235e02ee17efd3551", + "processing/jobs/retained-prior/features/_schema.json": "c80f7d1e05378bf2399098e9887fc463edda22e366236eab3e9b1b0526d1f0f0", + "processing/jobs/retained-prior/features/emg/sim.emg.main/windows.csv": "0c9b8016e1295976eb10eabdb913efff752cf9936bf4a7cab1d3107a85ca97ff", + "processing/jobs/retained-prior/features/emg/sim.emg.main/windows.parquet": "c5d6d1727acd151ca0b1430eecb0dd0491fe2863a9f7c163d7524bfed584e60f", + "processing/jobs/retained-prior/features/imu/sim.imu.upper/windows.csv": "62212faf4179e9050c4d7a2e3530a461c70d0e56b227138e31b0c273bb21a277", + "processing/jobs/retained-prior/features/imu/sim.imu.upper/windows.parquet": "ff4ca0fbfed45e13e95f73d03d8ba56ce0f8305868012ecb5101df277a449ba9", + "processing/jobs/retained-prior/figures/emg_sim.emg.main_channels.png": "4c7a4aee76c4895cf99e38874de271e83a52c0e7389093c14a93344e9dc43853", + "processing/jobs/retained-prior/figures/imu_sim.imu.upper_accel.png": "8cc603bf604d8925ba13be2c77e0bd8d8f8efbce9529e7d459a449fd61e6a8a4", + "processing/jobs/retained-prior/figures/sync_dashboard.png": "bda125c256b17dbd688ec825c2a5b9b8542f346ce95209faf15efadad5c78d48", + "processing/jobs/retained-prior/figures/sync_dashboard_series.json": "ba1181c30b0a3ab1b26b716e56bf0787f2e67aa4178cd511f0106486d04aa8e6", + "processing/jobs/retained-prior/job_manifest.json": "21471f1ee0cae441202b4b704c6cd1359558ac1bf27f077668508eb1368ae6e7", + "processing/jobs/retained-prior/logs/job.log": "3cf99c71a0e4e3046b791ad2c04e388adfe452959b315d8dd5df6d278a5aaf63", + "processing/jobs/retained-prior/params.json": "9c0e1ab18949727f29352f1a602ae65d74db48f8453a49faa72fbc95c518b35b", + "processing/jobs/retained-prior/reports/qc.html": "db815562d270dc133bce019f0c0791bea4e9af52fc62ce7107a41ea6a8485d20", + "processing/jobs/retained-prior/reports/qc.json": "2a1addc8accb001643f81a4b1061458f8fa27de6ffcc157fbed5ddb837c9cf27", + "sources/sim.emg.main/health/gaps.jsonl": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "sources/sim.emg.main/source.json": "4e7626e51bfb804c27f83bf98ee186a47ec9f36fec0cbd7863ea8ecb1ecfbd10", + "sources/sim.emg.main/streams/sim.emg.main.batch/segments/000000.mcap": "6f3b9bd4ce01238f122649a1139a290ea6193893938a95f3ac61dd61a447d997", + "sources/sim.emg.main/streams/sim.emg.main.batch/stream.json": "5307697f957309eaca816fa0e20c4799c900e2598a8acf66a59928aa83b305b2", + "sources/sim.imu.upper/source.json": "a6198f509edc557c1e1d8583a767a540962977751c80a1b6491e3d594b60c7a8", + "sources/sim.imu.upper/streams/sim.imu.upper.frames/segments/000000.mcap": "c477a0e0865086fbb4154c977def4d93ea5fb38cc098a4862c45b21b966014c9", + "sources/sim.imu.upper/streams/sim.imu.upper.frames/stream.json": "ec39026bed1b833d4decb0ef7b0efb94c5557a5647bc50addc060bef3a30d50d" + } + }, + "frames": { + "numeric-channel.png": { + "bytes": 39590, + "sha256": "24dc1f0a7372d5faa63bfaf63b3d3c78ef623f06129958391016893f3f2dfc82", + "width": 1200, + "height": 820 + }, + "legacy-linked-plots.png": { + "bytes": 50152, + "sha256": "ebb6d1914c041ef2717f4498203635350d37a84a369b996bb24360b5e7d8352b", + "width": 1200, + "height": 820 + }, + "legacy-flat-figure.png": { + "bytes": 27026, + "sha256": "b6431cac7a7ec09e4f53e476274ada0f6a92e1e400f9ca4fe6e920ddaac612c5", + "width": 1200, + "height": 820 + } + } +} diff --git a/docs/evidence/nested-figure-gallery-401c5d17da79/source-input.json b/docs/evidence/nested-figure-gallery-401c5d17da79/source-input.json new file mode 100644 index 00000000..fc9258bb --- /dev/null +++ b/docs/evidence/nested-figure-gallery-401c5d17da79/source-input.json @@ -0,0 +1,16 @@ +{ + "source": "/dev/shm/capturesuite-gallery-401c5d17da79/source", + "authored_base": "3e3ecc5ecc1cfc79c79901eb5cffe10b0ec5852e", + "canonical_gallery_current_through": "3e3ecc5ecc1cfc79c79901eb5cffe10b0ec5852e", + "gallery_sha256": "85c73f881ee7d60ef2f868f7ff73fc57c0a4ef99a717f7f5015534db23e1ab86", + "sparse": true, + "objects_read_only": "/dev/shm/hamon-401c5d17da79-capture-history-pr/objects.git/objects", + "free_bytes": 6275072, + "setup_note": "An initial normal shared clone could not walk the donor incomplete parent graph. This explicit sparse repository declares the genuine0ed commit as its shallow boundary; no donor object or metadata was changed.", + "initial_pre_edit_anchor": "0ed1ccaa023a5327495565d59e1dd0b28b2ee5bd", + "shallow_boundaries": [ + "0ed1ccaa023a5327495565d59e1dd0b28b2ee5bd", + "3e3ecc5ecc1cfc79c79901eb5cffe10b0ec5852e" + ], + "current_tree": "18e97093f04de23de5e9878fd22c1f5ed986d5f3" +} diff --git a/docs/evidence/nested-figure-gallery-401c5d17da79/visual/legacy-flat-figure.png b/docs/evidence/nested-figure-gallery-401c5d17da79/visual/legacy-flat-figure.png new file mode 100644 index 00000000..ba0c8165 Binary files /dev/null and b/docs/evidence/nested-figure-gallery-401c5d17da79/visual/legacy-flat-figure.png differ diff --git a/docs/evidence/nested-figure-gallery-401c5d17da79/visual/legacy-linked-plots.png b/docs/evidence/nested-figure-gallery-401c5d17da79/visual/legacy-linked-plots.png new file mode 100644 index 00000000..0a55d981 Binary files /dev/null and b/docs/evidence/nested-figure-gallery-401c5d17da79/visual/legacy-linked-plots.png differ diff --git a/docs/evidence/nested-figure-gallery-401c5d17da79/visual/numeric-channel.png b/docs/evidence/nested-figure-gallery-401c5d17da79/visual/numeric-channel.png new file mode 100644 index 00000000..871ee734 Binary files /dev/null and b/docs/evidence/nested-figure-gallery-401c5d17da79/visual/numeric-channel.png differ diff --git a/docs/operator/README.md b/docs/operator/README.md index 541cb2f9..ff6bac28 100644 --- a/docs/operator/README.md +++ b/docs/operator/README.md @@ -19,6 +19,33 @@ Or manually: 3. Status bar shows **Connected · instance …** 4. **Create Session** → select sim sources → **Rehearse** or **Start Selected** +## Open saved analysis + +In **Analysis**, use **Browse…** or **Use open session** to select a `.mmsession` +package. **Saved analysis** lists its retained completed and failed jobs, with +their recorded status. Choose a job and click **Open saved result** to load its +existing figures and output inventory into the gallery and job inspector. +Selecting a different item in the list keeps the current result open until you +explicitly open the selected one. + +**Result details…** opens read-only **Parameters**, **Log** and **Manifest** tabs +for the currently displayed result. Failed jobs can be useful here: their saved +log explains the failure even when no figures were produced. Missing parameters +or logs are identified in their respective tabs. Long logs show their final +256 KiB, with the truncation stated; the JSON viewer accepts files up to 4 MiB. + +Use **Refresh** to discover jobs written since the package was selected. Opening, +refreshing and reading details do not rerun analysis or change any package files. +Changing packages clears the previous package's result and details window. If an +earlier job completes after a package change, its result stays with the original +package; select that package to open it. + +An **unavailable** row includes the reason it cannot be opened, such as a missing +manifest, unsupported job schema or mismatched session identity. A package copy +can retain the original absolute path in its manifest; the viewer reads the job +directory inside the package you selected. It does not follow job-directory +links into another package. + ## Why are buttons greyed out? | State | Enabled actions | diff --git a/docs/receiving/analysis-history-ci-budget-401c5d17da79/README.md b/docs/receiving/analysis-history-ci-budget-401c5d17da79/README.md new file mode 100644 index 00000000..8fd0d8cc --- /dev/null +++ b/docs/receiving/analysis-history-ci-budget-401c5d17da79/README.md @@ -0,0 +1,20 @@ +# Analysis history: hosted CI time allowance + +The full Windows Python suite reached its existing 300-second subprocess limit twice while reviewing PR71. The retained attempts used actual proposed merge `0de94b767061ec1fe5c05d11c6baa36ec9ddf16b`, a clean unchanged source tree, and no final JUnit. Neither timeout is classified as a passing product run. + +- Original job: https://github.com/Jacob-Met/CaptureSuite/actions/runs/37811934426/job/113430721070 +- One unchanged-job retry: https://github.com/Jacob-Met/CaptureSuite/actions/runs/37811934426/job/113459881579 + +A temporary autouse fixture then recorded entry/exit around each of this PR's eight unchanged history tests. On actual proposed merge `f17f811366bc9915e0f001b42d9df86afc353213`, every history test passed in 0.073–0.158 seconds; their displayed timings sum to 0.834 seconds. The full suite passed 555 with 6 daemon-availability skips in 295.60 seconds (296.7734097 seconds including wrapper evidence processing). This left about 4.4 seconds before the existing child-process deadline. This one observation establishes little timing margin; it is not a claim about every runner's speed. + +Diagnostic job: https://github.com/Jacob-Met/CaptureSuite/actions/runs/37826104818/job/113479261945 + +## Source change + +Restore `tests/ui/test_analysis_history.py` exactly to its pre-diagnostic blob `f013473f750b515a8305e2f7f8426b6520e26a65`. Change only the Python suite subprocess allowance in `tools/run_ci_tests.py` from 300 to 600 seconds. The existing 20-minute Windows job limit remains, as do all process-exit/JUnit/source-immutability acceptance predicates and the suite's existing test selection. No test is removed, skipped or weakened. The existing runner file is byte-identical in the PR source and inspected canonical main before this single-literal change. + +All product source is unchanged by this correction. The previous native history qualifications retain their recorded inputs. The new source head still requires its own hosted gate; this record does not convert either prior timeout into success. + +## Preserved evidence + +The three complete hosted logs are adjacent to this file, along with the actual diagnostic receipt. The source owner is `estate-401c5d17da79`, working in PR71. The prepared source and raw logs are also retained under the ThinkPad estate `capturesuite-ci-a2fd-20261008` packet. The transient diagnostic-only source remains in parent commit `8747cb95bfb2ac91aa4f1ff604ad677f3597fa12`. diff --git a/docs/receiving/analysis-history-ci-budget-401c5d17da79/diagnostic-receipt.json b/docs/receiving/analysis-history-ci-budget-401c5d17da79/diagnostic-receipt.json new file mode 100644 index 00000000..db6b4814 --- /dev/null +++ b/docs/receiving/analysis-history-ci-budget-401c5d17da79/diagnostic-receipt.json @@ -0,0 +1,34 @@ +{ + "schema": "capturesuite.test-receipt.v1", + "accepted": true, + "process_exit": 0, + "counts": { + "tests": 561, + "passed": 555, + "failures": 0, + "errors": 0, + "skipped": 6 + }, + "junit_sha256": "024d03bebc15c2640a86fc8309a8a1cc2ad411f87a000f404b0ef846f0f10764", + "problems": [], + "scope": "Process and test-evidence consistency, not clinical validation", + "seconds": 296.77340969999995, + "created_at": "2026-10-08T18:47:47.824177+00:00", + "run_directory": "build/evidence/python-20261008T184250Z-e1bb4f7d", + "log_sha256": "2a6e81ac2871463414d40e41de21c2e62b93497289601fe13ae3529aa9b6a935", + "source_commit": "f17f811366bc9915e0f001b42d9df86afc353213", + "source_worktree_dirty": false, + "source_tree_sha256": "e265754e62a900bd080b409d4fa720d570003c24e6d06fb5136cf9275856a446", + "source_file_count": 1142, + "github": { + "GITHUB_ACTIONS": "true", + "GITHUB_EVENT_NAME": "pull_request", + "GITHUB_SHA": "f17f811366bc9915e0f001b42d9df86afc353213", + "GITHUB_REF": "refs/pull/71/merge", + "GITHUB_HEAD_REF": "work/analysis-history-401c5d17da79", + "GITHUB_BASE_REF": "main", + "GITHUB_RUN_ID": "37826104818", + "GITHUB_WORKFLOW_REF": "Jacob-Met/CaptureSuite/.github/workflows/ci.yml@refs/pull/71/merge" + }, + "source_unchanged_during_test": true +} diff --git a/docs/receiving/analysis-history-ci-budget-401c5d17da79/diagnostic-windows-success.log b/docs/receiving/analysis-history-ci-budget-401c5d17da79/diagnostic-windows-success.log new file mode 100644 index 00000000..14d0ccea --- /dev/null +++ b/docs/receiving/analysis-history-ci-budget-401c5d17da79/diagnostic-windows-success.log @@ -0,0 +1,580 @@ +2026-10-08T18:40:34.0783039Z Current runner version: '2.337.0' +2026-10-08T18:40:34.0807212Z ##[group]Runner Image Provisioner +2026-10-08T18:40:34.0808007Z Hosted Compute Agent +2026-10-08T18:40:34.0808535Z Version: 20261002.596 +2026-10-08T18:40:34.0809116Z Commit: c3d12f3313a95f25162a1503be624f3b0617f8c0 +2026-10-08T18:40:34.0809785Z Build Date: 2026-10-02T22:28:27Z +2026-10-08T18:40:34.0810407Z Worker ID: {9ac89e71-83c9-42fc-8de2-cbc2de3b62ac} +2026-10-08T18:40:34.0811058Z Region: centralus +2026-10-08T18:40:34.0811554Z Cloud: Azure +2026-10-08T18:40:34.0812046Z ##[endgroup] +2026-10-08T18:40:34.0813407Z ##[group]Operating System +2026-10-08T18:40:34.0814008Z Microsoft Windows Server 2022 +2026-10-08T18:40:34.0814563Z 10.0.20348 +2026-10-08T18:40:34.0815033Z Datacenter +2026-10-08T18:40:34.0815504Z ##[endgroup] +2026-10-08T18:40:34.0815980Z ##[group]Runner Image +2026-10-08T18:40:34.0816503Z Image: windows-2022 +2026-10-08T18:40:34.0817016Z Version: 20261004.326.1 +2026-10-08T18:40:34.0818330Z Included Software: https://github.com/actions/runner-images/blob/win22/20261004.326/images/windows/Windows2022-Readme.md +2026-10-08T18:40:34.0819796Z Image Release: https://github.com/actions/runner-images/releases/tag/win22%2F20261004.326 +2026-10-08T18:40:34.0820659Z ##[endgroup] +2026-10-08T18:40:34.0821767Z ##[group]GITHUB_TOKEN Permissions +2026-10-08T18:40:34.0823524Z Contents: read +2026-10-08T18:40:34.0824111Z Metadata: read +2026-10-08T18:40:34.0824594Z Packages: read +2026-10-08T18:40:34.0825102Z ##[endgroup] +2026-10-08T18:40:34.0827081Z Secret source: Actions +2026-10-08T18:40:34.0827900Z Cache mode: write +2026-10-08T18:40:34.0828589Z Prepare workflow directory +2026-10-08T18:40:34.1226162Z Prepare all required actions +2026-10-08T18:40:34.1295771Z Getting action download info +2026-10-08T18:40:34.3867407Z Download action repository 'actions/checkout@v4' (SHA:11d5960a326750d5838078e36cf38b85af677262) +2026-10-08T18:40:34.4958772Z Download action repository 'actions/setup-python@v5' (SHA:a26af69be951a213d495a4c3e4e4022e16d87065) +2026-10-08T18:40:34.6378849Z Download action repository 'actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a' (SHA:043fb46d1a93c77aae656e7c1c64a875d1fc6a0a) +2026-10-08T18:40:34.8604347Z Complete job name: python +2026-10-08T18:40:35.0171274Z ##[group]Run actions/checkout@v4 +2026-10-08T18:40:35.0172474Z with: +2026-10-08T18:40:35.0172922Z repository: Jacob-Met/CaptureSuite +2026-10-08T18:40:35.0176745Z token: *** +2026-10-08T18:40:35.0177146Z ssh-strict: true +2026-10-08T18:40:35.0177558Z ssh-user: git +2026-10-08T18:40:35.0177962Z persist-credentials: true +2026-10-08T18:40:35.0178408Z clean: true +2026-10-08T18:40:35.0178816Z sparse-checkout-cone-mode: true +2026-10-08T18:40:35.0179295Z fetch-depth: 1 +2026-10-08T18:40:35.0179687Z fetch-tags: false +2026-10-08T18:40:35.0180083Z show-progress: true +2026-10-08T18:40:35.0180504Z lfs: false +2026-10-08T18:40:35.0180890Z submodules: false +2026-10-08T18:40:35.0181309Z set-safe-directory: true +2026-10-08T18:40:35.0181781Z allow-unsafe-pr-checkout: false +2026-10-08T18:40:35.0182564Z ##[endgroup] +2026-10-08T18:40:35.1750822Z Syncing repository: Jacob-Met/CaptureSuite +2026-10-08T18:40:35.1752570Z ##[group]Getting Git version info +2026-10-08T18:40:35.1753309Z Working directory is 'D:\a\CaptureSuite\CaptureSuite' +2026-10-08T18:40:35.2761157Z [command]"C:\Program Files\Git\bin\git.exe" version +2026-10-08T18:40:35.5943706Z git version 2.56.0.windows.1 +2026-10-08T18:40:35.5988576Z ##[endgroup] +2026-10-08T18:40:35.6009357Z Temporarily overriding HOME='D:\a\_temp\5cbf3b83-fa66-4c93-a132-1f57853741d6' before making global git config changes +2026-10-08T18:40:35.6011786Z Adding repository directory to the temporary git global config as a safe directory +2026-10-08T18:40:35.6020962Z [command]"C:\Program Files\Git\bin\git.exe" config --global --add safe.directory D:\a\CaptureSuite\CaptureSuite +2026-10-08T18:40:35.6581623Z Deleting the contents of 'D:\a\CaptureSuite\CaptureSuite' +2026-10-08T18:40:35.6586879Z ##[group]Initializing the repository +2026-10-08T18:40:35.6596538Z [command]"C:\Program Files\Git\bin\git.exe" init D:\a\CaptureSuite\CaptureSuite +2026-10-08T18:40:35.7344780Z Initialized empty Git repository in D:/a/CaptureSuite/CaptureSuite/.git/ +2026-10-08T18:40:35.7384514Z [command]"C:\Program Files\Git\bin\git.exe" remote add origin https://github.com/Jacob-Met/CaptureSuite +2026-10-08T18:40:35.7924100Z ##[endgroup] +2026-10-08T18:40:35.7925021Z ##[group]Disabling automatic garbage collection +2026-10-08T18:40:35.7933039Z [command]"C:\Program Files\Git\bin\git.exe" config --local gc.auto 0 +2026-10-08T18:40:35.8237675Z ##[endgroup] +2026-10-08T18:40:35.8239068Z ##[group]Setting up auth +2026-10-08T18:40:35.8240921Z [command]"C:\Program Files\Git\bin\git.exe" config --local --name-only --get-regexp core\.sshCommand +2026-10-08T18:40:35.8563331Z [command]"C:\Program Files\Git\bin\git.exe" submodule foreach --recursive "sh -c \"git config --local --name-only --get-regexp 'core\.sshCommand' && git config --local --unset-all 'core.sshCommand' || :\"" +2026-10-08T18:40:37.1235964Z [command]"C:\Program Files\Git\bin\git.exe" config --local --name-only --get-regexp http\.https\:\/\/github\.com\/\.extraheader +2026-10-08T18:40:37.1572282Z [command]"C:\Program Files\Git\bin\git.exe" submodule foreach --recursive "sh -c \"git config --local --name-only --get-regexp 'http\.https\:\/\/github\.com\/\.extraheader' && git config --local --unset-all 'http.https://github.com/.extraheader' || :\"" +2026-10-08T18:40:37.6178432Z [command]"C:\Program Files\Git\bin\git.exe" config --local --name-only --get-regexp ^includeIf\.gitdir: +2026-10-08T18:40:37.6479486Z [command]"C:\Program Files\Git\bin\git.exe" submodule foreach --recursive "git config --local --show-origin --name-only --get-regexp remote.origin.url" +2026-10-08T18:40:38.1370401Z [command]"C:\Program Files\Git\bin\git.exe" config --local http.https://github.com/.extraheader "AUTHORIZATION: basic ***" +2026-10-08T18:40:38.1678327Z ##[endgroup] +2026-10-08T18:40:38.1678855Z ##[group]Fetching the repository +2026-10-08T18:40:38.1702033Z [command]"C:\Program Files\Git\bin\git.exe" -c protocol.version=2 fetch --no-tags --prune --no-recurse-submodules --depth=1 origin +f17f811366bc9915e0f001b42d9df86afc353213:refs/remotes/pull/71/merge +2026-10-08T18:40:39.5956910Z From https://github.com/Jacob-Met/CaptureSuite +2026-10-08T18:40:39.5957843Z * [new ref] f17f811366bc9915e0f001b42d9df86afc353213 -> pull/71/merge +2026-10-08T18:40:39.5990927Z ##[endgroup] +2026-10-08T18:40:39.5991619Z ##[group]Determining the checkout info +2026-10-08T18:40:39.5994112Z ##[endgroup] +2026-10-08T18:40:39.6003831Z [command]"C:\Program Files\Git\bin\git.exe" sparse-checkout disable +2026-10-08T18:40:39.6426741Z [command]"C:\Program Files\Git\bin\git.exe" config --local --unset-all extensions.worktreeConfig +2026-10-08T18:40:39.6727844Z ##[group]Checking out the ref +2026-10-08T18:40:39.6741753Z [command]"C:\Program Files\Git\bin\git.exe" checkout --progress --force refs/remotes/pull/71/merge +2026-10-08T18:40:39.9875541Z Note: switching to 'refs/remotes/pull/71/merge'. +2026-10-08T18:40:39.9876017Z +2026-10-08T18:40:39.9876546Z You are in 'detached HEAD' state. You can look around, make experimental +2026-10-08T18:40:39.9957812Z changes and commit them, and you can discard any commits you make in this +2026-10-08T18:40:39.9958677Z state without impacting any branches by switching back to a branch. +2026-10-08T18:40:39.9959128Z +2026-10-08T18:40:39.9959431Z If you want to create a new branch to retain commits you create, you may +2026-10-08T18:40:39.9960243Z do so (now or later) by using -c with the switch command. Example: +2026-10-08T18:40:39.9960705Z +2026-10-08T18:40:39.9960915Z git switch -c +2026-10-08T18:40:39.9961224Z +2026-10-08T18:40:39.9961406Z Or undo this operation with: +2026-10-08T18:40:39.9962204Z +2026-10-08T18:40:39.9962371Z git switch - +2026-10-08T18:40:39.9962624Z +2026-10-08T18:40:39.9963001Z Turn off this advice by setting config variable advice.detachedHead to false +2026-10-08T18:40:39.9964868Z +2026-10-08T18:40:39.9966405Z HEAD is now at f17f811 Merge 8747cb95bfb2ac91aa4f1ff604ad677f3597fa12 into 11cc78297d8d214407aea693548af4de855d61da +2026-10-08T18:40:39.9968991Z ##[endgroup] +2026-10-08T18:40:40.0316882Z [command]"C:\Program Files\Git\bin\git.exe" log -1 --format=%H +2026-10-08T18:40:40.0637044Z f17f811366bc9915e0f001b42d9df86afc353213 +2026-10-08T18:40:40.1172069Z ##[group]Run actions/setup-python@v5 +2026-10-08T18:40:40.1172430Z with: +2026-10-08T18:40:40.1172617Z python-version: 3.12 +2026-10-08T18:40:40.1172848Z check-latest: false +2026-10-08T18:40:40.1175267Z token: *** +2026-10-08T18:40:40.1175476Z update-environment: true +2026-10-08T18:40:40.1175706Z allow-prereleases: false +2026-10-08T18:40:40.1175915Z freethreaded: false +2026-10-08T18:40:40.1176104Z ##[endgroup] +2026-10-08T18:40:40.2713388Z ##[group]Installed versions +2026-10-08T18:40:40.2850497Z (node:4632) [DEP0040] DeprecationWarning: The `punycode` module is deprecated. Please use a userland alternative instead. +2026-10-08T18:40:40.2851900Z (Use `node --trace-deprecation ...` to show where the warning was created) +2026-10-08T18:40:40.2853585Z Successfully set up CPython (3.12.10) +2026-10-08T18:40:40.2854116Z ##[endgroup] +2026-10-08T18:40:40.3107788Z ##[group]Run python -m pip install -r requirements-ci.txt +2026-10-08T18:40:40.3108357Z python -m pip install -r requirements-ci.txt +2026-10-08T18:40:40.3230261Z shell: C:\Program Files\PowerShell\7\pwsh.EXE -command ". '{0}'" +2026-10-08T18:40:40.3230648Z env: +2026-10-08T18:40:40.3230924Z pythonLocation: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T18:40:40.3231433Z PKG_CONFIG_PATH: C:\hostedtoolcache\windows\Python\3.12.10\x64/lib/pkgconfig +2026-10-08T18:40:40.3231918Z Python_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T18:40:40.3232348Z Python2_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T18:40:40.3232774Z Python3_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T18:40:40.3233135Z ##[endgroup] +2026-10-08T18:40:56.4165946Z Obtaining file:///D:/a/CaptureSuite/CaptureSuite/libs/python/capture_protocol (from -r requirements-ci.txt (line 3)) +2026-10-08T18:40:56.4194170Z Installing build dependencies: started +2026-10-08T18:41:00.0683694Z Installing build dependencies: finished with status 'done' +2026-10-08T18:41:00.0698247Z Checking if build backend supports build_editable: started +2026-10-08T18:41:00.7627972Z Checking if build backend supports build_editable: finished with status 'done' +2026-10-08T18:41:00.7652922Z Getting requirements to build editable: started +2026-10-08T18:41:01.3064449Z Getting requirements to build editable: finished with status 'done' +2026-10-08T18:41:01.3093329Z Preparing editable metadata (pyproject.toml): started +2026-10-08T18:41:01.6428236Z Preparing editable metadata (pyproject.toml): finished with status 'done' +2026-10-08T18:41:01.6477362Z Obtaining file:///D:/a/CaptureSuite/CaptureSuite/libs/python/capture_session (from -r requirements-ci.txt (line 4)) +2026-10-08T18:41:01.6506289Z Installing build dependencies: started +2026-10-08T18:41:03.2585899Z Installing build dependencies: finished with status 'done' +2026-10-08T18:41:03.2599995Z Checking if build backend supports build_editable: started +2026-10-08T18:41:03.7581017Z Checking if build backend supports build_editable: finished with status 'done' +2026-10-08T18:41:03.7605912Z Getting requirements to build editable: started +2026-10-08T18:41:04.2805447Z Getting requirements to build editable: finished with status 'done' +2026-10-08T18:41:04.2831922Z Preparing editable metadata (pyproject.toml): started +2026-10-08T18:41:04.6101866Z Preparing editable metadata (pyproject.toml): finished with status 'done' +2026-10-08T18:41:04.6147375Z Obtaining file:///D:/a/CaptureSuite/CaptureSuite/libs/python/capture_analysis +2026-10-08T18:41:04.6173106Z Installing build dependencies: started +2026-10-08T18:41:06.2345459Z Installing build dependencies: finished with status 'done' +2026-10-08T18:41:06.2360444Z Checking if build backend supports build_editable: started +2026-10-08T18:41:06.7065896Z Checking if build backend supports build_editable: finished with status 'done' +2026-10-08T18:41:06.7089054Z Getting requirements to build editable: started +2026-10-08T18:41:07.2309309Z Getting requirements to build editable: finished with status 'done' +2026-10-08T18:41:07.2335587Z Preparing editable metadata (pyproject.toml): started +2026-10-08T18:41:07.5945575Z Preparing editable metadata (pyproject.toml): finished with status 'done' +2026-10-08T18:41:07.5996969Z Obtaining file:///D:/a/CaptureSuite/CaptureSuite/libs/python/capture_worker (from -r requirements-ci.txt (line 6)) +2026-10-08T18:41:07.6023906Z Installing build dependencies: started +2026-10-08T18:41:09.2036418Z Installing build dependencies: finished with status 'done' +2026-10-08T18:41:09.2052440Z Checking if build backend supports build_editable: started +2026-10-08T18:41:09.6664125Z Checking if build backend supports build_editable: finished with status 'done' +2026-10-08T18:41:09.6685749Z Getting requirements to build editable: started +2026-10-08T18:41:10.2011142Z Getting requirements to build editable: finished with status 'done' +2026-10-08T18:41:10.2035469Z Preparing editable metadata (pyproject.toml): started +2026-10-08T18:41:10.5620796Z Preparing editable metadata (pyproject.toml): finished with status 'done' +2026-10-08T18:41:10.5665139Z Obtaining file:///D:/a/CaptureSuite/CaptureSuite/desktop +2026-10-08T18:41:10.5691401Z Installing build dependencies: started +2026-10-08T18:41:12.2742931Z Installing build dependencies: finished with status 'done' +2026-10-08T18:41:12.2758238Z Checking if build backend supports build_editable: started +2026-10-08T18:41:12.7398446Z Checking if build backend supports build_editable: finished with status 'done' +2026-10-08T18:41:12.7424841Z Getting requirements to build editable: started +2026-10-08T18:41:13.5350306Z Getting requirements to build editable: finished with status 'done' +2026-10-08T18:41:13.5378536Z Preparing editable metadata (pyproject.toml): started +2026-10-08T18:41:13.8964497Z Preparing editable metadata (pyproject.toml): finished with status 'done' +2026-10-08T18:41:14.7167674Z Collecting grpcio-tools<1.63,>=1.62 (from -r requirements-ci.txt (line 8)) +2026-10-08T18:41:14.8987090Z Downloading grpcio_tools-1.62.3-cp312-cp312-win_amd64.whl.metadata (6.4 kB) +2026-10-08T18:41:14.9518413Z Collecting mcap<2,>=1.1 (from -r requirements-ci.txt (line 9)) +2026-10-08T18:41:14.9636160Z Downloading mcap-1.5.0-py3-none-any.whl.metadata (380 bytes) +2026-10-08T18:41:15.0256311Z Collecting pytest>=8 (from -r requirements-ci.txt (line 10)) +2026-10-08T18:41:15.0375671Z Downloading pytest-9.1.1-py3-none-any.whl.metadata (7.6 kB) +2026-10-08T18:41:15.1061704Z Collecting pytest-cov>=5 (from -r requirements-ci.txt (line 11)) +2026-10-08T18:41:15.1188119Z Downloading pytest_cov-7.1.0-py3-none-any.whl.metadata (32 kB) +2026-10-08T18:41:15.5400825Z Collecting ruff<1,>=0.6 (from -r requirements-ci.txt (line 12)) +2026-10-08T18:41:15.5527700Z Downloading ruff-0.16.10-py3-none-win_amd64.whl.metadata (21 kB) +2026-10-08T18:41:15.7503008Z Collecting protobuf<5,>=4.25 (from capture-protocol==0.1.0->-r requirements-ci.txt (line 3)) +2026-10-08T18:41:15.7635679Z Downloading protobuf-4.25.9-cp310-abi3-win_amd64.whl.metadata (541 bytes) +2026-10-08T18:41:15.8228061Z Collecting jsonschema>=4.21 (from capture-session==0.1.0->-r requirements-ci.txt (line 4)) +2026-10-08T18:41:15.8409076Z Downloading jsonschema-4.26.0-py3-none-any.whl.metadata (7.6 kB) +2026-10-08T18:41:15.9466788Z Collecting pyyaml>=6.0 (from capture-analysis==0.1.0) +2026-10-08T18:41:15.9592614Z Downloading pyyaml-6.0.3-cp312-cp312-win_amd64.whl.metadata (2.4 kB) +2026-10-08T18:41:16.0301482Z Collecting PySide6<7,>=6.6 (from capture-desktop==0.1.0) +2026-10-08T18:41:16.0465205Z Downloading pyside6-6.12.0-cp310-abi3-win_amd64.whl.metadata (5.7 kB) +2026-10-08T18:41:16.3177313Z Collecting numpy>=1.26 (from capture-analysis==0.1.0) +2026-10-08T18:41:16.3338271Z Downloading numpy-2.5.3-cp312-cp312-win_amd64.whl.metadata (6.6 kB) +2026-10-08T18:41:16.5271081Z Collecting scipy>=1.11 (from capture-analysis==0.1.0) +2026-10-08T18:41:16.5437609Z Downloading scipy-1.18.1-cp312-cp312-win_amd64.whl.metadata (61 kB) +2026-10-08T18:41:16.7633887Z Collecting pandas>=2.1 (from capture-analysis==0.1.0) +2026-10-08T18:41:16.7774458Z Downloading pandas-3.0.6-cp312-cp312-win_amd64.whl.metadata (19 kB) +2026-10-08T18:41:16.9172160Z Collecting pyarrow>=14.0 (from capture-analysis==0.1.0) +2026-10-08T18:41:16.9365664Z Downloading pyarrow-25.0.1-cp312-cp312-win_amd64.whl.metadata (3.0 kB) +2026-10-08T18:41:17.1367714Z Collecting matplotlib>=3.8 (from capture-analysis==0.1.0) +2026-10-08T18:41:17.1527037Z Downloading matplotlib-3.11.2-cp312-cp312-win_amd64.whl.metadata (80 kB) +2026-10-08T18:41:17.2405644Z Collecting pyqtgraph>=0.13 (from capture-desktop==0.1.0) +2026-10-08T18:41:17.2756058Z Downloading pyqtgraph-0.14.0-py3-none-any.whl.metadata (1.5 kB) +2026-10-08T18:41:17.8959580Z Collecting grpcio>=1.62.3 (from grpcio-tools<1.63,>=1.62->-r requirements-ci.txt (line 8)) +2026-10-08T18:41:17.9119999Z Downloading grpcio-1.84.0-cp312-cp312-win_amd64.whl.metadata (3.9 kB) +2026-10-08T18:41:18.0234920Z Collecting setuptools (from grpcio-tools<1.63,>=1.62->-r requirements-ci.txt (line 8)) +2026-10-08T18:41:18.0261493Z Using cached setuptools-84.0.0-py3-none-any.whl.metadata (6.6 kB) +2026-10-08T18:41:18.1263817Z Collecting lz4 (from mcap<2,>=1.1->-r requirements-ci.txt (line 9)) +2026-10-08T18:41:18.1399974Z Downloading lz4-4.4.5-cp312-cp312-win_amd64.whl.metadata (3.9 kB) +2026-10-08T18:41:18.2610479Z Collecting zstandard (from mcap<2,>=1.1->-r requirements-ci.txt (line 9)) +2026-10-08T18:41:18.2775420Z Downloading zstandard-0.25.0-cp312-cp312-win_amd64.whl.metadata (3.3 kB) +2026-10-08T18:41:18.3353196Z Collecting PySide6_Essentials==6.12.0 (from PySide6<7,>=6.6->capture-desktop==0.1.0) +2026-10-08T18:41:18.3477845Z Downloading pyside6_essentials-6.12.0-cp310-abi3-win_amd64.whl.metadata (3.9 kB) +2026-10-08T18:41:18.4066847Z Collecting PySide6_Addons==6.12.0 (from PySide6<7,>=6.6->capture-desktop==0.1.0) +2026-10-08T18:41:18.4199663Z Downloading pyside6_addons-6.12.0-cp310-abi3-win_amd64.whl.metadata (4.4 kB) +2026-10-08T18:41:18.4748861Z Collecting PySide6_WebEngine==6.12.0.140 (from PySide6<7,>=6.6->capture-desktop==0.1.0) +2026-10-08T18:41:18.4867270Z Downloading pyside6_webengine-6.12.0.140-cp310-abi3-win_amd64.whl.metadata (3.7 kB) +2026-10-08T18:41:18.5354195Z Collecting PySide6_Pdf==6.12.0.140 (from PySide6<7,>=6.6->capture-desktop==0.1.0) +2026-10-08T18:41:18.5477557Z Downloading pyside6_pdf-6.12.0.140-cp310-abi3-win_amd64.whl.metadata (3.6 kB) +2026-10-08T18:41:18.6070730Z Collecting shiboken6==6.12.0 (from PySide6_Essentials==6.12.0->PySide6<7,>=6.6->capture-desktop==0.1.0) +2026-10-08T18:41:18.6195997Z Downloading shiboken6-6.12.0-cp310-abi3-win_amd64.whl.metadata (2.6 kB) +2026-10-08T18:41:18.6727616Z Requirement already satisfied: colorama>=0.4 in C:\hostedtoolcache\windows\Python\3.12.10\x64\Lib\site-packages (from pytest>=8->-r requirements-ci.txt (line 10)) (0.4.6) +2026-10-08T18:41:18.7035085Z Collecting iniconfig>=1.0.1 (from pytest>=8->-r requirements-ci.txt (line 10)) +2026-10-08T18:41:18.7156660Z Downloading iniconfig-2.3.1-py3-none-any.whl.metadata (2.8 kB) +2026-10-08T18:41:18.7332134Z Requirement already satisfied: packaging>=22 in C:\hostedtoolcache\windows\Python\3.12.10\x64\Lib\site-packages (from pytest>=8->-r requirements-ci.txt (line 10)) (26.3) +2026-10-08T18:41:18.7668902Z Collecting pluggy<2,>=1.5 (from pytest>=8->-r requirements-ci.txt (line 10)) +2026-10-08T18:41:18.7790363Z Downloading pluggy-1.6.0-py3-none-any.whl.metadata (4.8 kB) +2026-10-08T18:41:18.8406979Z Collecting pygments>=2.7.2 (from pytest>=8->-r requirements-ci.txt (line 10)) +2026-10-08T18:41:18.8527872Z Downloading pygments-2.21.0-py3-none-any.whl.metadata (2.5 kB) +2026-10-08T18:41:19.3808711Z Collecting coverage>=7.10.6 (from coverage[toml]>=7.10.6->pytest-cov>=5->-r requirements-ci.txt (line 11)) +2026-10-08T18:41:19.3931918Z Downloading coverage-7.16.2-cp312-cp312-win_amd64.whl.metadata (8.4 kB) +2026-10-08T18:41:19.4542641Z Collecting typing-extensions~=4.12 (from grpcio>=1.62.3->grpcio-tools<1.63,>=1.62->-r requirements-ci.txt (line 8)) +2026-10-08T18:41:19.4666239Z Downloading typing_extensions-4.16.0-py3-none-any.whl.metadata (3.3 kB) +2026-10-08T18:41:19.5216272Z Collecting attrs>=22.2.0 (from jsonschema>=4.21->capture-session==0.1.0->-r requirements-ci.txt (line 4)) +2026-10-08T18:41:19.5349099Z Downloading attrs-26.1.0-py3-none-any.whl.metadata (8.8 kB) +2026-10-08T18:41:19.5927906Z Collecting jsonschema-specifications>=2023.03.6 (from jsonschema>=4.21->capture-session==0.1.0->-r requirements-ci.txt (line 4)) +2026-10-08T18:41:19.6052104Z Downloading jsonschema_specifications-2025.9.1-py3-none-any.whl.metadata (2.9 kB) +2026-10-08T18:41:19.6628479Z Collecting referencing>=0.28.4 (from jsonschema>=4.21->capture-session==0.1.0->-r requirements-ci.txt (line 4)) +2026-10-08T18:41:19.6752975Z Downloading referencing-0.37.0-py3-none-any.whl.metadata (2.8 kB) +2026-10-08T18:41:19.9948950Z Collecting rpds-py>=0.25.0 (from jsonschema>=4.21->capture-session==0.1.0->-r requirements-ci.txt (line 4)) +2026-10-08T18:41:20.0067138Z Downloading rpds_py-2026.9.1-cp312-cp312-win_amd64.whl.metadata (4.2 kB) +2026-10-08T18:41:20.1831104Z Collecting contourpy>=1.0.1 (from matplotlib>=3.8->capture-analysis==0.1.0) +2026-10-08T18:41:20.1953498Z Downloading contourpy-1.4.0-cp312-cp312-win_amd64.whl.metadata (3.8 kB) +2026-10-08T18:41:20.2452934Z Collecting cycler>=0.10 (from matplotlib>=3.8->capture-analysis==0.1.0) +2026-10-08T18:41:20.2587726Z Downloading cycler-0.12.1-py3-none-any.whl.metadata (3.8 kB) +2026-10-08T18:41:20.4582738Z Collecting fonttools>=4.28.2 (from matplotlib>=3.8->capture-analysis==0.1.0) +2026-10-08T18:41:20.4719067Z Downloading fonttools-4.66.1-cp312-cp312-win_amd64.whl.metadata (132 kB) +2026-10-08T18:41:20.5966935Z Collecting kiwisolver>=1.3.1 (from matplotlib>=3.8->capture-analysis==0.1.0) +2026-10-08T18:41:20.6090476Z Downloading kiwisolver-1.5.1-cp312-cp312-win_amd64.whl.metadata (5.2 kB) +2026-10-08T18:41:20.8656530Z Collecting pillow>=9 (from matplotlib>=3.8->capture-analysis==0.1.0) +2026-10-08T18:41:20.8776822Z Downloading pillow-12.3.0-cp312-cp312-win_amd64.whl.metadata (9.3 kB) +2026-10-08T18:41:20.9400165Z Collecting pyparsing>=3 (from matplotlib>=3.8->capture-analysis==0.1.0) +2026-10-08T18:41:20.9531862Z Downloading pyparsing-3.3.3-py3-none-any.whl.metadata (5.9 kB) +2026-10-08T18:41:21.0102813Z Collecting python-dateutil>=2.7 (from matplotlib>=3.8->capture-analysis==0.1.0) +2026-10-08T18:41:21.0220681Z Downloading python_dateutil-2.9.0.post0-py2.py3-none-any.whl.metadata (8.4 kB) +2026-10-08T18:41:21.0802650Z Collecting tzdata (from pandas>=2.1->capture-analysis==0.1.0) +2026-10-08T18:41:21.0921538Z Downloading tzdata-2026.5-py2.py3-none-any.whl.metadata (1.4 kB) +2026-10-08T18:41:21.1457125Z Collecting six>=1.5 (from python-dateutil>=2.7->matplotlib>=3.8->capture-analysis==0.1.0) +2026-10-08T18:41:21.1573016Z Downloading six-1.17.0-py2.py3-none-any.whl.metadata (1.7 kB) +2026-10-08T18:41:21.1981067Z Downloading grpcio_tools-1.62.3-cp312-cp312-win_amd64.whl (1.1 MB) +2026-10-08T18:41:21.2389847Z ---------------------------------------- 1.1/1.1 MB 25.5 MB/s 0:00:00 +2026-10-08T18:41:21.2503688Z Downloading mcap-1.5.0-py3-none-any.whl (21 kB) +2026-10-08T18:41:21.2791947Z Downloading ruff-0.16.10-py3-none-win_amd64.whl (10.6 MB) +2026-10-08T18:41:21.3826807Z ---------------------------------------- 10.6/10.6 MB 109.8 MB/s 0:00:00 +2026-10-08T18:41:21.3953816Z Downloading protobuf-4.25.9-cp310-abi3-win_amd64.whl (413 kB) +2026-10-08T18:41:21.4468297Z Downloading pyside6-6.12.0-cp310-abi3-win_amd64.whl (578 kB) +2026-10-08T18:41:21.4648202Z ---------------------------------------- 579.0/579.0 kB 19.8 MB/s 0:00:00 +2026-10-08T18:41:21.4766575Z Downloading pyside6_addons-6.12.0-cp310-abi3-win_amd64.whl (40.5 MB) +2026-10-08T18:41:21.9336082Z ---------------------------------------- 40.5/40.5 MB 88.7 MB/s 0:00:00 +2026-10-08T18:41:21.9454527Z Downloading pyside6_essentials-6.12.0-cp310-abi3-win_amd64.whl (82.2 MB) +2026-10-08T18:41:23.0583014Z ---------------------------------------- 82.2/82.2 MB 73.8 MB/s 0:00:01 +2026-10-08T18:41:23.0694532Z Downloading pyside6_pdf-6.12.0.140-cp310-abi3-win_amd64.whl (3.0 MB) +2026-10-08T18:41:23.1092395Z ---------------------------------------- 3.0/3.0 MB 87.8 MB/s 0:00:00 +2026-10-08T18:41:23.1241673Z Downloading pyside6_webengine-6.12.0.140-cp310-abi3-win_amd64.whl (131.7 MB) +2026-10-08T18:41:25.0396200Z ---------------------------------------- 131.7/131.7 MB 69.0 MB/s 0:00:01 +2026-10-08T18:41:25.0513385Z Downloading shiboken6-6.12.0-cp310-abi3-win_amd64.whl (1.3 MB) +2026-10-08T18:41:25.0764285Z ---------------------------------------- 1.3/1.3 MB 66.9 MB/s 0:00:00 +2026-10-08T18:41:25.0879655Z Downloading pytest-9.1.1-py3-none-any.whl (386 kB) +2026-10-08T18:41:25.1168090Z Downloading pluggy-1.6.0-py3-none-any.whl (20 kB) +2026-10-08T18:41:25.1446275Z Downloading pytest_cov-7.1.0-py3-none-any.whl (22 kB) +2026-10-08T18:41:25.1717120Z Downloading coverage-7.16.2-cp312-cp312-win_amd64.whl (226 kB) +2026-10-08T18:41:25.1998346Z Downloading grpcio-1.84.0-cp312-cp312-win_amd64.whl (5.3 MB) +2026-10-08T18:41:25.2460102Z ---------------------------------------- 5.3/5.3 MB 106.2 MB/s 0:00:00 +2026-10-08T18:41:25.2572528Z Downloading typing_extensions-4.16.0-py3-none-any.whl (45 kB) +2026-10-08T18:41:25.2842156Z Downloading iniconfig-2.3.1-py3-none-any.whl (7.6 kB) +2026-10-08T18:41:25.3093727Z Downloading jsonschema-4.26.0-py3-none-any.whl (90 kB) +2026-10-08T18:41:25.3407369Z Downloading attrs-26.1.0-py3-none-any.whl (67 kB) +2026-10-08T18:41:25.3660356Z Downloading jsonschema_specifications-2025.9.1-py3-none-any.whl (18 kB) +2026-10-08T18:41:25.3919731Z Downloading matplotlib-3.11.2-cp312-cp312-win_amd64.whl (9.3 MB) +2026-10-08T18:41:25.4640057Z ---------------------------------------- 9.3/9.3 MB 144.2 MB/s 0:00:00 +2026-10-08T18:41:25.4757196Z Downloading contourpy-1.4.0-cp312-cp312-win_amd64.whl (234 kB) +2026-10-08T18:41:25.5141811Z Downloading cycler-0.12.1-py3-none-any.whl (8.3 kB) +2026-10-08T18:41:25.6018318Z Downloading fonttools-4.66.1-cp312-cp312-win_amd64.whl (2.5 MB) +2026-10-08T18:41:25.6540408Z ---------------------------------------- 2.5/2.5 MB 35.3 MB/s 0:00:00 +2026-10-08T18:41:25.6657973Z Downloading kiwisolver-1.5.1-cp312-cp312-win_amd64.whl (70 kB) +2026-10-08T18:41:25.7074505Z Downloading numpy-2.5.3-cp312-cp312-win_amd64.whl (12.6 MB) +2026-10-08T18:41:25.7978235Z ---------------------------------------- 12.6/12.6 MB 130.9 MB/s 0:00:00 +2026-10-08T18:41:25.8102561Z Downloading pandas-3.0.6-cp312-cp312-win_amd64.whl (9.7 MB) +2026-10-08T18:41:25.8900241Z ---------------------------------------- 9.7/9.7 MB 120.5 MB/s 0:00:00 +2026-10-08T18:41:25.9014863Z Downloading pillow-12.3.0-cp312-cp312-win_amd64.whl (7.2 MB) +2026-10-08T18:41:25.9649733Z ---------------------------------------- 7.2/7.2 MB 148.2 MB/s 0:00:00 +2026-10-08T18:41:25.9850009Z Downloading pyarrow-25.0.1-cp312-cp312-win_amd64.whl (28.0 MB) +2026-10-08T18:41:26.2872460Z ---------------------------------------- 28.0/28.0 MB 93.2 MB/s 0:00:00 +2026-10-08T18:41:26.2996494Z Downloading pygments-2.21.0-py3-none-any.whl (1.3 MB) +2026-10-08T18:41:26.3361670Z ---------------------------------------- 1.3/1.3 MB 31.9 MB/s 0:00:00 +2026-10-08T18:41:26.3478751Z Downloading pyparsing-3.3.3-py3-none-any.whl (126 kB) +2026-10-08T18:41:26.3889803Z Downloading pyqtgraph-0.14.0-py3-none-any.whl (1.9 MB) +2026-10-08T18:41:26.4242121Z ---------------------------------------- 1.9/1.9 MB 52.0 MB/s 0:00:00 +2026-10-08T18:41:26.4392354Z Downloading python_dateutil-2.9.0.post0-py2.py3-none-any.whl (229 kB) +2026-10-08T18:41:26.4762736Z Downloading pyyaml-6.0.3-cp312-cp312-win_amd64.whl (154 kB) +2026-10-08T18:41:26.5056038Z Downloading referencing-0.37.0-py3-none-any.whl (26 kB) +2026-10-08T18:41:26.5379101Z Downloading rpds_py-2026.9.1-cp312-cp312-win_amd64.whl (222 kB) +2026-10-08T18:41:26.5802614Z Downloading scipy-1.18.1-cp312-cp312-win_amd64.whl (36.7 MB) +2026-10-08T18:41:27.3019438Z ---------------------------------------- 36.7/36.7 MB 50.6 MB/s 0:00:00 +2026-10-08T18:41:27.3137858Z Downloading six-1.17.0-py2.py3-none-any.whl (11 kB) +2026-10-08T18:41:27.3568281Z Downloading lz4-4.4.5-cp312-cp312-win_amd64.whl (99 kB) +2026-10-08T18:41:27.3847170Z Using cached setuptools-84.0.0-py3-none-any.whl (818 kB) +2026-10-08T18:41:27.3979288Z Downloading tzdata-2026.5-py2.py3-none-any.whl (347 kB) +2026-10-08T18:41:27.4254492Z Downloading zstandard-0.25.0-cp312-cp312-win_amd64.whl (506 kB) +2026-10-08T18:41:28.0446557Z Building wheels for collected packages: capture-protocol, capture-session, capture-analysis, capture-worker, capture-desktop +2026-10-08T18:41:28.8523354Z Building editable for capture-protocol (pyproject.toml): started +2026-10-08T18:41:29.2291562Z Building editable for capture-protocol (pyproject.toml): finished with status 'done' +2026-10-08T18:41:29.2325428Z Created wheel for capture-protocol: filename=capture_protocol-0.1.0-0.editable-py3-none-any.whl size=7398 sha256=74f5b123ef63870573d62852846385634c0781501bfa160498cc831e7e06118e +2026-10-08T18:41:29.2327704Z Stored in directory: C:\Users\runneradmin\AppData\Local\Temp\pip-ephem-wheel-cache-iy411gcj\wheels\be\38\74\adf0f9a8f0ba8d26599b299cff33b892a58ed35959c9e09acd +2026-10-08T18:41:29.2373038Z Building editable for capture-session (pyproject.toml): started +2026-10-08T18:41:29.5764249Z Building editable for capture-session (pyproject.toml): finished with status 'done' +2026-10-08T18:41:29.5799512Z Created wheel for capture-session: filename=capture_session-0.1.0-0.editable-py3-none-any.whl size=2863 sha256=ede2369ea7e581a7a326e3c2b5819c81737343f8fc6b0b2b17c0ac75c3e4f023 +2026-10-08T18:41:29.5801662Z Stored in directory: C:\Users\runneradmin\AppData\Local\Temp\pip-ephem-wheel-cache-iy411gcj\wheels\49\8f\6e\163bd066522d89fdd0906cf22a1687ebc628821c7980903be9 +2026-10-08T18:41:29.5845189Z Building editable for capture-analysis (pyproject.toml): started +2026-10-08T18:41:29.9604535Z Building editable for capture-analysis (pyproject.toml): finished with status 'done' +2026-10-08T18:41:29.9635479Z Created wheel for capture-analysis: filename=capture_analysis-0.1.0-0.editable-py3-none-any.whl size=3050 sha256=02382b2a15b5123617c2e39a3087a08c1a28ad8e86e893857425a83d46bb6259 +2026-10-08T18:41:29.9637618Z Stored in directory: C:\Users\runneradmin\AppData\Local\Temp\pip-ephem-wheel-cache-iy411gcj\wheels\f4\d1\58\14e4976a0c15c2c470fc12f9a2873cc8c4bc7bd989766b97b4 +2026-10-08T18:41:29.9681668Z Building editable for capture-worker (pyproject.toml): started +2026-10-08T18:41:30.3359203Z Building editable for capture-worker (pyproject.toml): finished with status 'done' +2026-10-08T18:41:30.3394224Z Created wheel for capture-worker: filename=capture_worker-0.1.0-0.editable-py3-none-any.whl size=7659 sha256=e32d1edd9be4ed3f4ea6b49fa5ea82c2eb27175ba76bcf2d5f853aa465060882 +2026-10-08T18:41:30.3396093Z Stored in directory: C:\Users\runneradmin\AppData\Local\Temp\pip-ephem-wheel-cache-iy411gcj\wheels\91\10\bd\b56fd1c22822b4cd753ca217f259119db33a4fa54b26c297ee +2026-10-08T18:41:30.3441100Z Building editable for capture-desktop (pyproject.toml): started +2026-10-08T18:41:30.7048024Z Building editable for capture-desktop (pyproject.toml): finished with status 'done' +2026-10-08T18:41:30.7083864Z Created wheel for capture-desktop: filename=capture_desktop-0.1.0-0.editable-py3-none-any.whl size=3184 sha256=684a9220c5dfcbc09d69964340ab998956b37443c65d9d9e117389ccbfe6757a +2026-10-08T18:41:30.7085737Z Stored in directory: C:\Users\runneradmin\AppData\Local\Temp\pip-ephem-wheel-cache-iy411gcj\wheels\04\f4\80\083223dba330947d948f2d768e3de9f1e54ae638d0a391d614 +2026-10-08T18:41:30.7111020Z Successfully built capture-protocol capture-session capture-analysis capture-worker capture-desktop +2026-10-08T18:41:30.8854495Z Installing collected packages: zstandard, tzdata, typing-extensions, six, shiboken6, setuptools, ruff, rpds-py, pyyaml, pyparsing, pygments, pyarrow, protobuf, pluggy, pillow, numpy, lz4, kiwisolver, iniconfig, fonttools, cycler, coverage, attrs, scipy, referencing, python-dateutil, pytest, PySide6_Essentials, pyqtgraph, mcap, grpcio, contourpy, capture-protocol, pytest-cov, PySide6_Pdf, PySide6_Addons, pandas, matplotlib, jsonschema-specifications, grpcio-tools, capture-worker, PySide6_WebEngine, jsonschema, PySide6, capture-session, capture-desktop, capture-analysis +2026-10-08T18:42:22.6046310Z +2026-10-08T18:42:22.6100190Z Successfully installed PySide6-6.12.0 PySide6_Addons-6.12.0 PySide6_Essentials-6.12.0 PySide6_Pdf-6.12.0.140 PySide6_WebEngine-6.12.0.140 attrs-26.1.0 capture-analysis-0.1.0 capture-desktop-0.1.0 capture-protocol-0.1.0 capture-session-0.1.0 capture-worker-0.1.0 contourpy-1.4.0 coverage-7.16.2 cycler-0.12.1 fonttools-4.66.1 grpcio-1.84.0 grpcio-tools-1.62.3 iniconfig-2.3.1 jsonschema-4.26.0 jsonschema-specifications-2025.9.1 kiwisolver-1.5.1 lz4-4.4.5 matplotlib-3.11.2 mcap-1.5.0 numpy-2.5.3 pandas-3.0.6 pillow-12.3.0 pluggy-1.6.0 protobuf-4.25.9 pyarrow-25.0.1 pygments-2.21.0 pyparsing-3.3.3 pyqtgraph-0.14.0 pytest-9.1.1 pytest-cov-7.1.0 python-dateutil-2.9.0.post0 pyyaml-6.0.3 referencing-0.37.0 rpds-py-2026.9.1 ruff-0.16.10 scipy-1.18.1 setuptools-84.0.0 shiboken6-6.12.0 six-1.17.0 typing-extensions-4.16.0 tzdata-2026.5 zstandard-0.25.0 +2026-10-08T18:42:23.4091185Z ##[group]Run python -m pip check +2026-10-08T18:42:23.4091545Z python -m pip check +2026-10-08T18:42:23.4135227Z shell: C:\Program Files\PowerShell\7\pwsh.EXE -command ". '{0}'" +2026-10-08T18:42:23.4135577Z env: +2026-10-08T18:42:23.4135862Z pythonLocation: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T18:42:23.4136339Z PKG_CONFIG_PATH: C:\hostedtoolcache\windows\Python\3.12.10\x64/lib/pkgconfig +2026-10-08T18:42:23.4136804Z Python_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T18:42:23.4137208Z Python2_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T18:42:23.4137601Z Python3_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T18:42:23.4137915Z ##[endgroup] +2026-10-08T18:42:24.1892770Z No broken requirements found. +2026-10-08T18:42:24.3593416Z ##[group]Run python tools/check_ci_contract.py --check-environment +2026-10-08T18:42:24.3593958Z python tools/check_ci_contract.py --check-environment +2026-10-08T18:42:24.3634266Z shell: C:\Program Files\PowerShell\7\pwsh.EXE -command ". '{0}'" +2026-10-08T18:42:24.3634607Z env: +2026-10-08T18:42:24.3634872Z pythonLocation: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T18:42:24.3635361Z PKG_CONFIG_PATH: C:\hostedtoolcache\windows\Python\3.12.10\x64/lib/pkgconfig +2026-10-08T18:42:24.3635816Z Python_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T18:42:24.3636229Z Python2_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T18:42:24.3636614Z Python3_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T18:42:24.3636933Z ##[endgroup] +2026-10-08T18:42:30.7534155Z Matplotlib is building the font cache; this may take a moment. +2026-10-08T18:42:46.3844915Z { +2026-10-08T18:42:46.3846145Z "accepted": true, +2026-10-08T18:42:46.3846491Z "errors": [] +2026-10-08T18:42:46.3846783Z } +2026-10-08T18:42:46.7136620Z ##[group]Run python tools/gen_protos.py +2026-10-08T18:42:46.7137001Z python tools/gen_protos.py +2026-10-08T18:42:46.7177615Z shell: C:\Program Files\PowerShell\7\pwsh.EXE -command ". '{0}'" +2026-10-08T18:42:46.7177967Z env: +2026-10-08T18:42:46.7178241Z pythonLocation: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T18:42:46.7178704Z PKG_CONFIG_PATH: C:\hostedtoolcache\windows\Python\3.12.10\x64/lib/pkgconfig +2026-10-08T18:42:46.7179150Z Python_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T18:42:46.7180337Z Python2_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T18:42:46.7180731Z Python3_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T18:42:46.7181051Z ##[endgroup] +2026-10-08T18:42:47.1923842Z Running: C:\hostedtoolcache\windows\Python\3.12.10\x64\python.exe -m grpc_tools.protoc --proto_path=D:\a\CaptureSuite\CaptureSuite\schemas\proto --python_out=D:\a\CaptureSuite\CaptureSuite\libs\python\capture_protocol\capture_protocol\generated --descriptor_set_out=D:\a\CaptureSuite\CaptureSuite\build\generated\capture_v1.desc --include_imports --proto_path=C:\hostedtoolcache\windows\Python\3.12.10\x64\Lib\site-packages\grpc_tools\_proto capture/v1/arrays.proto capture/v1/common.proto capture/v1/control.proto capture/v1/data/emg_batch.proto capture/v1/data/imu_frame.proto capture/v1/data/numeric_batch.proto capture/v1/data/radar_doppler.proto capture/v1/data/radar_frame.proto capture/v1/data/video_timing.proto capture/v1/events.proto capture/v1/health.proto capture/v1/presets.proto capture/v1/preview.proto capture/v1/project.proto capture/v1/source.proto capture/v1/storage.proto capture/v1/worker.proto +2026-10-08T18:42:47.1929086Z Wrote Python bindings under D:\a\CaptureSuite\CaptureSuite\libs\python\capture_protocol\capture_protocol\generated +2026-10-08T18:42:47.1929900Z Wrote descriptor set D:\a\CaptureSuite\CaptureSuite\build\generated\capture_v1.desc +2026-10-08T18:42:47.3288881Z ##[group]Run git diff --exit-code -- libs/python/capture_protocol/capture_protocol/generated +2026-10-08T18:42:47.3289592Z git diff --exit-code -- libs/python/capture_protocol/capture_protocol/generated +2026-10-08T18:42:47.3332148Z shell: C:\Program Files\PowerShell\7\pwsh.EXE -command ". '{0}'" +2026-10-08T18:42:47.3332753Z env: +2026-10-08T18:42:47.3333194Z pythonLocation: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T18:42:47.3334019Z PKG_CONFIG_PATH: C:\hostedtoolcache\windows\Python\3.12.10\x64/lib/pkgconfig +2026-10-08T18:42:47.3334851Z Python_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T18:42:47.3335577Z Python2_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T18:42:47.3336280Z Python3_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T18:42:47.3336851Z ##[endgroup] +2026-10-08T18:42:47.8426426Z ##[group]Run python tools/gen_session_schemas.py +2026-10-08T18:42:47.8426870Z python tools/gen_session_schemas.py +2026-10-08T18:42:47.8474326Z shell: C:\Program Files\PowerShell\7\pwsh.EXE -command ". '{0}'" +2026-10-08T18:42:47.8474678Z env: +2026-10-08T18:42:47.8474939Z pythonLocation: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T18:42:47.8475394Z PKG_CONFIG_PATH: C:\hostedtoolcache\windows\Python\3.12.10\x64/lib/pkgconfig +2026-10-08T18:42:47.8476016Z Python_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T18:42:47.8476691Z Python2_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T18:42:47.8477394Z Python3_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T18:42:47.8477829Z ##[endgroup] +2026-10-08T18:42:48.1900550Z Wrote 19 schemas to D:\a\CaptureSuite\CaptureSuite\schemas\session\jsonschema +2026-10-08T18:42:48.3039387Z ##[group]Run git diff --exit-code -- schemas/session/jsonschema +2026-10-08T18:42:48.3039918Z git diff --exit-code -- schemas/session/jsonschema +2026-10-08T18:42:48.3083537Z shell: C:\Program Files\PowerShell\7\pwsh.EXE -command ". '{0}'" +2026-10-08T18:42:48.3083893Z env: +2026-10-08T18:42:48.3084156Z pythonLocation: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T18:42:48.3084615Z PKG_CONFIG_PATH: C:\hostedtoolcache\windows\Python\3.12.10\x64/lib/pkgconfig +2026-10-08T18:42:48.3085050Z Python_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T18:42:48.3085443Z Python2_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T18:42:48.3085843Z Python3_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T18:42:48.3086454Z ##[endgroup] +2026-10-08T18:42:48.6966101Z ##[group]Run ruff check libs/python/capture_protocol libs/python/capture_session libs/python/capture_analysis libs/python/capture_worker workers/python_host desktop/capture_desktop tools tests plugins/example_sine_py plugins/lsl_bridge +2026-10-08T18:42:48.6967838Z ruff check libs/python/capture_protocol libs/python/capture_session libs/python/capture_analysis libs/python/capture_worker workers/python_host desktop/capture_desktop tools tests plugins/example_sine_py plugins/lsl_bridge +2026-10-08T18:42:48.7008981Z shell: C:\Program Files\PowerShell\7\pwsh.EXE -command ". '{0}'" +2026-10-08T18:42:48.7009321Z env: +2026-10-08T18:42:48.7009592Z pythonLocation: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T18:42:48.7010052Z PKG_CONFIG_PATH: C:\hostedtoolcache\windows\Python\3.12.10\x64/lib/pkgconfig +2026-10-08T18:42:48.7010495Z Python_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T18:42:48.7010947Z Python2_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T18:42:48.7011333Z Python3_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T18:42:48.7011635Z ##[endgroup] +2026-10-08T18:42:49.1148936Z All checks passed! +2026-10-08T18:42:49.2212946Z ##[group]Run python tools/check_licenses.py --enforce-spdx +2026-10-08T18:42:49.2213450Z python tools/check_licenses.py --enforce-spdx +2026-10-08T18:42:49.2253992Z shell: C:\Program Files\PowerShell\7\pwsh.EXE -command ". '{0}'" +2026-10-08T18:42:49.2254342Z env: +2026-10-08T18:42:49.2254605Z pythonLocation: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T18:42:49.2255063Z PKG_CONFIG_PATH: C:\hostedtoolcache\windows\Python\3.12.10\x64/lib/pkgconfig +2026-10-08T18:42:49.2255499Z Python_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T18:42:49.2255901Z Python2_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T18:42:49.2256640Z Python3_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T18:42:49.2257246Z ##[endgroup] +2026-10-08T18:42:50.0001912Z license check OK +2026-10-08T18:42:50.1121846Z ##[group]Run python tools/run_ci_tests.py +2026-10-08T18:42:50.1122244Z python tools/run_ci_tests.py +2026-10-08T18:42:50.1163277Z shell: C:\Program Files\PowerShell\7\pwsh.EXE -command ". '{0}'" +2026-10-08T18:42:50.1163626Z env: +2026-10-08T18:42:50.1163884Z pythonLocation: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T18:42:50.1164356Z PKG_CONFIG_PATH: C:\hostedtoolcache\windows\Python\3.12.10\x64/lib/pkgconfig +2026-10-08T18:42:50.1164814Z Python_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T18:42:50.1165205Z Python2_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T18:42:50.1165867Z Python3_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T18:42:50.1166776Z QT_QPA_PLATFORM: offscreen +2026-10-08T18:42:50.1166992Z ##[endgroup] +2026-10-08T18:47:48.4473444Z ........................................................................ [ 12%] +2026-10-08T18:47:48.4474596Z ........................................................................ [ 25%] +2026-10-08T18:47:48.4475251Z ........................................................................ [ 38%] +2026-10-08T18:47:48.4475872Z ........................................................................ [ 51%] +2026-10-08T18:47:48.4476490Z ..................................................................ssssss [ 64%] +2026-10-08T18:47:48.4477103Z ........................................................................ [ 77%] +2026-10-08T18:47:48.4477707Z ........................................................................ [ 89%] +2026-10-08T18:47:48.4478885Z ................[analysis-history:start] tests/ui/test_analysis_history.py::test_real_completed_and_failed_jobs_are_read_only +2026-10-08T18:47:48.4480212Z .[analysis-history:finish] tests/ui/test_analysis_history.py::test_real_completed_and_failed_jobs_are_read_only 0.093s +2026-10-08T18:47:48.4481912Z [analysis-history:start] tests/ui/test_analysis_history.py::test_copied_package_keeps_its_saved_result +2026-10-08T18:47:48.4483189Z .[analysis-history:finish] tests/ui/test_analysis_history.py::test_copied_package_keeps_its_saved_result 0.094s +2026-10-08T18:47:48.4484548Z [analysis-history:start] tests/ui/test_analysis_history.py::test_catalog_explains_unreadable_rows_without_hiding_good_jobs +2026-10-08T18:47:48.4485992Z .[analysis-history:finish] tests/ui/test_analysis_history.py::test_catalog_explains_unreadable_rows_without_hiding_good_jobs 0.085s +2026-10-08T18:47:48.4487349Z [analysis-history:start] tests/ui/test_analysis_history.py::test_missing_details_and_long_log_are_explicit +2026-10-08T18:47:48.4488629Z .[analysis-history:finish] tests/ui/test_analysis_history.py::test_missing_details_and_long_log_are_explicit 0.073s +2026-10-08T18:47:48.4489951Z [analysis-history:start] tests/ui/test_analysis_history.py::test_native_open_and_details_leave_the_package_unchanged +2026-10-08T18:47:48.4491354Z .[analysis-history:finish] tests/ui/test_analysis_history.py::test_native_open_and_details_leave_the_package_unchanged 0.116s +2026-10-08T18:47:48.4492748Z [analysis-history:start] tests/ui/test_analysis_history.py::test_refresh_preserves_the_view_and_offers_a_new_retained_job +2026-10-08T18:47:48.4494284Z .[analysis-history:finish] tests/ui/test_analysis_history.py::test_refresh_preserves_the_view_and_offers_a_new_retained_job 0.158s +2026-10-08T18:47:48.4495717Z [analysis-history:start] tests/ui/test_analysis_history.py::test_real_threaded_completion_populates_history +2026-10-08T18:47:48.4497047Z .[analysis-history:finish] tests/ui/test_analysis_history.py::test_real_threaded_completion_populates_history 0.114s +2026-10-08T18:47:48.4498434Z [analysis-history:start] tests/ui/test_analysis_history.py::test_real_threaded_failure_offers_its_retained_diagnostics +2026-10-08T18:47:48.4499947Z .[analysis-history:finish] tests/ui/test_analysis_history.py::test_real_threaded_failure_offers_its_retained_diagnostics 0.101s +2026-10-08T18:47:48.4503604Z ................................. [100%] +2026-10-08T18:47:48.4504312Z ============================== warnings summary =============================== +2026-10-08T18:47:48.4504937Z :488 +2026-10-08T18:47:48.4506953Z :488: DeprecationWarning: Type google._upb._message.MessageMapContainer uses PyType_Spec with a metaclass that has custom tp_new. This is deprecated and will no longer be allowed in Python 3.14. +2026-10-08T18:47:48.4508425Z +2026-10-08T18:47:48.4508583Z :488 +2026-10-08T18:47:48.4510134Z :488: DeprecationWarning: Type google._upb._message.ScalarMapContainer uses PyType_Spec with a metaclass that has custom tp_new. This is deprecated and will no longer be allowed in Python 3.14. +2026-10-08T18:47:48.4511574Z +2026-10-08T18:47:48.4512025Z -- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html +2026-10-08T18:47:48.4512835Z =========================== short test summary info =========================== +2026-10-08T18:47:48.4513828Z SKIPPED [1] tests\protocol\test_daemon_e2e.py:74: capture_daemon.exe not built (run cmake --build) +2026-10-08T18:47:48.4514967Z SKIPPED [1] tests\protocol\test_daemon_e2e.py:148: capture_daemon.exe not built (run cmake --build) +2026-10-08T18:47:48.4516315Z SKIPPED [1] tests\protocol\test_daemon_e2e.py:161: capture_daemon.exe not built (run cmake --build) +2026-10-08T18:47:48.4517545Z SKIPPED [1] tests\protocol\test_daemon_e2e.py:196: capture_daemon.exe not built (run cmake --build) +2026-10-08T18:47:48.4518679Z SKIPPED [1] tests\protocol\test_daemon_e2e.py:238: capture_daemon.exe not built (run cmake --build) +2026-10-08T18:47:48.4519805Z SKIPPED [1] tests\protocol\test_daemon_e2e.py:262: capture_daemon.exe not built (run cmake --build) +2026-10-08T18:47:48.4520684Z 555 passed, 6 skipped, 2 warnings in 295.60s (0:04:55) +2026-10-08T18:47:48.4521327Z +2026-10-08T18:47:48.4521496Z { +2026-10-08T18:47:48.4521875Z "schema": "capturesuite.test-receipt.v1", +2026-10-08T18:47:48.4522498Z "accepted": true, +2026-10-08T18:47:48.4522917Z "process_exit": 0, +2026-10-08T18:47:48.4523299Z "counts": { +2026-10-08T18:47:48.4523626Z "tests": 561, +2026-10-08T18:47:48.4523985Z "passed": 555, +2026-10-08T18:47:48.4524330Z "failures": 0, +2026-10-08T18:47:48.4524652Z "errors": 0, +2026-10-08T18:47:48.4524974Z "skipped": 6 +2026-10-08T18:47:48.4525298Z }, +2026-10-08T18:47:48.4525865Z "junit_sha256": "024d03bebc15c2640a86fc8309a8a1cc2ad411f87a000f404b0ef846f0f10764", +2026-10-08T18:47:48.4526608Z "problems": [], +2026-10-08T18:47:48.4527197Z "scope": "Process and test-evidence consistency, not clinical validation", +2026-10-08T18:47:48.4527961Z "seconds": 296.77340969999995, +2026-10-08T18:47:48.4528479Z "created_at": "2026-10-08T18:47:47.824177+00:00", +2026-10-08T18:47:48.4529202Z "run_directory": "build/evidence/python-20261008T184250Z-e1bb4f7d", +2026-10-08T18:47:48.4530113Z "log_sha256": "2a6e81ac2871463414d40e41de21c2e62b93497289601fe13ae3529aa9b6a935", +2026-10-08T18:47:48.4530968Z "source_commit": "f17f811366bc9915e0f001b42d9df86afc353213", +2026-10-08T18:47:48.4531612Z "source_worktree_dirty": false, +2026-10-08T18:47:48.4532363Z "source_tree_sha256": "e265754e62a900bd080b409d4fa720d570003c24e6d06fb5136cf9275856a446", +2026-10-08T18:47:48.4533141Z "source_file_count": 1142, +2026-10-08T18:47:48.4533565Z "github": { +2026-10-08T18:47:48.4533947Z "GITHUB_ACTIONS": "true", +2026-10-08T18:47:48.4534383Z "GITHUB_EVENT_NAME": "pull_request", +2026-10-08T18:47:48.4534943Z "GITHUB_SHA": "f17f811366bc9915e0f001b42d9df86afc353213", +2026-10-08T18:47:48.4535513Z "GITHUB_REF": "refs/pull/71/merge", +2026-10-08T18:47:48.4536072Z "GITHUB_HEAD_REF": "work/analysis-history-401c5d17da79", +2026-10-08T18:47:48.4536634Z "GITHUB_BASE_REF": "main", +2026-10-08T18:47:48.4537044Z "GITHUB_RUN_ID": "37826104818", +2026-10-08T18:47:48.4538690Z "GITHUB_WORKFLOW_REF": "Jacob-Met/CaptureSuite/.github/workflows/ci.yml@refs/pull/71/merge" +2026-10-08T18:47:48.4539493Z }, +2026-10-08T18:47:48.4539845Z "source_unchanged_during_test": true +2026-10-08T18:47:48.4540341Z } +2026-10-08T18:47:48.5684282Z ##[group]Run actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a +2026-10-08T18:47:48.5684836Z with: +2026-10-08T18:47:48.5685084Z name: python-test-evidence +2026-10-08T18:47:48.5685366Z path: build/evidence/ +2026-10-08T18:47:48.5685622Z if-no-files-found: warn +2026-10-08T18:47:48.5685876Z retention-days: 7 +2026-10-08T18:47:48.5712691Z compression-level: 6 +2026-10-08T18:47:48.5712956Z overwrite: false +2026-10-08T18:47:48.5713177Z include-hidden-files: false +2026-10-08T18:47:48.5713458Z archive: true +2026-10-08T18:47:48.5713691Z env: +2026-10-08T18:47:48.5714029Z pythonLocation: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T18:47:48.5714541Z PKG_CONFIG_PATH: C:\hostedtoolcache\windows\Python\3.12.10\x64/lib/pkgconfig +2026-10-08T18:47:48.5715072Z Python_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T18:47:48.5715510Z Python2_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T18:47:48.5716018Z Python3_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T18:47:48.5716387Z ##[endgroup] +2026-10-08T18:47:48.8901358Z With the provided path, there will be 281 files uploaded +2026-10-08T18:47:48.8907472Z Artifact name is valid! +2026-10-08T18:47:48.8908969Z Root directory input is valid! +2026-10-08T18:47:49.2140420Z Uploading artifact: python-test-evidence.zip +2026-10-08T18:47:49.2189165Z Beginning upload of artifact content to blob storage +2026-10-08T18:47:49.9861524Z Uploaded bytes 1613155 +2026-10-08T18:47:50.0252565Z Finished uploading artifact content to blob storage! +2026-10-08T18:47:50.0253439Z SHA256 digest of uploaded artifact is 3f26c00b6f7ba7ba472ac417109df28ceb52ca1df2cbc377b78c09cd8d0bacb6 +2026-10-08T18:47:50.0255368Z Finalizing artifact upload +2026-10-08T18:47:50.3497324Z Artifact python-test-evidence successfully finalized. Artifact ID 11572321018 +2026-10-08T18:47:50.3498792Z Artifact python-test-evidence has been successfully uploaded! Final size is 1613155 bytes. Artifact ID is 11572321018 +2026-10-08T18:47:50.3504653Z Artifact download URL: https://github.com/Jacob-Met/CaptureSuite/actions/runs/37826104818/artifacts/11572321018 +2026-10-08T18:47:50.3811264Z Post job cleanup. +2026-10-08T18:47:50.5223319Z (node:7576) [DEP0040] DeprecationWarning: The `punycode` module is deprecated. Please use a userland alternative instead. +2026-10-08T18:47:50.5224199Z (Use `node --trace-deprecation ...` to show where the warning was created) +2026-10-08T18:47:50.5488855Z Post job cleanup. +2026-10-08T18:47:50.7984728Z [command]"C:\Program Files\Git\bin\git.exe" version +2026-10-08T18:47:50.8277716Z git version 2.56.0.windows.1 +2026-10-08T18:47:50.8350233Z Temporarily overriding HOME='D:\a\_temp\427e99bd-b099-4900-ba5b-18d86a931f30' before making global git config changes +2026-10-08T18:47:50.8352033Z Adding repository directory to the temporary git global config as a safe directory +2026-10-08T18:47:50.8363756Z [command]"C:\Program Files\Git\bin\git.exe" config --global --add safe.directory D:\a\CaptureSuite\CaptureSuite +2026-10-08T18:47:50.8733777Z [command]"C:\Program Files\Git\bin\git.exe" config --local --name-only --get-regexp core\.sshCommand +2026-10-08T18:47:50.9068324Z [command]"C:\Program Files\Git\bin\git.exe" submodule foreach --recursive "sh -c \"git config --local --name-only --get-regexp 'core\.sshCommand' && git config --local --unset-all 'core.sshCommand' || :\"" +2026-10-08T18:47:51.4758667Z [command]"C:\Program Files\Git\bin\git.exe" config --local --name-only --get-regexp http\.https\:\/\/github\.com\/\.extraheader +2026-10-08T18:47:51.5059058Z http.https://github.com/.extraheader +2026-10-08T18:47:51.5102290Z [command]"C:\Program Files\Git\bin\git.exe" config --local --unset-all http.https://github.com/.extraheader +2026-10-08T18:47:51.5498392Z [command]"C:\Program Files\Git\bin\git.exe" submodule foreach --recursive "sh -c \"git config --local --name-only --get-regexp 'http\.https\:\/\/github\.com\/\.extraheader' && git config --local --unset-all 'http.https://github.com/.extraheader' || :\"" +2026-10-08T18:47:52.0794220Z [command]"C:\Program Files\Git\bin\git.exe" config --local --name-only --get-regexp ^includeIf\.gitdir: +2026-10-08T18:47:52.1123607Z [command]"C:\Program Files\Git\bin\git.exe" submodule foreach --recursive "git config --local --show-origin --name-only --get-regexp remote.origin.url" +2026-10-08T18:47:52.6111731Z Cleaning up orphan processes +2026-10-08T18:47:52.6307945Z Terminate orphan process: pid (3788) (vctip) +2026-10-08T18:47:52.6362444Z Terminate orphan process: pid (5868) (MSBuild) +2026-10-08T18:47:52.6542418Z Terminate orphan process: pid (2880) (conhost) +2026-10-08T18:47:52.6820274Z ##[warning]Node.js 20 is deprecated. The following actions target Node.js 20 but are being forced to run on Node.js 24: actions/checkout@v4, actions/setup-python@v5. For more information see: https://github.blog/changelog/2025-09-19-deprecation-of-node-20-on-github-actions-runners/ diff --git a/docs/receiving/analysis-history-ci-budget-401c5d17da79/original-windows-timeout.log b/docs/receiving/analysis-history-ci-budget-401c5d17da79/original-windows-timeout.log new file mode 100644 index 00000000..78a18999 --- /dev/null +++ b/docs/receiving/analysis-history-ci-budget-401c5d17da79/original-windows-timeout.log @@ -0,0 +1,542 @@ +2026-10-08T16:50:40.1732602Z Current runner version: '2.337.0' +2026-10-08T16:50:40.1758241Z ##[group]Runner Image Provisioner +2026-10-08T16:50:40.1759051Z Hosted Compute Agent +2026-10-08T16:50:40.1759599Z Version: 20261002.596 +2026-10-08T16:50:40.1760250Z Commit: c3d12f3313a95f25162a1503be624f3b0617f8c0 +2026-10-08T16:50:40.1760933Z Build Date: 2026-10-02T22:28:27Z +2026-10-08T16:50:40.1761528Z Worker ID: {0e557afc-6416-42ff-a1a4-86af5f4cd416} +2026-10-08T16:50:40.1762207Z Region: eastus +2026-10-08T16:50:40.1762684Z Cloud: Azure +2026-10-08T16:50:40.1763142Z ##[endgroup] +2026-10-08T16:50:40.1764737Z ##[group]Operating System +2026-10-08T16:50:40.1765577Z Microsoft Windows Server 2022 +2026-10-08T16:50:40.1766464Z 10.0.20348 +2026-10-08T16:50:40.1766962Z Datacenter +2026-10-08T16:50:40.1767463Z ##[endgroup] +2026-10-08T16:50:40.1767982Z ##[group]Runner Image +2026-10-08T16:50:40.1768513Z Image: windows-2022 +2026-10-08T16:50:40.1769020Z Version: 20261004.326.1 +2026-10-08T16:50:40.1770684Z Included Software: https://github.com/actions/runner-images/blob/win22/20261004.326/images/windows/Windows2022-Readme.md +2026-10-08T16:50:40.1772353Z Image Release: https://github.com/actions/runner-images/releases/tag/win22%2F20261004.326 +2026-10-08T16:50:40.1773255Z ##[endgroup] +2026-10-08T16:50:40.1774373Z ##[group]GITHUB_TOKEN Permissions +2026-10-08T16:50:40.1776177Z Contents: read +2026-10-08T16:50:40.1776738Z Metadata: read +2026-10-08T16:50:40.1777231Z Packages: read +2026-10-08T16:50:40.1777835Z ##[endgroup] +2026-10-08T16:50:40.1779907Z Secret source: Actions +2026-10-08T16:50:40.1780720Z Cache mode: write +2026-10-08T16:50:40.1781383Z Prepare workflow directory +2026-10-08T16:50:40.2122719Z Prepare all required actions +2026-10-08T16:50:40.2168998Z Getting action download info +2026-10-08T16:50:40.3727201Z Download action repository 'actions/checkout@v4' (SHA:11d5960a326750d5838078e36cf38b85af677262) +2026-10-08T16:50:40.5367456Z Download action repository 'actions/setup-python@v5' (SHA:a26af69be951a213d495a4c3e4e4022e16d87065) +2026-10-08T16:50:40.8006955Z Download action repository 'actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a' (SHA:043fb46d1a93c77aae656e7c1c64a875d1fc6a0a) +2026-10-08T16:50:41.1484909Z Complete job name: python +2026-10-08T16:50:41.3092154Z ##[group]Run actions/checkout@v4 +2026-10-08T16:50:41.3093251Z with: +2026-10-08T16:50:41.3093724Z repository: Jacob-Met/CaptureSuite +2026-10-08T16:50:41.3098233Z token: *** +2026-10-08T16:50:41.3098682Z ssh-strict: true +2026-10-08T16:50:41.3099125Z ssh-user: git +2026-10-08T16:50:41.3099572Z persist-credentials: true +2026-10-08T16:50:41.3100063Z clean: true +2026-10-08T16:50:41.3100501Z sparse-checkout-cone-mode: true +2026-10-08T16:50:41.3101022Z fetch-depth: 1 +2026-10-08T16:50:41.3101459Z fetch-tags: false +2026-10-08T16:50:41.3101902Z show-progress: true +2026-10-08T16:50:41.3102348Z lfs: false +2026-10-08T16:50:41.3102761Z submodules: false +2026-10-08T16:50:41.3103230Z set-safe-directory: true +2026-10-08T16:50:41.3103757Z allow-unsafe-pr-checkout: false +2026-10-08T16:50:41.3104555Z ##[endgroup] +2026-10-08T16:50:41.4471667Z Syncing repository: Jacob-Met/CaptureSuite +2026-10-08T16:50:41.4473592Z ##[group]Getting Git version info +2026-10-08T16:50:41.4474432Z Working directory is 'D:\a\CaptureSuite\CaptureSuite' +2026-10-08T16:50:41.5889109Z [command]"C:\Program Files\Git\bin\git.exe" version +2026-10-08T16:50:43.3854406Z git version 2.56.0.windows.1 +2026-10-08T16:50:43.3899541Z ##[endgroup] +2026-10-08T16:50:43.3917906Z Temporarily overriding HOME='D:\a\_temp\bfe3167c-7825-46d1-8d5d-7a72fbb78fb6' before making global git config changes +2026-10-08T16:50:43.3919021Z Adding repository directory to the temporary git global config as a safe directory +2026-10-08T16:50:43.3929370Z [command]"C:\Program Files\Git\bin\git.exe" config --global --add safe.directory D:\a\CaptureSuite\CaptureSuite +2026-10-08T16:50:43.5775530Z Deleting the contents of 'D:\a\CaptureSuite\CaptureSuite' +2026-10-08T16:50:43.5780572Z ##[group]Initializing the repository +2026-10-08T16:50:43.5789821Z [command]"C:\Program Files\Git\bin\git.exe" init D:\a\CaptureSuite\CaptureSuite +2026-10-08T16:50:43.8783912Z Initialized empty Git repository in D:/a/CaptureSuite/CaptureSuite/.git/ +2026-10-08T16:50:43.8825991Z [command]"C:\Program Files\Git\bin\git.exe" remote add origin https://github.com/Jacob-Met/CaptureSuite +2026-10-08T16:50:44.0614832Z ##[endgroup] +2026-10-08T16:50:44.0615371Z ##[group]Disabling automatic garbage collection +2026-10-08T16:50:44.0624256Z [command]"C:\Program Files\Git\bin\git.exe" config --local gc.auto 0 +2026-10-08T16:50:44.0916303Z ##[endgroup] +2026-10-08T16:50:44.0917248Z ##[group]Setting up auth +2026-10-08T16:50:44.0929436Z [command]"C:\Program Files\Git\bin\git.exe" config --local --name-only --get-regexp core\.sshCommand +2026-10-08T16:50:44.1227324Z [command]"C:\Program Files\Git\bin\git.exe" submodule foreach --recursive "sh -c \"git config --local --name-only --get-regexp 'core\.sshCommand' && git config --local --unset-all 'core.sshCommand' || :\"" +2026-10-08T16:50:49.7036543Z [command]"C:\Program Files\Git\bin\git.exe" config --local --name-only --get-regexp http\.https\:\/\/github\.com\/\.extraheader +2026-10-08T16:50:49.7350551Z [command]"C:\Program Files\Git\bin\git.exe" submodule foreach --recursive "sh -c \"git config --local --name-only --get-regexp 'http\.https\:\/\/github\.com\/\.extraheader' && git config --local --unset-all 'http.https://github.com/.extraheader' || :\"" +2026-10-08T16:50:50.2267341Z [command]"C:\Program Files\Git\bin\git.exe" config --local --name-only --get-regexp ^includeIf\.gitdir: +2026-10-08T16:50:50.2561916Z [command]"C:\Program Files\Git\bin\git.exe" submodule foreach --recursive "git config --local --show-origin --name-only --get-regexp remote.origin.url" +2026-10-08T16:50:50.7278395Z [command]"C:\Program Files\Git\bin\git.exe" config --local http.https://github.com/.extraheader "AUTHORIZATION: basic ***" +2026-10-08T16:50:50.7584907Z ##[endgroup] +2026-10-08T16:50:50.7585607Z ##[group]Fetching the repository +2026-10-08T16:50:50.7601533Z [command]"C:\Program Files\Git\bin\git.exe" -c protocol.version=2 fetch --no-tags --prune --no-recurse-submodules --depth=1 origin +0de94b767061ec1fe5c05d11c6baa36ec9ddf16b:refs/remotes/pull/71/merge +2026-10-08T16:50:54.3618633Z From https://github.com/Jacob-Met/CaptureSuite +2026-10-08T16:50:54.3619855Z * [new ref] 0de94b767061ec1fe5c05d11c6baa36ec9ddf16b -> pull/71/merge +2026-10-08T16:50:54.3652768Z ##[endgroup] +2026-10-08T16:50:54.3653501Z ##[group]Determining the checkout info +2026-10-08T16:50:54.3656535Z ##[endgroup] +2026-10-08T16:50:54.3665543Z [command]"C:\Program Files\Git\bin\git.exe" sparse-checkout disable +2026-10-08T16:50:54.4483696Z [command]"C:\Program Files\Git\bin\git.exe" config --local --unset-all extensions.worktreeConfig +2026-10-08T16:50:54.4841742Z ##[group]Checking out the ref +2026-10-08T16:50:54.4842688Z [command]"C:\Program Files\Git\bin\git.exe" checkout --progress --force refs/remotes/pull/71/merge +2026-10-08T16:50:54.8789346Z Note: switching to 'refs/remotes/pull/71/merge'. +2026-10-08T16:50:54.8789772Z +2026-10-08T16:50:54.8790126Z You are in 'detached HEAD' state. You can look around, make experimental +2026-10-08T16:50:54.8791540Z changes and commit them, and you can discard any commits you make in this +2026-10-08T16:50:54.8792214Z state without impacting any branches by switching back to a branch. +2026-10-08T16:50:54.8792606Z +2026-10-08T16:50:54.8792856Z If you want to create a new branch to retain commits you create, you may +2026-10-08T16:50:54.8793406Z do so (now or later) by using -c with the switch command. Example: +2026-10-08T16:50:54.8793659Z +2026-10-08T16:50:54.8793765Z git switch -c +2026-10-08T16:50:54.8793943Z +2026-10-08T16:50:54.8794036Z Or undo this operation with: +2026-10-08T16:50:54.8794191Z +2026-10-08T16:50:54.8794272Z git switch - +2026-10-08T16:50:54.8794385Z +2026-10-08T16:50:54.8794602Z Turn off this advice by setting config variable advice.detachedHead to false +2026-10-08T16:50:54.8795838Z +2026-10-08T16:50:54.8808549Z HEAD is now at 0de94b7 Merge aefaffe03331f5c8e0cc41dfd75ce9c81f9d09fe into 3cbb5300bdc79c157370d1b3e599a6c82752d54a +2026-10-08T16:50:54.8879557Z ##[endgroup] +2026-10-08T16:50:54.9476126Z [command]"C:\Program Files\Git\bin\git.exe" log -1 --format=%H +2026-10-08T16:50:54.9740996Z 0de94b767061ec1fe5c05d11c6baa36ec9ddf16b +2026-10-08T16:50:55.0162922Z ##[group]Run actions/setup-python@v5 +2026-10-08T16:50:55.0163300Z with: +2026-10-08T16:50:55.0163498Z python-version: 3.12 +2026-10-08T16:50:55.0163721Z check-latest: false +2026-10-08T16:50:55.0166505Z token: *** +2026-10-08T16:50:55.0166700Z update-environment: true +2026-10-08T16:50:55.0166924Z allow-prereleases: false +2026-10-08T16:50:55.0167130Z freethreaded: false +2026-10-08T16:50:55.0167325Z ##[endgroup] +2026-10-08T16:50:55.1676667Z ##[group]Installed versions +2026-10-08T16:50:55.2030994Z (node:4948) [DEP0040] DeprecationWarning: The `punycode` module is deprecated. Please use a userland alternative instead. +2026-10-08T16:50:55.2032300Z (Use `node --trace-deprecation ...` to show where the warning was created) +2026-10-08T16:50:55.2033015Z Successfully set up CPython (3.12.10) +2026-10-08T16:50:55.2033755Z ##[endgroup] +2026-10-08T16:50:55.2274227Z ##[group]Run python -m pip install -r requirements-ci.txt +2026-10-08T16:50:55.2274748Z python -m pip install -r requirements-ci.txt +2026-10-08T16:50:55.2388503Z shell: C:\Program Files\PowerShell\7\pwsh.EXE -command ". '{0}'" +2026-10-08T16:50:55.2388983Z env: +2026-10-08T16:50:55.2389379Z pythonLocation: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:50:55.2390042Z PKG_CONFIG_PATH: C:\hostedtoolcache\windows\Python\3.12.10\x64/lib/pkgconfig +2026-10-08T16:50:55.2390640Z Python_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:50:55.2391164Z Python2_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:50:55.2391687Z Python3_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:50:55.2392125Z ##[endgroup] +2026-10-08T16:51:13.5562825Z Obtaining file:///D:/a/CaptureSuite/CaptureSuite/libs/python/capture_protocol (from -r requirements-ci.txt (line 3)) +2026-10-08T16:51:13.5590941Z Installing build dependencies: started +2026-10-08T16:51:16.9073033Z Installing build dependencies: finished with status 'done' +2026-10-08T16:51:16.9088450Z Checking if build backend supports build_editable: started +2026-10-08T16:51:17.4898741Z Checking if build backend supports build_editable: finished with status 'done' +2026-10-08T16:51:17.4922111Z Getting requirements to build editable: started +2026-10-08T16:51:18.0287688Z Getting requirements to build editable: finished with status 'done' +2026-10-08T16:51:18.0316377Z Preparing editable metadata (pyproject.toml): started +2026-10-08T16:51:18.3490975Z Preparing editable metadata (pyproject.toml): finished with status 'done' +2026-10-08T16:51:18.3536906Z Obtaining file:///D:/a/CaptureSuite/CaptureSuite/libs/python/capture_session (from -r requirements-ci.txt (line 4)) +2026-10-08T16:51:18.3563001Z Installing build dependencies: started +2026-10-08T16:51:19.9030065Z Installing build dependencies: finished with status 'done' +2026-10-08T16:51:19.9045112Z Checking if build backend supports build_editable: started +2026-10-08T16:51:20.5394434Z Checking if build backend supports build_editable: finished with status 'done' +2026-10-08T16:51:20.5418588Z Getting requirements to build editable: started +2026-10-08T16:51:21.0356063Z Getting requirements to build editable: finished with status 'done' +2026-10-08T16:51:21.0382743Z Preparing editable metadata (pyproject.toml): started +2026-10-08T16:51:21.3597787Z Preparing editable metadata (pyproject.toml): finished with status 'done' +2026-10-08T16:51:21.3643789Z Obtaining file:///D:/a/CaptureSuite/CaptureSuite/libs/python/capture_analysis +2026-10-08T16:51:21.3670454Z Installing build dependencies: started +2026-10-08T16:51:22.9890787Z Installing build dependencies: finished with status 'done' +2026-10-08T16:51:22.9905940Z Checking if build backend supports build_editable: started +2026-10-08T16:51:23.4751136Z Checking if build backend supports build_editable: finished with status 'done' +2026-10-08T16:51:23.4783113Z Getting requirements to build editable: started +2026-10-08T16:51:24.0174905Z Getting requirements to build editable: finished with status 'done' +2026-10-08T16:51:24.0202966Z Preparing editable metadata (pyproject.toml): started +2026-10-08T16:51:24.3431631Z Preparing editable metadata (pyproject.toml): finished with status 'done' +2026-10-08T16:51:24.3487068Z Obtaining file:///D:/a/CaptureSuite/CaptureSuite/libs/python/capture_worker (from -r requirements-ci.txt (line 6)) +2026-10-08T16:51:24.3514943Z Installing build dependencies: started +2026-10-08T16:51:26.1672664Z Installing build dependencies: finished with status 'done' +2026-10-08T16:51:26.1687153Z Checking if build backend supports build_editable: started +2026-10-08T16:51:26.6197779Z Checking if build backend supports build_editable: finished with status 'done' +2026-10-08T16:51:26.6220120Z Getting requirements to build editable: started +2026-10-08T16:51:27.1743260Z Getting requirements to build editable: finished with status 'done' +2026-10-08T16:51:27.1777729Z Preparing editable metadata (pyproject.toml): started +2026-10-08T16:51:27.5016936Z Preparing editable metadata (pyproject.toml): finished with status 'done' +2026-10-08T16:51:27.5062590Z Obtaining file:///D:/a/CaptureSuite/CaptureSuite/desktop +2026-10-08T16:51:27.5090179Z Installing build dependencies: started +2026-10-08T16:51:30.3968898Z Installing build dependencies: finished with status 'done' +2026-10-08T16:51:30.3983330Z Checking if build backend supports build_editable: started +2026-10-08T16:51:30.8880960Z Checking if build backend supports build_editable: finished with status 'done' +2026-10-08T16:51:30.8903623Z Getting requirements to build editable: started +2026-10-08T16:51:31.4620925Z Getting requirements to build editable: finished with status 'done' +2026-10-08T16:51:31.4647262Z Preparing editable metadata (pyproject.toml): started +2026-10-08T16:51:31.8104116Z Preparing editable metadata (pyproject.toml): finished with status 'done' +2026-10-08T16:51:32.6665181Z Collecting grpcio-tools<1.63,>=1.62 (from -r requirements-ci.txt (line 8)) +2026-10-08T16:51:32.8479723Z Downloading grpcio_tools-1.62.3-cp312-cp312-win_amd64.whl.metadata (6.4 kB) +2026-10-08T16:51:32.8875854Z Collecting mcap<2,>=1.1 (from -r requirements-ci.txt (line 9)) +2026-10-08T16:51:32.9236282Z Downloading mcap-1.5.0-py3-none-any.whl.metadata (380 bytes) +2026-10-08T16:51:32.9835664Z Collecting pytest>=8 (from -r requirements-ci.txt (line 10)) +2026-10-08T16:51:33.0018085Z Downloading pytest-9.1.1-py3-none-any.whl.metadata (7.6 kB) +2026-10-08T16:51:33.0725675Z Collecting pytest-cov>=5 (from -r requirements-ci.txt (line 11)) +2026-10-08T16:51:33.0844784Z Downloading pytest_cov-7.1.0-py3-none-any.whl.metadata (32 kB) +2026-10-08T16:51:33.4915789Z Collecting ruff<1,>=0.6 (from -r requirements-ci.txt (line 12)) +2026-10-08T16:51:33.5046928Z Downloading ruff-0.16.10-py3-none-win_amd64.whl.metadata (21 kB) +2026-10-08T16:51:33.6889359Z Collecting protobuf<5,>=4.25 (from capture-protocol==0.1.0->-r requirements-ci.txt (line 3)) +2026-10-08T16:51:33.7014397Z Downloading protobuf-4.25.9-cp310-abi3-win_amd64.whl.metadata (541 bytes) +2026-10-08T16:51:33.7463248Z Collecting jsonschema>=4.21 (from capture-session==0.1.0->-r requirements-ci.txt (line 4)) +2026-10-08T16:51:33.7570141Z Downloading jsonschema-4.26.0-py3-none-any.whl.metadata (7.6 kB) +2026-10-08T16:51:33.8471756Z Collecting pyyaml>=6.0 (from capture-analysis==0.1.0) +2026-10-08T16:51:33.8649268Z Downloading pyyaml-6.0.3-cp312-cp312-win_amd64.whl.metadata (2.4 kB) +2026-10-08T16:51:34.0216512Z Collecting PySide6<7,>=6.6 (from capture-desktop==0.1.0) +2026-10-08T16:51:34.0370745Z Downloading pyside6-6.12.0-cp310-abi3-win_amd64.whl.metadata (5.7 kB) +2026-10-08T16:51:34.3969610Z Collecting numpy>=1.26 (from capture-analysis==0.1.0) +2026-10-08T16:51:34.4336309Z Downloading numpy-2.5.3-cp312-cp312-win_amd64.whl.metadata (6.6 kB) +2026-10-08T16:51:34.5910488Z Collecting scipy>=1.11 (from capture-analysis==0.1.0) +2026-10-08T16:51:34.6033611Z Downloading scipy-1.18.1-cp312-cp312-win_amd64.whl.metadata (61 kB) +2026-10-08T16:51:34.7878801Z Collecting pandas>=2.1 (from capture-analysis==0.1.0) +2026-10-08T16:51:34.8051138Z Downloading pandas-3.0.6-cp312-cp312-win_amd64.whl.metadata (19 kB) +2026-10-08T16:51:34.9584489Z Collecting pyarrow>=14.0 (from capture-analysis==0.1.0) +2026-10-08T16:51:34.9717279Z Downloading pyarrow-25.0.1-cp312-cp312-win_amd64.whl.metadata (3.0 kB) +2026-10-08T16:51:35.1460811Z Collecting matplotlib>=3.8 (from capture-analysis==0.1.0) +2026-10-08T16:51:35.1567985Z Downloading matplotlib-3.11.2-cp312-cp312-win_amd64.whl.metadata (80 kB) +2026-10-08T16:51:35.2172709Z Collecting pyqtgraph>=0.13 (from capture-desktop==0.1.0) +2026-10-08T16:51:35.2286880Z Downloading pyqtgraph-0.14.0-py3-none-any.whl.metadata (1.5 kB) +2026-10-08T16:51:35.8214587Z Collecting grpcio>=1.62.3 (from grpcio-tools<1.63,>=1.62->-r requirements-ci.txt (line 8)) +2026-10-08T16:51:35.8364492Z Downloading grpcio-1.84.0-cp312-cp312-win_amd64.whl.metadata (3.9 kB) +2026-10-08T16:51:35.9428826Z Collecting setuptools (from grpcio-tools<1.63,>=1.62->-r requirements-ci.txt (line 8)) +2026-10-08T16:51:35.9716851Z Using cached setuptools-84.0.0-py3-none-any.whl.metadata (6.6 kB) +2026-10-08T16:51:36.0496957Z Collecting lz4 (from mcap<2,>=1.1->-r requirements-ci.txt (line 9)) +2026-10-08T16:51:36.0614904Z Downloading lz4-4.4.5-cp312-cp312-win_amd64.whl.metadata (3.9 kB) +2026-10-08T16:51:36.1520867Z Collecting zstandard (from mcap<2,>=1.1->-r requirements-ci.txt (line 9)) +2026-10-08T16:51:36.1633446Z Downloading zstandard-0.25.0-cp312-cp312-win_amd64.whl.metadata (3.3 kB) +2026-10-08T16:51:36.3551252Z Collecting PySide6_Essentials==6.12.0 (from PySide6<7,>=6.6->capture-desktop==0.1.0) +2026-10-08T16:51:36.3897367Z Downloading pyside6_essentials-6.12.0-cp310-abi3-win_amd64.whl.metadata (3.9 kB) +2026-10-08T16:51:36.5877382Z Collecting PySide6_Addons==6.12.0 (from PySide6<7,>=6.6->capture-desktop==0.1.0) +2026-10-08T16:51:36.6260147Z Downloading pyside6_addons-6.12.0-cp310-abi3-win_amd64.whl.metadata (4.4 kB) +2026-10-08T16:51:36.7838062Z Collecting PySide6_WebEngine==6.12.0.140 (from PySide6<7,>=6.6->capture-desktop==0.1.0) +2026-10-08T16:51:36.7956957Z Downloading pyside6_webengine-6.12.0.140-cp310-abi3-win_amd64.whl.metadata (3.7 kB) +2026-10-08T16:51:36.8793260Z Collecting PySide6_Pdf==6.12.0.140 (from PySide6<7,>=6.6->capture-desktop==0.1.0) +2026-10-08T16:51:36.9148705Z Downloading pyside6_pdf-6.12.0.140-cp310-abi3-win_amd64.whl.metadata (3.6 kB) +2026-10-08T16:51:37.0672128Z Collecting shiboken6==6.12.0 (from PySide6_Essentials==6.12.0->PySide6<7,>=6.6->capture-desktop==0.1.0) +2026-10-08T16:51:37.0932130Z Downloading shiboken6-6.12.0-cp310-abi3-win_amd64.whl.metadata (2.6 kB) +2026-10-08T16:51:37.1601355Z Requirement already satisfied: colorama>=0.4 in C:\hostedtoolcache\windows\Python\3.12.10\x64\Lib\site-packages (from pytest>=8->-r requirements-ci.txt (line 10)) (0.4.6) +2026-10-08T16:51:37.2758472Z Collecting iniconfig>=1.0.1 (from pytest>=8->-r requirements-ci.txt (line 10)) +2026-10-08T16:51:37.3133143Z Downloading iniconfig-2.3.1-py3-none-any.whl.metadata (2.8 kB) +2026-10-08T16:51:37.3724899Z Requirement already satisfied: packaging>=22 in C:\hostedtoolcache\windows\Python\3.12.10\x64\Lib\site-packages (from pytest>=8->-r requirements-ci.txt (line 10)) (26.3) +2026-10-08T16:51:37.4228392Z Collecting pluggy<2,>=1.5 (from pytest>=8->-r requirements-ci.txt (line 10)) +2026-10-08T16:51:37.4331131Z Downloading pluggy-1.6.0-py3-none-any.whl.metadata (4.8 kB) +2026-10-08T16:51:37.6292817Z Collecting pygments>=2.7.2 (from pytest>=8->-r requirements-ci.txt (line 10)) +2026-10-08T16:51:37.6400206Z Downloading pygments-2.21.0-py3-none-any.whl.metadata (2.5 kB) +2026-10-08T16:51:38.1853638Z Collecting coverage>=7.10.6 (from coverage[toml]>=7.10.6->pytest-cov>=5->-r requirements-ci.txt (line 11)) +2026-10-08T16:51:38.1967161Z Downloading coverage-7.16.2-cp312-cp312-win_amd64.whl.metadata (8.4 kB) +2026-10-08T16:51:38.3299896Z Collecting typing-extensions~=4.12 (from grpcio>=1.62.3->grpcio-tools<1.63,>=1.62->-r requirements-ci.txt (line 8)) +2026-10-08T16:51:38.3404511Z Downloading typing_extensions-4.16.0-py3-none-any.whl.metadata (3.3 kB) +2026-10-08T16:51:38.3785942Z Collecting attrs>=22.2.0 (from jsonschema>=4.21->capture-session==0.1.0->-r requirements-ci.txt (line 4)) +2026-10-08T16:51:38.3902889Z Downloading attrs-26.1.0-py3-none-any.whl.metadata (8.8 kB) +2026-10-08T16:51:38.4536870Z Collecting jsonschema-specifications>=2023.03.6 (from jsonschema>=4.21->capture-session==0.1.0->-r requirements-ci.txt (line 4)) +2026-10-08T16:51:38.4640671Z Downloading jsonschema_specifications-2025.9.1-py3-none-any.whl.metadata (2.9 kB) +2026-10-08T16:51:38.5140596Z Collecting referencing>=0.28.4 (from jsonschema>=4.21->capture-session==0.1.0->-r requirements-ci.txt (line 4)) +2026-10-08T16:51:38.5468151Z Downloading referencing-0.37.0-py3-none-any.whl.metadata (2.8 kB) +2026-10-08T16:51:38.8536997Z Collecting rpds-py>=0.25.0 (from jsonschema>=4.21->capture-session==0.1.0->-r requirements-ci.txt (line 4)) +2026-10-08T16:51:38.8641850Z Downloading rpds_py-2026.9.1-cp312-cp312-win_amd64.whl.metadata (4.2 kB) +2026-10-08T16:51:38.9861672Z Collecting contourpy>=1.0.1 (from matplotlib>=3.8->capture-analysis==0.1.0) +2026-10-08T16:51:38.9989727Z Downloading contourpy-1.4.0-cp312-cp312-win_amd64.whl.metadata (3.8 kB) +2026-10-08T16:51:39.0362010Z Collecting cycler>=0.10 (from matplotlib>=3.8->capture-analysis==0.1.0) +2026-10-08T16:51:39.0607948Z Downloading cycler-0.12.1-py3-none-any.whl.metadata (3.8 kB) +2026-10-08T16:51:39.2518309Z Collecting fonttools>=4.28.2 (from matplotlib>=3.8->capture-analysis==0.1.0) +2026-10-08T16:51:39.2811582Z Downloading fonttools-4.66.1-cp312-cp312-win_amd64.whl.metadata (132 kB) +2026-10-08T16:51:39.3938175Z Collecting kiwisolver>=1.3.1 (from matplotlib>=3.8->capture-analysis==0.1.0) +2026-10-08T16:51:39.4293485Z Downloading kiwisolver-1.5.1-cp312-cp312-win_amd64.whl.metadata (5.2 kB) +2026-10-08T16:51:39.6636259Z Collecting pillow>=9 (from matplotlib>=3.8->capture-analysis==0.1.0) +2026-10-08T16:51:39.6747267Z Downloading pillow-12.3.0-cp312-cp312-win_amd64.whl.metadata (9.3 kB) +2026-10-08T16:51:39.7563396Z Collecting pyparsing>=3 (from matplotlib>=3.8->capture-analysis==0.1.0) +2026-10-08T16:51:39.7679568Z Downloading pyparsing-3.3.3-py3-none-any.whl.metadata (5.9 kB) +2026-10-08T16:51:39.8079353Z Collecting python-dateutil>=2.7 (from matplotlib>=3.8->capture-analysis==0.1.0) +2026-10-08T16:51:39.8448456Z Downloading python_dateutil-2.9.0.post0-py2.py3-none-any.whl.metadata (8.4 kB) +2026-10-08T16:51:39.8903732Z Collecting tzdata (from pandas>=2.1->capture-analysis==0.1.0) +2026-10-08T16:51:39.9016037Z Downloading tzdata-2026.5-py2.py3-none-any.whl.metadata (1.4 kB) +2026-10-08T16:51:39.9411270Z Collecting six>=1.5 (from python-dateutil>=2.7->matplotlib>=3.8->capture-analysis==0.1.0) +2026-10-08T16:51:39.9523806Z Downloading six-1.17.0-py2.py3-none-any.whl.metadata (1.7 kB) +2026-10-08T16:51:40.0433696Z Downloading grpcio_tools-1.62.3-cp312-cp312-win_amd64.whl (1.1 MB) +2026-10-08T16:51:40.0895726Z ---------------------------------------- 1.1/1.1 MB 25.5 MB/s 0:00:00 +2026-10-08T16:51:40.1102531Z Downloading mcap-1.5.0-py3-none-any.whl (21 kB) +2026-10-08T16:51:40.1368500Z Downloading ruff-0.16.10-py3-none-win_amd64.whl (10.6 MB) +2026-10-08T16:51:40.3075799Z ---------------------------------------- 10.6/10.6 MB 60.0 MB/s 0:00:00 +2026-10-08T16:51:40.3240580Z Downloading protobuf-4.25.9-cp310-abi3-win_amd64.whl (413 kB) +2026-10-08T16:51:40.3543332Z Downloading pyside6-6.12.0-cp310-abi3-win_amd64.whl (578 kB) +2026-10-08T16:51:40.3750754Z ---------------------------------------- 579.0/579.0 kB 10.2 MB/s 0:00:00 +2026-10-08T16:51:40.3868574Z Downloading pyside6_addons-6.12.0-cp310-abi3-win_amd64.whl (40.5 MB) +2026-10-08T16:51:41.2050753Z ---------------------------------------- 40.5/40.5 MB 48.6 MB/s 0:00:00 +2026-10-08T16:51:41.2170127Z Downloading pyside6_essentials-6.12.0-cp310-abi3-win_amd64.whl (82.2 MB) +2026-10-08T16:51:42.9091584Z ---------------------------------------- 82.2/82.2 MB 49.0 MB/s 0:00:01 +2026-10-08T16:51:42.9212582Z Downloading pyside6_pdf-6.12.0.140-cp310-abi3-win_amd64.whl (3.0 MB) +2026-10-08T16:51:43.0358416Z ---------------------------------------- 3.0/3.0 MB 29.3 MB/s 0:00:00 +2026-10-08T16:51:43.0614204Z Downloading pyside6_webengine-6.12.0.140-cp310-abi3-win_amd64.whl (131.7 MB) +2026-10-08T16:51:46.2080232Z ---------------------------------------- 131.7/131.7 MB 41.9 MB/s 0:00:03 +2026-10-08T16:51:46.2224123Z Downloading shiboken6-6.12.0-cp310-abi3-win_amd64.whl (1.3 MB) +2026-10-08T16:51:46.2598974Z ---------------------------------------- 1.3/1.3 MB 32.4 MB/s 0:00:00 +2026-10-08T16:51:46.2702954Z Downloading pytest-9.1.1-py3-none-any.whl (386 kB) +2026-10-08T16:51:46.2968396Z Downloading pluggy-1.6.0-py3-none-any.whl (20 kB) +2026-10-08T16:51:46.3193605Z Downloading pytest_cov-7.1.0-py3-none-any.whl (22 kB) +2026-10-08T16:51:46.3450263Z Downloading coverage-7.16.2-cp312-cp312-win_amd64.whl (226 kB) +2026-10-08T16:51:46.3773061Z Downloading grpcio-1.84.0-cp312-cp312-win_amd64.whl (5.3 MB) +2026-10-08T16:51:46.4518703Z ---------------------------------------- 5.3/5.3 MB 79.2 MB/s 0:00:00 +2026-10-08T16:51:46.4621264Z Downloading typing_extensions-4.16.0-py3-none-any.whl (45 kB) +2026-10-08T16:51:46.4968460Z Downloading iniconfig-2.3.1-py3-none-any.whl (7.6 kB) +2026-10-08T16:51:46.5207024Z Downloading jsonschema-4.26.0-py3-none-any.whl (90 kB) +2026-10-08T16:51:46.5438660Z Downloading attrs-26.1.0-py3-none-any.whl (67 kB) +2026-10-08T16:51:46.5684012Z Downloading jsonschema_specifications-2025.9.1-py3-none-any.whl (18 kB) +2026-10-08T16:51:46.6167020Z Downloading matplotlib-3.11.2-cp312-cp312-win_amd64.whl (9.3 MB) +2026-10-08T16:51:46.9089907Z ---------------------------------------- 9.3/9.3 MB 30.7 MB/s 0:00:00 +2026-10-08T16:51:46.9243307Z Downloading contourpy-1.4.0-cp312-cp312-win_amd64.whl (234 kB) +2026-10-08T16:51:46.9512255Z Downloading cycler-0.12.1-py3-none-any.whl (8.3 kB) +2026-10-08T16:51:46.9795440Z Downloading fonttools-4.66.1-cp312-cp312-win_amd64.whl (2.5 MB) +2026-10-08T16:51:47.0168912Z ---------------------------------------- 2.5/2.5 MB 71.8 MB/s 0:00:00 +2026-10-08T16:51:47.0321105Z Downloading kiwisolver-1.5.1-cp312-cp312-win_amd64.whl (70 kB) +2026-10-08T16:51:47.0693402Z Downloading numpy-2.5.3-cp312-cp312-win_amd64.whl (12.6 MB) +2026-10-08T16:51:47.2093110Z ---------------------------------------- 12.6/12.6 MB 87.3 MB/s 0:00:00 +2026-10-08T16:51:47.2225921Z Downloading pandas-3.0.6-cp312-cp312-win_amd64.whl (9.7 MB) +2026-10-08T16:51:47.3407580Z ---------------------------------------- 9.7/9.7 MB 86.2 MB/s 0:00:00 +2026-10-08T16:51:47.3571737Z Downloading pillow-12.3.0-cp312-cp312-win_amd64.whl (7.2 MB) +2026-10-08T16:51:47.4228512Z ---------------------------------------- 7.2/7.2 MB 112.3 MB/s 0:00:00 +2026-10-08T16:51:47.4363287Z Downloading pyarrow-25.0.1-cp312-cp312-win_amd64.whl (28.0 MB) +2026-10-08T16:51:47.9542078Z ---------------------------------------- 28.0/28.0 MB 53.8 MB/s 0:00:00 +2026-10-08T16:51:47.9655214Z Downloading pygments-2.21.0-py3-none-any.whl (1.3 MB) +2026-10-08T16:51:47.9955546Z ---------------------------------------- 1.3/1.3 MB 31.9 MB/s 0:00:00 +2026-10-08T16:51:48.0055069Z Downloading pyparsing-3.3.3-py3-none-any.whl (126 kB) +2026-10-08T16:51:48.0400895Z Downloading pyqtgraph-0.14.0-py3-none-any.whl (1.9 MB) +2026-10-08T16:51:48.0956516Z ---------------------------------------- 1.9/1.9 MB 35.4 MB/s 0:00:00 +2026-10-08T16:51:48.2590989Z Downloading python_dateutil-2.9.0.post0-py2.py3-none-any.whl (229 kB) +2026-10-08T16:51:48.2878370Z Downloading pyyaml-6.0.3-cp312-cp312-win_amd64.whl (154 kB) +2026-10-08T16:51:48.3126164Z Downloading referencing-0.37.0-py3-none-any.whl (26 kB) +2026-10-08T16:51:48.3413706Z Downloading rpds_py-2026.9.1-cp312-cp312-win_amd64.whl (222 kB) +2026-10-08T16:51:48.3724232Z Downloading scipy-1.18.1-cp312-cp312-win_amd64.whl (36.7 MB) +2026-10-08T16:51:48.9477921Z ---------------------------------------- 36.7/36.7 MB 63.0 MB/s 0:00:00 +2026-10-08T16:51:48.9592956Z Downloading six-1.17.0-py2.py3-none-any.whl (11 kB) +2026-10-08T16:51:48.9994280Z Downloading lz4-4.4.5-cp312-cp312-win_amd64.whl (99 kB) +2026-10-08T16:51:49.0165711Z Using cached setuptools-84.0.0-py3-none-any.whl (818 kB) +2026-10-08T16:51:49.0289558Z Downloading tzdata-2026.5-py2.py3-none-any.whl (347 kB) +2026-10-08T16:51:49.0572328Z Downloading zstandard-0.25.0-cp312-cp312-win_amd64.whl (506 kB) +2026-10-08T16:51:49.6707981Z Building wheels for collected packages: capture-protocol, capture-session, capture-analysis, capture-worker, capture-desktop +2026-10-08T16:51:50.2220816Z Building editable for capture-protocol (pyproject.toml): started +2026-10-08T16:51:50.6194992Z Building editable for capture-protocol (pyproject.toml): finished with status 'done' +2026-10-08T16:51:50.6225793Z Created wheel for capture-protocol: filename=capture_protocol-0.1.0-0.editable-py3-none-any.whl size=7398 sha256=e0b159196577c37bb5b58304d4293099c61bc1729aec54e852c28ac0ba0286c3 +2026-10-08T16:51:50.6227573Z Stored in directory: C:\Users\runneradmin\AppData\Local\Temp\pip-ephem-wheel-cache-z_40czgb\wheels\be\38\74\adf0f9a8f0ba8d26599b299cff33b892a58ed35959c9e09acd +2026-10-08T16:51:50.6271832Z Building editable for capture-session (pyproject.toml): started +2026-10-08T16:51:50.9660583Z Building editable for capture-session (pyproject.toml): finished with status 'done' +2026-10-08T16:51:50.9692518Z Created wheel for capture-session: filename=capture_session-0.1.0-0.editable-py3-none-any.whl size=2863 sha256=410383a4f1e4e5ae6d0bef5e66a215409b7ef0fa0df33a81d9b06e652aa17398 +2026-10-08T16:51:50.9695181Z Stored in directory: C:\Users\runneradmin\AppData\Local\Temp\pip-ephem-wheel-cache-z_40czgb\wheels\49\8f\6e\163bd066522d89fdd0906cf22a1687ebc628821c7980903be9 +2026-10-08T16:51:50.9739496Z Building editable for capture-analysis (pyproject.toml): started +2026-10-08T16:51:51.3481274Z Building editable for capture-analysis (pyproject.toml): finished with status 'done' +2026-10-08T16:51:51.3512631Z Created wheel for capture-analysis: filename=capture_analysis-0.1.0-0.editable-py3-none-any.whl size=3050 sha256=6b42d188c746b1bb1592932b2c42a4ea19c82ff13151c094a51c3347c7cc9669 +2026-10-08T16:51:51.3515358Z Stored in directory: C:\Users\runneradmin\AppData\Local\Temp\pip-ephem-wheel-cache-z_40czgb\wheels\f4\d1\58\14e4976a0c15c2c470fc12f9a2873cc8c4bc7bd989766b97b4 +2026-10-08T16:51:51.3561749Z Building editable for capture-worker (pyproject.toml): started +2026-10-08T16:51:51.7272322Z Building editable for capture-worker (pyproject.toml): finished with status 'done' +2026-10-08T16:51:51.7306396Z Created wheel for capture-worker: filename=capture_worker-0.1.0-0.editable-py3-none-any.whl size=7659 sha256=f4262489391c85149b5426e67c319327b5c213437784f35ade3bc9880d5874f7 +2026-10-08T16:51:51.7308698Z Stored in directory: C:\Users\runneradmin\AppData\Local\Temp\pip-ephem-wheel-cache-z_40czgb\wheels\91\10\bd\b56fd1c22822b4cd753ca217f259119db33a4fa54b26c297ee +2026-10-08T16:51:51.7353359Z Building editable for capture-desktop (pyproject.toml): started +2026-10-08T16:51:52.0805299Z Building editable for capture-desktop (pyproject.toml): finished with status 'done' +2026-10-08T16:51:52.0838895Z Created wheel for capture-desktop: filename=capture_desktop-0.1.0-0.editable-py3-none-any.whl size=3184 sha256=be0abcbb2767c25cc20e7c870237a5063cf2c9cd798191e9dddf531d1cdda113 +2026-10-08T16:51:52.0841606Z Stored in directory: C:\Users\runneradmin\AppData\Local\Temp\pip-ephem-wheel-cache-z_40czgb\wheels\04\f4\80\083223dba330947d948f2d768e3de9f1e54ae638d0a391d614 +2026-10-08T16:51:52.0865240Z Successfully built capture-protocol capture-session capture-analysis capture-worker capture-desktop +2026-10-08T16:51:52.2517353Z Installing collected packages: zstandard, tzdata, typing-extensions, six, shiboken6, setuptools, ruff, rpds-py, pyyaml, pyparsing, pygments, pyarrow, protobuf, pluggy, pillow, numpy, lz4, kiwisolver, iniconfig, fonttools, cycler, coverage, attrs, scipy, referencing, python-dateutil, pytest, PySide6_Essentials, pyqtgraph, mcap, grpcio, contourpy, capture-protocol, pytest-cov, PySide6_Pdf, PySide6_Addons, pandas, matplotlib, jsonschema-specifications, grpcio-tools, capture-worker, PySide6_WebEngine, jsonschema, PySide6, capture-session, capture-desktop, capture-analysis +2026-10-08T16:52:38.8098372Z +2026-10-08T16:52:38.8152100Z Successfully installed PySide6-6.12.0 PySide6_Addons-6.12.0 PySide6_Essentials-6.12.0 PySide6_Pdf-6.12.0.140 PySide6_WebEngine-6.12.0.140 attrs-26.1.0 capture-analysis-0.1.0 capture-desktop-0.1.0 capture-protocol-0.1.0 capture-session-0.1.0 capture-worker-0.1.0 contourpy-1.4.0 coverage-7.16.2 cycler-0.12.1 fonttools-4.66.1 grpcio-1.84.0 grpcio-tools-1.62.3 iniconfig-2.3.1 jsonschema-4.26.0 jsonschema-specifications-2025.9.1 kiwisolver-1.5.1 lz4-4.4.5 matplotlib-3.11.2 mcap-1.5.0 numpy-2.5.3 pandas-3.0.6 pillow-12.3.0 pluggy-1.6.0 protobuf-4.25.9 pyarrow-25.0.1 pygments-2.21.0 pyparsing-3.3.3 pyqtgraph-0.14.0 pytest-9.1.1 pytest-cov-7.1.0 python-dateutil-2.9.0.post0 pyyaml-6.0.3 referencing-0.37.0 rpds-py-2026.9.1 ruff-0.16.10 scipy-1.18.1 setuptools-84.0.0 shiboken6-6.12.0 six-1.17.0 typing-extensions-4.16.0 tzdata-2026.5 zstandard-0.25.0 +2026-10-08T16:52:39.6732066Z ##[group]Run python -m pip check +2026-10-08T16:52:39.6732427Z python -m pip check +2026-10-08T16:52:39.6775789Z shell: C:\Program Files\PowerShell\7\pwsh.EXE -command ". '{0}'" +2026-10-08T16:52:39.6776135Z env: +2026-10-08T16:52:39.6776409Z pythonLocation: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:52:39.6776865Z PKG_CONFIG_PATH: C:\hostedtoolcache\windows\Python\3.12.10\x64/lib/pkgconfig +2026-10-08T16:52:39.6777320Z Python_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:52:39.6777710Z Python2_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:52:39.6778108Z Python3_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:52:39.6778417Z ##[endgroup] +2026-10-08T16:52:40.4364840Z No broken requirements found. +2026-10-08T16:52:40.5905951Z ##[group]Run python tools/check_ci_contract.py --check-environment +2026-10-08T16:52:40.5906507Z python tools/check_ci_contract.py --check-environment +2026-10-08T16:52:40.5950239Z shell: C:\Program Files\PowerShell\7\pwsh.EXE -command ". '{0}'" +2026-10-08T16:52:40.5950586Z env: +2026-10-08T16:52:40.5950859Z pythonLocation: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:52:40.5951331Z PKG_CONFIG_PATH: C:\hostedtoolcache\windows\Python\3.12.10\x64/lib/pkgconfig +2026-10-08T16:52:40.5951789Z Python_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:52:40.5952208Z Python2_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:52:40.5952618Z Python3_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:52:40.5952933Z ##[endgroup] +2026-10-08T16:52:47.3810056Z Matplotlib is building the font cache; this may take a moment. +2026-10-08T16:53:01.4329598Z { +2026-10-08T16:53:01.4330050Z "accepted": true, +2026-10-08T16:53:01.4330321Z "errors": [] +2026-10-08T16:53:01.4330548Z } +2026-10-08T16:53:01.7223635Z ##[group]Run python tools/gen_protos.py +2026-10-08T16:53:01.7224048Z python tools/gen_protos.py +2026-10-08T16:53:01.7263656Z shell: C:\Program Files\PowerShell\7\pwsh.EXE -command ". '{0}'" +2026-10-08T16:53:01.7263991Z env: +2026-10-08T16:53:01.7264249Z pythonLocation: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:53:01.7264703Z PKG_CONFIG_PATH: C:\hostedtoolcache\windows\Python\3.12.10\x64/lib/pkgconfig +2026-10-08T16:53:01.7265152Z Python_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:53:01.7266359Z Python2_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:53:01.7266758Z Python3_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:53:01.7267085Z ##[endgroup] +2026-10-08T16:53:02.1747213Z Running: C:\hostedtoolcache\windows\Python\3.12.10\x64\python.exe -m grpc_tools.protoc --proto_path=D:\a\CaptureSuite\CaptureSuite\schemas\proto --python_out=D:\a\CaptureSuite\CaptureSuite\libs\python\capture_protocol\capture_protocol\generated --descriptor_set_out=D:\a\CaptureSuite\CaptureSuite\build\generated\capture_v1.desc --include_imports --proto_path=C:\hostedtoolcache\windows\Python\3.12.10\x64\Lib\site-packages\grpc_tools\_proto capture/v1/arrays.proto capture/v1/common.proto capture/v1/control.proto capture/v1/data/emg_batch.proto capture/v1/data/imu_frame.proto capture/v1/data/numeric_batch.proto capture/v1/data/radar_doppler.proto capture/v1/data/radar_frame.proto capture/v1/data/video_timing.proto capture/v1/events.proto capture/v1/health.proto capture/v1/presets.proto capture/v1/preview.proto capture/v1/project.proto capture/v1/source.proto capture/v1/storage.proto capture/v1/worker.proto +2026-10-08T16:53:02.1752124Z Wrote Python bindings under D:\a\CaptureSuite\CaptureSuite\libs\python\capture_protocol\capture_protocol\generated +2026-10-08T16:53:02.1753025Z Wrote descriptor set D:\a\CaptureSuite\CaptureSuite\build\generated\capture_v1.desc +2026-10-08T16:53:02.3018159Z ##[group]Run git diff --exit-code -- libs/python/capture_protocol/capture_protocol/generated +2026-10-08T16:53:02.3018869Z git diff --exit-code -- libs/python/capture_protocol/capture_protocol/generated +2026-10-08T16:53:02.3058436Z shell: C:\Program Files\PowerShell\7\pwsh.EXE -command ". '{0}'" +2026-10-08T16:53:02.3058768Z env: +2026-10-08T16:53:02.3059035Z pythonLocation: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:53:02.3059503Z PKG_CONFIG_PATH: C:\hostedtoolcache\windows\Python\3.12.10\x64/lib/pkgconfig +2026-10-08T16:53:02.3059985Z Python_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:53:02.3060376Z Python2_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:53:02.3060779Z Python3_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:53:02.3061098Z ##[endgroup] +2026-10-08T16:53:02.8470572Z ##[group]Run python tools/gen_session_schemas.py +2026-10-08T16:53:02.8471012Z python tools/gen_session_schemas.py +2026-10-08T16:53:02.8510532Z shell: C:\Program Files\PowerShell\7\pwsh.EXE -command ". '{0}'" +2026-10-08T16:53:02.8510874Z env: +2026-10-08T16:53:02.8511141Z pythonLocation: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:53:02.8511620Z PKG_CONFIG_PATH: C:\hostedtoolcache\windows\Python\3.12.10\x64/lib/pkgconfig +2026-10-08T16:53:02.8512091Z Python_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:53:02.8512497Z Python2_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:53:02.8512935Z Python3_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:53:02.8513251Z ##[endgroup] +2026-10-08T16:53:03.1790445Z Wrote 19 schemas to D:\a\CaptureSuite\CaptureSuite\schemas\session\jsonschema +2026-10-08T16:53:03.2871205Z ##[group]Run git diff --exit-code -- schemas/session/jsonschema +2026-10-08T16:53:03.2871842Z git diff --exit-code -- schemas/session/jsonschema +2026-10-08T16:53:03.2912272Z shell: C:\Program Files\PowerShell\7\pwsh.EXE -command ". '{0}'" +2026-10-08T16:53:03.2912678Z env: +2026-10-08T16:53:03.2969389Z pythonLocation: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:53:03.2969931Z PKG_CONFIG_PATH: C:\hostedtoolcache\windows\Python\3.12.10\x64/lib/pkgconfig +2026-10-08T16:53:03.2970406Z Python_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:53:03.2970816Z Python2_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:53:03.2971213Z Python3_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:53:03.2971763Z ##[endgroup] +2026-10-08T16:53:03.6547038Z ##[group]Run ruff check libs/python/capture_protocol libs/python/capture_session libs/python/capture_analysis libs/python/capture_worker workers/python_host desktop/capture_desktop tools tests plugins/example_sine_py plugins/lsl_bridge +2026-10-08T16:53:03.6548729Z ruff check libs/python/capture_protocol libs/python/capture_session libs/python/capture_analysis libs/python/capture_worker workers/python_host desktop/capture_desktop tools tests plugins/example_sine_py plugins/lsl_bridge +2026-10-08T16:53:03.6589774Z shell: C:\Program Files\PowerShell\7\pwsh.EXE -command ". '{0}'" +2026-10-08T16:53:03.6590117Z env: +2026-10-08T16:53:03.6590382Z pythonLocation: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:53:03.6590842Z PKG_CONFIG_PATH: C:\hostedtoolcache\windows\Python\3.12.10\x64/lib/pkgconfig +2026-10-08T16:53:03.6591316Z Python_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:53:03.6591765Z Python2_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:53:03.6592167Z Python3_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:53:03.6592479Z ##[endgroup] +2026-10-08T16:53:04.0439418Z All checks passed! +2026-10-08T16:53:04.1471828Z ##[group]Run python tools/check_licenses.py --enforce-spdx +2026-10-08T16:53:04.1472315Z python tools/check_licenses.py --enforce-spdx +2026-10-08T16:53:04.1518903Z shell: C:\Program Files\PowerShell\7\pwsh.EXE -command ". '{0}'" +2026-10-08T16:53:04.1519255Z env: +2026-10-08T16:53:04.1519541Z pythonLocation: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:53:04.1520018Z PKG_CONFIG_PATH: C:\hostedtoolcache\windows\Python\3.12.10\x64/lib/pkgconfig +2026-10-08T16:53:04.1520477Z Python_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:53:04.1520876Z Python2_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:53:04.1521275Z Python3_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:53:04.1521602Z ##[endgroup] +2026-10-08T16:53:04.9046500Z license check OK +2026-10-08T16:53:05.0105423Z ##[group]Run python tools/run_ci_tests.py +2026-10-08T16:53:05.0105801Z python tools/run_ci_tests.py +2026-10-08T16:53:05.0144836Z shell: C:\Program Files\PowerShell\7\pwsh.EXE -command ". '{0}'" +2026-10-08T16:53:05.0145175Z env: +2026-10-08T16:53:05.0145433Z pythonLocation: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:53:05.0145911Z PKG_CONFIG_PATH: C:\hostedtoolcache\windows\Python\3.12.10\x64/lib/pkgconfig +2026-10-08T16:53:05.0146357Z Python_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:53:05.0146763Z Python2_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:53:05.0147163Z Python3_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:53:05.0147486Z QT_QPA_PLATFORM: offscreen +2026-10-08T16:53:05.0147703Z ##[endgroup] +2026-10-08T16:58:06.6384166Z ........................................................................ [ 13%] +2026-10-08T16:58:06.6385761Z ........................................................................ [ 26%] +2026-10-08T16:58:06.6386475Z ........................................................................ [ 39%] +2026-10-08T16:58:06.6387110Z ........................................................................ [ 52%] +2026-10-08T16:58:06.6387788Z ..........................................................ssssss........ [ 65%] +2026-10-08T16:58:06.6388427Z ........................................................................ [ 78%] +2026-10-08T16:58:06.6389064Z ........................................................................ [ 91%] +2026-10-08T16:58:06.6389621Z .................. +2026-10-08T16:58:06.6389973Z { +2026-10-08T16:58:06.6390332Z "schema": "capturesuite.test-receipt.v1", +2026-10-08T16:58:06.6390827Z "accepted": false, +2026-10-08T16:58:06.6391190Z "process_exit": null, +2026-10-08T16:58:06.6391865Z "counts": null, +2026-10-08T16:58:06.6392211Z "junit_sha256": null, +2026-10-08T16:58:06.6392573Z "problems": [ +2026-10-08T16:58:06.6392995Z "Test process did not exit successfully", +2026-10-08T16:58:06.6393608Z "JUnit unavailable or invalid: FileNotFoundError" +2026-10-08T16:58:06.6394155Z ], +2026-10-08T16:58:06.6394737Z "scope": "Process and test-evidence consistency, not clinical validation", +2026-10-08T16:58:06.6395486Z "seconds": 300.02024009999997, +2026-10-08T16:58:06.6395981Z "created_at": "2026-10-08T16:58:05.977591+00:00", +2026-10-08T16:58:06.6396905Z "run_directory": "build/evidence/python-20261008T165305Z-8ba576a8", +2026-10-08T16:58:06.6397806Z "log_sha256": "c2bf3d9313504aa13db59b07ce25b84c5cd3fcfc99331a60e3d0da7351784408", +2026-10-08T16:58:06.6398669Z "source_commit": "0de94b767061ec1fe5c05d11c6baa36ec9ddf16b", +2026-10-08T16:58:06.6399214Z "source_worktree_dirty": false, +2026-10-08T16:58:06.6399991Z "source_tree_sha256": "54236876c74e30d97fb8ef1a930918dec17b2ca7d719fcdb47ca1af3bc6f1bed", +2026-10-08T16:58:06.6400869Z "source_file_count": 1129, +2026-10-08T16:58:06.6401346Z "github": { +2026-10-08T16:58:06.6401732Z "GITHUB_ACTIONS": "true", +2026-10-08T16:58:06.6402215Z "GITHUB_EVENT_NAME": "pull_request", +2026-10-08T16:58:06.6402861Z "GITHUB_SHA": "0de94b767061ec1fe5c05d11c6baa36ec9ddf16b", +2026-10-08T16:58:06.6403516Z "GITHUB_REF": "refs/pull/71/merge", +2026-10-08T16:58:06.6404167Z "GITHUB_HEAD_REF": "work/analysis-history-401c5d17da79", +2026-10-08T16:58:06.6405106Z "GITHUB_BASE_REF": "main", +2026-10-08T16:58:06.6405673Z "GITHUB_RUN_ID": "37811934426", +2026-10-08T16:58:06.6406492Z "GITHUB_WORKFLOW_REF": "Jacob-Met/CaptureSuite/.github/workflows/ci.yml@refs/pull/71/merge" +2026-10-08T16:58:06.6407237Z }, +2026-10-08T16:58:06.6407603Z "source_unchanged_during_test": true +2026-10-08T16:58:06.6408101Z } +2026-10-08T16:58:06.7385198Z ##[error]Process completed with exit code 1. +2026-10-08T16:58:06.7589535Z ##[group]Run actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a +2026-10-08T16:58:06.7590073Z with: +2026-10-08T16:58:06.7590317Z name: python-test-evidence +2026-10-08T16:58:06.7590610Z path: build/evidence/ +2026-10-08T16:58:06.7590879Z if-no-files-found: warn +2026-10-08T16:58:06.7591515Z retention-days: 7 +2026-10-08T16:58:06.7591837Z compression-level: 6 +2026-10-08T16:58:06.7592109Z overwrite: false +2026-10-08T16:58:06.7592390Z include-hidden-files: false +2026-10-08T16:58:06.7592661Z archive: true +2026-10-08T16:58:06.7592908Z env: +2026-10-08T16:58:06.7593211Z pythonLocation: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:58:06.7593726Z PKG_CONFIG_PATH: C:\hostedtoolcache\windows\Python\3.12.10\x64/lib/pkgconfig +2026-10-08T16:58:06.7594241Z Python_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:58:06.7594690Z Python2_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:58:06.7595203Z Python3_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:58:06.7595573Z ##[endgroup] +2026-10-08T16:58:07.1168016Z With the provided path, there will be 280 files uploaded +2026-10-08T16:58:07.1174341Z Artifact name is valid! +2026-10-08T16:58:07.1175964Z Root directory input is valid! +2026-10-08T16:58:07.3285502Z Uploading artifact: python-test-evidence.zip +2026-10-08T16:58:07.3332109Z Beginning upload of artifact content to blob storage +2026-10-08T16:58:07.8565612Z Uploaded bytes 1600563 +2026-10-08T16:58:07.8696378Z Finished uploading artifact content to blob storage! +2026-10-08T16:58:07.8698090Z SHA256 digest of uploaded artifact is 5d0a77f1b24a3807d407e11e847e0354a3876c6ffbbe1d937a188dc0896c18f3 +2026-10-08T16:58:07.8699101Z Finalizing artifact upload +2026-10-08T16:58:08.1441604Z Artifact python-test-evidence successfully finalized. Artifact ID 11566210891 +2026-10-08T16:58:08.1443437Z Artifact python-test-evidence has been successfully uploaded! Final size is 1600563 bytes. Artifact ID is 11566210891 +2026-10-08T16:58:08.1449751Z Artifact download URL: https://github.com/Jacob-Met/CaptureSuite/actions/runs/37811934426/artifacts/11566210891 +2026-10-08T16:58:08.1794732Z Post job cleanup. +2026-10-08T16:58:08.4211801Z [command]"C:\Program Files\Git\bin\git.exe" version +2026-10-08T16:58:08.4510656Z git version 2.56.0.windows.1 +2026-10-08T16:58:08.4585935Z Temporarily overriding HOME='D:\a\_temp\c5c09ce2-1082-4774-8541-c786d7428b36' before making global git config changes +2026-10-08T16:58:08.4587608Z Adding repository directory to the temporary git global config as a safe directory +2026-10-08T16:58:08.4600414Z [command]"C:\Program Files\Git\bin\git.exe" config --global --add safe.directory D:\a\CaptureSuite\CaptureSuite +2026-10-08T16:58:08.4932217Z [command]"C:\Program Files\Git\bin\git.exe" config --local --name-only --get-regexp core\.sshCommand +2026-10-08T16:58:08.5262548Z [command]"C:\Program Files\Git\bin\git.exe" submodule foreach --recursive "sh -c \"git config --local --name-only --get-regexp 'core\.sshCommand' && git config --local --unset-all 'core.sshCommand' || :\"" +2026-10-08T16:58:09.0448059Z [command]"C:\Program Files\Git\bin\git.exe" config --local --name-only --get-regexp http\.https\:\/\/github\.com\/\.extraheader +2026-10-08T16:58:09.0731062Z http.https://github.com/.extraheader +2026-10-08T16:58:09.0768682Z [command]"C:\Program Files\Git\bin\git.exe" config --local --unset-all http.https://github.com/.extraheader +2026-10-08T16:58:09.1078354Z [command]"C:\Program Files\Git\bin\git.exe" submodule foreach --recursive "sh -c \"git config --local --name-only --get-regexp 'http\.https\:\/\/github\.com\/\.extraheader' && git config --local --unset-all 'http.https://github.com/.extraheader' || :\"" +2026-10-08T16:58:09.6026739Z [command]"C:\Program Files\Git\bin\git.exe" config --local --name-only --get-regexp ^includeIf\.gitdir: +2026-10-08T16:58:09.6356072Z [command]"C:\Program Files\Git\bin\git.exe" submodule foreach --recursive "git config --local --show-origin --name-only --get-regexp remote.origin.url" +2026-10-08T16:58:10.1268790Z Cleaning up orphan processes +2026-10-08T16:58:10.1510083Z Terminate orphan process: pid (6732) (vctip) +2026-10-08T16:58:10.1569860Z Terminate orphan process: pid (5600) (MSBuild) +2026-10-08T16:58:10.1717959Z Terminate orphan process: pid (2176) (conhost) +2026-10-08T16:58:10.1726130Z ##[warning]Node.js 20 is deprecated. The following actions target Node.js 20 but are being forced to run on Node.js 24: actions/checkout@v4, actions/setup-python@v5. For more information see: https://github.blog/changelog/2025-09-19-deprecation-of-node-20-on-github-actions-runners/ diff --git a/docs/receiving/analysis-history-ci-budget-401c5d17da79/retry-windows-timeout.log b/docs/receiving/analysis-history-ci-budget-401c5d17da79/retry-windows-timeout.log new file mode 100644 index 00000000..bb77d92c --- /dev/null +++ b/docs/receiving/analysis-history-ci-budget-401c5d17da79/retry-windows-timeout.log @@ -0,0 +1,542 @@ +2026-10-08T17:56:47.7326226Z Current runner version: '2.337.0' +2026-10-08T17:56:47.7346244Z ##[group]Runner Image Provisioner +2026-10-08T17:56:47.7346904Z Hosted Compute Agent +2026-10-08T17:56:47.7347356Z Version: 20261002.596 +2026-10-08T17:56:47.7347798Z Commit: c3d12f3313a95f25162a1503be624f3b0617f8c0 +2026-10-08T17:56:47.7348319Z Build Date: 2026-10-02T22:28:27Z +2026-10-08T17:56:47.7348824Z Worker ID: {6648adac-1715-40e8-a42f-f6295f46e7d0} +2026-10-08T17:56:47.7349311Z Region: westus3 +2026-10-08T17:56:47.7349696Z Cloud: Azure +2026-10-08T17:56:47.7350068Z ##[endgroup] +2026-10-08T17:56:47.7351049Z ##[group]Operating System +2026-10-08T17:56:47.7351517Z Microsoft Windows Server 2022 +2026-10-08T17:56:47.7351967Z 10.0.20348 +2026-10-08T17:56:47.7352342Z Datacenter +2026-10-08T17:56:47.7352706Z ##[endgroup] +2026-10-08T17:56:47.7353083Z ##[group]Runner Image +2026-10-08T17:56:47.7353498Z Image: windows-2022 +2026-10-08T17:56:47.7353891Z Version: 20261004.326.1 +2026-10-08T17:56:47.7354963Z Included Software: https://github.com/actions/runner-images/blob/win22/20261004.326/images/windows/Windows2022-Readme.md +2026-10-08T17:56:47.7356097Z Image Release: https://github.com/actions/runner-images/releases/tag/win22%2F20261004.326 +2026-10-08T17:56:47.7356811Z ##[endgroup] +2026-10-08T17:56:47.7357715Z ##[group]GITHUB_TOKEN Permissions +2026-10-08T17:56:47.7359089Z Contents: read +2026-10-08T17:56:47.7359513Z Metadata: read +2026-10-08T17:56:47.7359973Z Packages: read +2026-10-08T17:56:47.7360405Z ##[endgroup] +2026-10-08T17:56:47.7361993Z Secret source: Actions +2026-10-08T17:56:47.7362658Z Cache mode: write +2026-10-08T17:56:47.7363119Z Prepare workflow directory +2026-10-08T17:56:47.7632414Z Prepare all required actions +2026-10-08T17:56:47.7685714Z Getting action download info +2026-10-08T17:56:48.0967089Z Download action repository 'actions/checkout@v4' (SHA:11d5960a326750d5838078e36cf38b85af677262) +2026-10-08T17:56:48.2383804Z Download action repository 'actions/setup-python@v5' (SHA:a26af69be951a213d495a4c3e4e4022e16d87065) +2026-10-08T17:56:48.5032702Z Download action repository 'actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a' (SHA:043fb46d1a93c77aae656e7c1c64a875d1fc6a0a) +2026-10-08T17:56:48.8673977Z Complete job name: python +2026-10-08T17:56:49.1352281Z ##[group]Run actions/checkout@v4 +2026-10-08T17:56:49.1353324Z with: +2026-10-08T17:56:49.1353651Z repository: Jacob-Met/CaptureSuite +2026-10-08T17:56:49.1357143Z token: *** +2026-10-08T17:56:49.1357461Z ssh-strict: true +2026-10-08T17:56:49.1357787Z ssh-user: git +2026-10-08T17:56:49.1358111Z persist-credentials: true +2026-10-08T17:56:49.1358463Z clean: true +2026-10-08T17:56:49.1358787Z sparse-checkout-cone-mode: true +2026-10-08T17:56:49.1359164Z fetch-depth: 1 +2026-10-08T17:56:49.1359474Z fetch-tags: false +2026-10-08T17:56:49.1359786Z show-progress: true +2026-10-08T17:56:49.1360109Z lfs: false +2026-10-08T17:56:49.1360416Z submodules: false +2026-10-08T17:56:49.1360738Z set-safe-directory: true +2026-10-08T17:56:49.1361099Z allow-unsafe-pr-checkout: false +2026-10-08T17:56:49.1361734Z ##[endgroup] +2026-10-08T17:56:49.2523169Z Syncing repository: Jacob-Met/CaptureSuite +2026-10-08T17:56:49.2524574Z ##[group]Getting Git version info +2026-10-08T17:56:49.2525171Z Working directory is 'D:\a\CaptureSuite\CaptureSuite' +2026-10-08T17:56:49.3362137Z [command]"C:\Program Files\Git\bin\git.exe" version +2026-10-08T17:56:50.7414136Z git version 2.56.0.windows.1 +2026-10-08T17:56:50.7445182Z ##[endgroup] +2026-10-08T17:56:50.7459491Z Temporarily overriding HOME='D:\a\_temp\f1d6413d-486e-499a-89e9-ed09f2312c5c' before making global git config changes +2026-10-08T17:56:50.7460400Z Adding repository directory to the temporary git global config as a safe directory +2026-10-08T17:56:50.7468373Z [command]"C:\Program Files\Git\bin\git.exe" config --global --add safe.directory D:\a\CaptureSuite\CaptureSuite +2026-10-08T17:56:50.8460419Z Deleting the contents of 'D:\a\CaptureSuite\CaptureSuite' +2026-10-08T17:56:50.8464528Z ##[group]Initializing the repository +2026-10-08T17:56:50.8472143Z [command]"C:\Program Files\Git\bin\git.exe" init D:\a\CaptureSuite\CaptureSuite +2026-10-08T17:56:50.9891136Z Initialized empty Git repository in D:/a/CaptureSuite/CaptureSuite/.git/ +2026-10-08T17:56:50.9927986Z [command]"C:\Program Files\Git\bin\git.exe" remote add origin https://github.com/Jacob-Met/CaptureSuite +2026-10-08T17:56:51.0933044Z ##[endgroup] +2026-10-08T17:56:51.0933519Z ##[group]Disabling automatic garbage collection +2026-10-08T17:56:51.0940936Z [command]"C:\Program Files\Git\bin\git.exe" config --local gc.auto 0 +2026-10-08T17:56:51.1164314Z ##[endgroup] +2026-10-08T17:56:51.1164673Z ##[group]Setting up auth +2026-10-08T17:56:51.1173553Z [command]"C:\Program Files\Git\bin\git.exe" config --local --name-only --get-regexp core\.sshCommand +2026-10-08T17:56:51.1410006Z [command]"C:\Program Files\Git\bin\git.exe" submodule foreach --recursive "sh -c \"git config --local --name-only --get-regexp 'core\.sshCommand' && git config --local --unset-all 'core.sshCommand' || :\"" +2026-10-08T17:56:54.5328680Z [command]"C:\Program Files\Git\bin\git.exe" config --local --name-only --get-regexp http\.https\:\/\/github\.com\/\.extraheader +2026-10-08T17:56:54.5565190Z [command]"C:\Program Files\Git\bin\git.exe" submodule foreach --recursive "sh -c \"git config --local --name-only --get-regexp 'http\.https\:\/\/github\.com\/\.extraheader' && git config --local --unset-all 'http.https://github.com/.extraheader' || :\"" +2026-10-08T17:56:55.4711341Z [command]"C:\Program Files\Git\bin\git.exe" config --local --name-only --get-regexp ^includeIf\.gitdir: +2026-10-08T17:56:55.4979962Z [command]"C:\Program Files\Git\bin\git.exe" submodule foreach --recursive "git config --local --show-origin --name-only --get-regexp remote.origin.url" +2026-10-08T17:56:55.8909181Z [command]"C:\Program Files\Git\bin\git.exe" config --local http.https://github.com/.extraheader "AUTHORIZATION: basic ***" +2026-10-08T17:56:55.9144963Z ##[endgroup] +2026-10-08T17:56:55.9154900Z ##[group]Fetching the repository +2026-10-08T17:56:55.9157750Z [command]"C:\Program Files\Git\bin\git.exe" -c protocol.version=2 fetch --no-tags --prune --no-recurse-submodules --depth=1 origin +0de94b767061ec1fe5c05d11c6baa36ec9ddf16b:refs/remotes/pull/71/merge +2026-10-08T17:56:59.6644767Z From https://github.com/Jacob-Met/CaptureSuite +2026-10-08T17:56:59.6645515Z * [new ref] 0de94b767061ec1fe5c05d11c6baa36ec9ddf16b -> pull/71/merge +2026-10-08T17:56:59.6672909Z ##[endgroup] +2026-10-08T17:56:59.6673552Z ##[group]Determining the checkout info +2026-10-08T17:56:59.6675313Z ##[endgroup] +2026-10-08T17:56:59.6684343Z [command]"C:\Program Files\Git\bin\git.exe" sparse-checkout disable +2026-10-08T17:56:59.7190073Z [command]"C:\Program Files\Git\bin\git.exe" config --local --unset-all extensions.worktreeConfig +2026-10-08T17:56:59.7446670Z ##[group]Checking out the ref +2026-10-08T17:56:59.7447158Z [command]"C:\Program Files\Git\bin\git.exe" checkout --progress --force refs/remotes/pull/71/merge +2026-10-08T17:57:00.0432897Z Note: switching to 'refs/remotes/pull/71/merge'. +2026-10-08T17:57:00.0433269Z +2026-10-08T17:57:00.0433517Z You are in 'detached HEAD' state. You can look around, make experimental +2026-10-08T17:57:00.0434209Z changes and commit them, and you can discard any commits you make in this +2026-10-08T17:57:00.0434683Z state without impacting any branches by switching back to a branch. +2026-10-08T17:57:00.0434922Z +2026-10-08T17:57:00.0435068Z If you want to create a new branch to retain commits you create, you may +2026-10-08T17:57:00.0435470Z do so (now or later) by using -c with the switch command. Example: +2026-10-08T17:57:00.0435668Z +2026-10-08T17:57:00.0435777Z git switch -c +2026-10-08T17:57:00.0435922Z +2026-10-08T17:57:00.0436007Z Or undo this operation with: +2026-10-08T17:57:00.0436126Z +2026-10-08T17:57:00.0436195Z git switch - +2026-10-08T17:57:00.0436284Z +2026-10-08T17:57:00.0436451Z Turn off this advice by setting config variable advice.detachedHead to false +2026-10-08T17:57:00.0437560Z +2026-10-08T17:57:00.0564135Z HEAD is now at 0de94b7 Merge aefaffe03331f5c8e0cc41dfd75ce9c81f9d09fe into 3cbb5300bdc79c157370d1b3e599a6c82752d54a +2026-10-08T17:57:00.0618418Z ##[endgroup] +2026-10-08T17:57:00.0989617Z [command]"C:\Program Files\Git\bin\git.exe" log -1 --format=%H +2026-10-08T17:57:00.2602209Z 0de94b767061ec1fe5c05d11c6baa36ec9ddf16b +2026-10-08T17:57:00.2940222Z ##[group]Run actions/setup-python@v5 +2026-10-08T17:57:00.2940499Z with: +2026-10-08T17:57:00.2940656Z python-version: 3.12 +2026-10-08T17:57:00.2940844Z check-latest: false +2026-10-08T17:57:00.2942749Z token: *** +2026-10-08T17:57:00.2942921Z update-environment: true +2026-10-08T17:57:00.2943102Z allow-prereleases: false +2026-10-08T17:57:00.2943271Z freethreaded: false +2026-10-08T17:57:00.2943428Z ##[endgroup] +2026-10-08T17:57:00.4119855Z ##[group]Installed versions +2026-10-08T17:57:00.5101298Z (node:1592) [DEP0040] DeprecationWarning: The `punycode` module is deprecated. Please use a userland alternative instead. +2026-10-08T17:57:00.5102205Z (Use `node --trace-deprecation ...` to show where the warning was created) +2026-10-08T17:57:00.5102685Z Successfully set up CPython (3.12.10) +2026-10-08T17:57:00.5116627Z ##[endgroup] +2026-10-08T17:57:00.5310264Z ##[group]Run python -m pip install -r requirements-ci.txt +2026-10-08T17:57:00.5310724Z python -m pip install -r requirements-ci.txt +2026-10-08T17:57:00.5422103Z shell: C:\Program Files\PowerShell\7\pwsh.EXE -command ". '{0}'" +2026-10-08T17:57:00.5422370Z env: +2026-10-08T17:57:00.5422579Z pythonLocation: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T17:57:00.5422956Z PKG_CONFIG_PATH: C:\hostedtoolcache\windows\Python\3.12.10\x64/lib/pkgconfig +2026-10-08T17:57:00.5423302Z Python_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T17:57:00.5423603Z Python2_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T17:57:00.5423898Z Python3_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T17:57:00.5424155Z ##[endgroup] +2026-10-08T17:57:13.8364101Z Obtaining file:///D:/a/CaptureSuite/CaptureSuite/libs/python/capture_protocol (from -r requirements-ci.txt (line 3)) +2026-10-08T17:57:13.8387001Z Installing build dependencies: started +2026-10-08T17:57:16.9915103Z Installing build dependencies: finished with status 'done' +2026-10-08T17:57:16.9927473Z Checking if build backend supports build_editable: started +2026-10-08T17:57:17.6027485Z Checking if build backend supports build_editable: finished with status 'done' +2026-10-08T17:57:17.6045800Z Getting requirements to build editable: started +2026-10-08T17:57:18.1678876Z Getting requirements to build editable: finished with status 'done' +2026-10-08T17:57:18.1700620Z Preparing editable metadata (pyproject.toml): started +2026-10-08T17:57:18.4172009Z Preparing editable metadata (pyproject.toml): finished with status 'done' +2026-10-08T17:57:18.4209664Z Obtaining file:///D:/a/CaptureSuite/CaptureSuite/libs/python/capture_session (from -r requirements-ci.txt (line 4)) +2026-10-08T17:57:18.4232429Z Installing build dependencies: started +2026-10-08T17:57:19.8623999Z Installing build dependencies: finished with status 'done' +2026-10-08T17:57:19.8636404Z Checking if build backend supports build_editable: started +2026-10-08T17:57:20.2740652Z Checking if build backend supports build_editable: finished with status 'done' +2026-10-08T17:57:20.2757960Z Getting requirements to build editable: started +2026-10-08T17:57:20.7574938Z Getting requirements to build editable: finished with status 'done' +2026-10-08T17:57:20.7596486Z Preparing editable metadata (pyproject.toml): started +2026-10-08T17:57:21.0189141Z Preparing editable metadata (pyproject.toml): finished with status 'done' +2026-10-08T17:57:21.0224232Z Obtaining file:///D:/a/CaptureSuite/CaptureSuite/libs/python/capture_analysis +2026-10-08T17:57:21.0244717Z Installing build dependencies: started +2026-10-08T17:57:23.8436096Z Installing build dependencies: finished with status 'done' +2026-10-08T17:57:23.8447741Z Checking if build backend supports build_editable: started +2026-10-08T17:57:24.4631077Z Checking if build backend supports build_editable: finished with status 'done' +2026-10-08T17:57:24.4647255Z Getting requirements to build editable: started +2026-10-08T17:57:25.2352957Z Getting requirements to build editable: finished with status 'done' +2026-10-08T17:57:25.2376307Z Preparing editable metadata (pyproject.toml): started +2026-10-08T17:57:25.5709018Z Preparing editable metadata (pyproject.toml): finished with status 'done' +2026-10-08T17:57:25.5746651Z Obtaining file:///D:/a/CaptureSuite/CaptureSuite/libs/python/capture_worker (from -r requirements-ci.txt (line 6)) +2026-10-08T17:57:25.5766510Z Installing build dependencies: started +2026-10-08T17:57:27.7691170Z Installing build dependencies: finished with status 'done' +2026-10-08T17:57:27.7704662Z Checking if build backend supports build_editable: started +2026-10-08T17:57:28.4184415Z Checking if build backend supports build_editable: finished with status 'done' +2026-10-08T17:57:28.4201298Z Getting requirements to build editable: started +2026-10-08T17:57:30.0800787Z Getting requirements to build editable: finished with status 'done' +2026-10-08T17:57:30.0820319Z Preparing editable metadata (pyproject.toml): started +2026-10-08T17:57:30.3877760Z Preparing editable metadata (pyproject.toml): finished with status 'done' +2026-10-08T17:57:30.3911213Z Obtaining file:///D:/a/CaptureSuite/CaptureSuite/desktop +2026-10-08T17:57:30.3932556Z Installing build dependencies: started +2026-10-08T17:57:32.7957072Z Installing build dependencies: finished with status 'done' +2026-10-08T17:57:32.7968781Z Checking if build backend supports build_editable: started +2026-10-08T17:57:33.2265032Z Checking if build backend supports build_editable: finished with status 'done' +2026-10-08T17:57:33.2281837Z Getting requirements to build editable: started +2026-10-08T17:57:33.6587068Z Getting requirements to build editable: finished with status 'done' +2026-10-08T17:57:33.6607347Z Preparing editable metadata (pyproject.toml): started +2026-10-08T17:57:33.9067811Z Preparing editable metadata (pyproject.toml): finished with status 'done' +2026-10-08T17:57:34.5565953Z Collecting grpcio-tools<1.63,>=1.62 (from -r requirements-ci.txt (line 8)) +2026-10-08T17:57:34.6811557Z Downloading grpcio_tools-1.62.3-cp312-cp312-win_amd64.whl.metadata (6.4 kB) +2026-10-08T17:57:34.9110048Z Collecting mcap<2,>=1.1 (from -r requirements-ci.txt (line 9)) +2026-10-08T17:57:34.9169092Z Downloading mcap-1.5.0-py3-none-any.whl.metadata (380 bytes) +2026-10-08T17:57:35.0593349Z Collecting pytest>=8 (from -r requirements-ci.txt (line 10)) +2026-10-08T17:57:35.0673129Z Downloading pytest-9.1.1-py3-none-any.whl.metadata (7.6 kB) +2026-10-08T17:57:35.1618220Z Collecting pytest-cov>=5 (from -r requirements-ci.txt (line 11)) +2026-10-08T17:57:35.1657087Z Downloading pytest_cov-7.1.0-py3-none-any.whl.metadata (32 kB) +2026-10-08T17:57:35.5579775Z Collecting ruff<1,>=0.6 (from -r requirements-ci.txt (line 12)) +2026-10-08T17:57:35.5727113Z Downloading ruff-0.16.10-py3-none-win_amd64.whl.metadata (21 kB) +2026-10-08T17:57:35.9518688Z Collecting protobuf<5,>=4.25 (from capture-protocol==0.1.0->-r requirements-ci.txt (line 3)) +2026-10-08T17:57:35.9591566Z Downloading protobuf-4.25.9-cp310-abi3-win_amd64.whl.metadata (541 bytes) +2026-10-08T17:57:36.1657639Z Collecting jsonschema>=4.21 (from capture-session==0.1.0->-r requirements-ci.txt (line 4)) +2026-10-08T17:57:36.1701651Z Downloading jsonschema-4.26.0-py3-none-any.whl.metadata (7.6 kB) +2026-10-08T17:57:36.3344934Z Collecting pyyaml>=6.0 (from capture-analysis==0.1.0) +2026-10-08T17:57:36.3387571Z Downloading pyyaml-6.0.3-cp312-cp312-win_amd64.whl.metadata (2.4 kB) +2026-10-08T17:57:36.4501523Z Collecting PySide6<7,>=6.6 (from capture-desktop==0.1.0) +2026-10-08T17:57:36.4543193Z Downloading pyside6-6.12.0-cp310-abi3-win_amd64.whl.metadata (5.7 kB) +2026-10-08T17:57:36.6845401Z Collecting numpy>=1.26 (from capture-analysis==0.1.0) +2026-10-08T17:57:36.6892856Z Downloading numpy-2.5.3-cp312-cp312-win_amd64.whl.metadata (6.6 kB) +2026-10-08T17:57:36.8787036Z Collecting scipy>=1.11 (from capture-analysis==0.1.0) +2026-10-08T17:57:36.8845686Z Downloading scipy-1.18.1-cp312-cp312-win_amd64.whl.metadata (61 kB) +2026-10-08T17:57:37.0844933Z Collecting pandas>=2.1 (from capture-analysis==0.1.0) +2026-10-08T17:57:37.0942953Z Downloading pandas-3.0.6-cp312-cp312-win_amd64.whl.metadata (19 kB) +2026-10-08T17:57:37.7307361Z Collecting pyarrow>=14.0 (from capture-analysis==0.1.0) +2026-10-08T17:57:37.7386891Z Downloading pyarrow-25.0.1-cp312-cp312-win_amd64.whl.metadata (3.0 kB) +2026-10-08T17:57:37.9172942Z Collecting matplotlib>=3.8 (from capture-analysis==0.1.0) +2026-10-08T17:57:37.9225658Z Downloading matplotlib-3.11.2-cp312-cp312-win_amd64.whl.metadata (80 kB) +2026-10-08T17:57:38.0875701Z Collecting pyqtgraph>=0.13 (from capture-desktop==0.1.0) +2026-10-08T17:57:38.0930842Z Downloading pyqtgraph-0.14.0-py3-none-any.whl.metadata (1.5 kB) +2026-10-08T17:57:38.6176555Z Collecting grpcio>=1.62.3 (from grpcio-tools<1.63,>=1.62->-r requirements-ci.txt (line 8)) +2026-10-08T17:57:38.6350630Z Downloading grpcio-1.84.0-cp312-cp312-win_amd64.whl.metadata (3.9 kB) +2026-10-08T17:57:38.8024247Z Collecting setuptools (from grpcio-tools<1.63,>=1.62->-r requirements-ci.txt (line 8)) +2026-10-08T17:57:38.8176033Z Using cached setuptools-84.0.0-py3-none-any.whl.metadata (6.6 kB) +2026-10-08T17:57:39.1502545Z Collecting lz4 (from mcap<2,>=1.1->-r requirements-ci.txt (line 9)) +2026-10-08T17:57:39.1711702Z Downloading lz4-4.4.5-cp312-cp312-win_amd64.whl.metadata (3.9 kB) +2026-10-08T17:57:39.4763531Z Collecting zstandard (from mcap<2,>=1.1->-r requirements-ci.txt (line 9)) +2026-10-08T17:57:39.4929874Z Downloading zstandard-0.25.0-cp312-cp312-win_amd64.whl.metadata (3.3 kB) +2026-10-08T17:57:39.6890568Z Collecting PySide6_Essentials==6.12.0 (from PySide6<7,>=6.6->capture-desktop==0.1.0) +2026-10-08T17:57:39.6965552Z Downloading pyside6_essentials-6.12.0-cp310-abi3-win_amd64.whl.metadata (3.9 kB) +2026-10-08T17:57:39.8621920Z Collecting PySide6_Addons==6.12.0 (from PySide6<7,>=6.6->capture-desktop==0.1.0) +2026-10-08T17:57:39.9265169Z Downloading pyside6_addons-6.12.0-cp310-abi3-win_amd64.whl.metadata (4.4 kB) +2026-10-08T17:57:40.1534040Z Collecting PySide6_WebEngine==6.12.0.140 (from PySide6<7,>=6.6->capture-desktop==0.1.0) +2026-10-08T17:57:40.1598143Z Downloading pyside6_webengine-6.12.0.140-cp310-abi3-win_amd64.whl.metadata (3.7 kB) +2026-10-08T17:57:40.4024023Z Collecting PySide6_Pdf==6.12.0.140 (from PySide6<7,>=6.6->capture-desktop==0.1.0) +2026-10-08T17:57:40.4209875Z Downloading pyside6_pdf-6.12.0.140-cp310-abi3-win_amd64.whl.metadata (3.6 kB) +2026-10-08T17:57:40.5825837Z Collecting shiboken6==6.12.0 (from PySide6_Essentials==6.12.0->PySide6<7,>=6.6->capture-desktop==0.1.0) +2026-10-08T17:57:40.6176037Z Downloading shiboken6-6.12.0-cp310-abi3-win_amd64.whl.metadata (2.6 kB) +2026-10-08T17:57:40.6891062Z Requirement already satisfied: colorama>=0.4 in C:\hostedtoolcache\windows\Python\3.12.10\x64\Lib\site-packages (from pytest>=8->-r requirements-ci.txt (line 10)) (0.4.6) +2026-10-08T17:57:40.7921965Z Collecting iniconfig>=1.0.1 (from pytest>=8->-r requirements-ci.txt (line 10)) +2026-10-08T17:57:40.7962808Z Downloading iniconfig-2.3.1-py3-none-any.whl.metadata (2.8 kB) +2026-10-08T17:57:40.9377792Z Requirement already satisfied: packaging>=22 in C:\hostedtoolcache\windows\Python\3.12.10\x64\Lib\site-packages (from pytest>=8->-r requirements-ci.txt (line 10)) (26.3) +2026-10-08T17:57:40.9990693Z Collecting pluggy<2,>=1.5 (from pytest>=8->-r requirements-ci.txt (line 10)) +2026-10-08T17:57:41.0094846Z Downloading pluggy-1.6.0-py3-none-any.whl.metadata (4.8 kB) +2026-10-08T17:57:41.1571054Z Collecting pygments>=2.7.2 (from pytest>=8->-r requirements-ci.txt (line 10)) +2026-10-08T17:57:41.1650762Z Downloading pygments-2.21.0-py3-none-any.whl.metadata (2.5 kB) +2026-10-08T17:57:41.5966550Z Collecting coverage>=7.10.6 (from coverage[toml]>=7.10.6->pytest-cov>=5->-r requirements-ci.txt (line 11)) +2026-10-08T17:57:41.6009924Z Downloading coverage-7.16.2-cp312-cp312-win_amd64.whl.metadata (8.4 kB) +2026-10-08T17:57:41.7848303Z Collecting typing-extensions~=4.12 (from grpcio>=1.62.3->grpcio-tools<1.63,>=1.62->-r requirements-ci.txt (line 8)) +2026-10-08T17:57:41.7887694Z Downloading typing_extensions-4.16.0-py3-none-any.whl.metadata (3.3 kB) +2026-10-08T17:57:41.8752378Z Collecting attrs>=22.2.0 (from jsonschema>=4.21->capture-session==0.1.0->-r requirements-ci.txt (line 4)) +2026-10-08T17:57:42.0100452Z Downloading attrs-26.1.0-py3-none-any.whl.metadata (8.8 kB) +2026-10-08T17:57:42.0938467Z Collecting jsonschema-specifications>=2023.03.6 (from jsonschema>=4.21->capture-session==0.1.0->-r requirements-ci.txt (line 4)) +2026-10-08T17:57:42.0976801Z Downloading jsonschema_specifications-2025.9.1-py3-none-any.whl.metadata (2.9 kB) +2026-10-08T17:57:42.5209828Z Collecting referencing>=0.28.4 (from jsonschema>=4.21->capture-session==0.1.0->-r requirements-ci.txt (line 4)) +2026-10-08T17:57:42.5249719Z Downloading referencing-0.37.0-py3-none-any.whl.metadata (2.8 kB) +2026-10-08T17:57:42.9112500Z Collecting rpds-py>=0.25.0 (from jsonschema>=4.21->capture-session==0.1.0->-r requirements-ci.txt (line 4)) +2026-10-08T17:57:42.9802780Z Downloading rpds_py-2026.9.1-cp312-cp312-win_amd64.whl.metadata (4.2 kB) +2026-10-08T17:57:43.1143975Z Collecting contourpy>=1.0.1 (from matplotlib>=3.8->capture-analysis==0.1.0) +2026-10-08T17:57:43.1201884Z Downloading contourpy-1.4.0-cp312-cp312-win_amd64.whl.metadata (3.8 kB) +2026-10-08T17:57:43.3583815Z Collecting cycler>=0.10 (from matplotlib>=3.8->capture-analysis==0.1.0) +2026-10-08T17:57:43.3625932Z Downloading cycler-0.12.1-py3-none-any.whl.metadata (3.8 kB) +2026-10-08T17:57:43.5677686Z Collecting fonttools>=4.28.2 (from matplotlib>=3.8->capture-analysis==0.1.0) +2026-10-08T17:57:43.5843514Z Downloading fonttools-4.66.1-cp312-cp312-win_amd64.whl.metadata (132 kB) +2026-10-08T17:57:43.7475543Z Collecting kiwisolver>=1.3.1 (from matplotlib>=3.8->capture-analysis==0.1.0) +2026-10-08T17:57:43.8181272Z Downloading kiwisolver-1.5.1-cp312-cp312-win_amd64.whl.metadata (5.2 kB) +2026-10-08T17:57:44.0452060Z Collecting pillow>=9 (from matplotlib>=3.8->capture-analysis==0.1.0) +2026-10-08T17:57:44.1538680Z Downloading pillow-12.3.0-cp312-cp312-win_amd64.whl.metadata (9.3 kB) +2026-10-08T17:57:44.2928714Z Collecting pyparsing>=3 (from matplotlib>=3.8->capture-analysis==0.1.0) +2026-10-08T17:57:44.2989679Z Downloading pyparsing-3.3.3-py3-none-any.whl.metadata (5.9 kB) +2026-10-08T17:57:44.3946238Z Collecting python-dateutil>=2.7 (from matplotlib>=3.8->capture-analysis==0.1.0) +2026-10-08T17:57:44.3994854Z Downloading python_dateutil-2.9.0.post0-py2.py3-none-any.whl.metadata (8.4 kB) +2026-10-08T17:57:44.5048514Z Collecting tzdata (from pandas>=2.1->capture-analysis==0.1.0) +2026-10-08T17:57:44.5089100Z Downloading tzdata-2026.5-py2.py3-none-any.whl.metadata (1.4 kB) +2026-10-08T17:57:44.6285074Z Collecting six>=1.5 (from python-dateutil>=2.7->matplotlib>=3.8->capture-analysis==0.1.0) +2026-10-08T17:57:44.6321879Z Downloading six-1.17.0-py2.py3-none-any.whl.metadata (1.7 kB) +2026-10-08T17:57:44.7305405Z Downloading grpcio_tools-1.62.3-cp312-cp312-win_amd64.whl (1.1 MB) +2026-10-08T17:57:44.7963909Z ---------------------------------------- 1.1/1.1 MB 12.6 MB/s 0:00:00 +2026-10-08T17:57:44.8086067Z Downloading mcap-1.5.0-py3-none-any.whl (21 kB) +2026-10-08T17:57:44.9467807Z Downloading ruff-0.16.10-py3-none-win_amd64.whl (10.6 MB) +2026-10-08T17:57:45.0999689Z ---------------------------------------- 10.6/10.6 MB 73.2 MB/s 0:00:00 +2026-10-08T17:57:45.1040040Z Downloading protobuf-4.25.9-cp310-abi3-win_amd64.whl (413 kB) +2026-10-08T17:57:45.1582575Z Downloading pyside6-6.12.0-cp310-abi3-win_amd64.whl (578 kB) +2026-10-08T17:57:45.2071187Z ---------------------------------------- 579.0/579.0 kB 6.7 MB/s 0:00:00 +2026-10-08T17:57:45.2198348Z Downloading pyside6_addons-6.12.0-cp310-abi3-win_amd64.whl (40.5 MB) +2026-10-08T17:57:47.2939682Z ---------------------------------------- 40.5/40.5 MB 19.4 MB/s 0:00:02 +2026-10-08T17:57:47.3020006Z Downloading pyside6_essentials-6.12.0-cp310-abi3-win_amd64.whl (82.2 MB) +2026-10-08T17:57:49.4867142Z ---------------------------------------- 82.2/82.2 MB 37.4 MB/s 0:00:02 +2026-10-08T17:57:49.4924167Z Downloading pyside6_pdf-6.12.0.140-cp310-abi3-win_amd64.whl (3.0 MB) +2026-10-08T17:57:49.5356746Z ---------------------------------------- 3.0/3.0 MB 57.9 MB/s 0:00:00 +2026-10-08T17:57:49.5419306Z Downloading pyside6_webengine-6.12.0.140-cp310-abi3-win_amd64.whl (131.7 MB) +2026-10-08T17:57:53.2829632Z ---------------------------------------- 131.7/131.7 MB 35.2 MB/s 0:00:03 +2026-10-08T17:57:53.2882494Z Downloading shiboken6-6.12.0-cp310-abi3-win_amd64.whl (1.3 MB) +2026-10-08T17:57:53.3184971Z ---------------------------------------- 1.3/1.3 MB 32.4 MB/s 0:00:00 +2026-10-08T17:57:53.3221768Z Downloading pytest-9.1.1-py3-none-any.whl (386 kB) +2026-10-08T17:57:53.3598283Z Downloading pluggy-1.6.0-py3-none-any.whl (20 kB) +2026-10-08T17:57:53.3866792Z Downloading pytest_cov-7.1.0-py3-none-any.whl (22 kB) +2026-10-08T17:57:53.4081921Z Downloading coverage-7.16.2-cp312-cp312-win_amd64.whl (226 kB) +2026-10-08T17:57:53.4358884Z Downloading grpcio-1.84.0-cp312-cp312-win_amd64.whl (5.3 MB) +2026-10-08T17:57:53.5071378Z ---------------------------------------- 5.3/5.3 MB 64.0 MB/s 0:00:00 +2026-10-08T17:57:53.5110474Z Downloading typing_extensions-4.16.0-py3-none-any.whl (45 kB) +2026-10-08T17:57:53.5318028Z Downloading iniconfig-2.3.1-py3-none-any.whl (7.6 kB) +2026-10-08T17:57:53.5574286Z Downloading jsonschema-4.26.0-py3-none-any.whl (90 kB) +2026-10-08T17:57:53.5817631Z Downloading attrs-26.1.0-py3-none-any.whl (67 kB) +2026-10-08T17:57:53.6154151Z Downloading jsonschema_specifications-2025.9.1-py3-none-any.whl (18 kB) +2026-10-08T17:57:53.6449941Z Downloading matplotlib-3.11.2-cp312-cp312-win_amd64.whl (9.3 MB) +2026-10-08T17:57:53.7813182Z ---------------------------------------- 9.3/9.3 MB 72.7 MB/s 0:00:00 +2026-10-08T17:57:53.7868230Z Downloading contourpy-1.4.0-cp312-cp312-win_amd64.whl (234 kB) +2026-10-08T17:57:53.8214482Z Downloading cycler-0.12.1-py3-none-any.whl (8.3 kB) +2026-10-08T17:57:53.8454690Z Downloading fonttools-4.66.1-cp312-cp312-win_amd64.whl (2.5 MB) +2026-10-08T17:57:53.8822107Z ---------------------------------------- 2.5/2.5 MB 71.8 MB/s 0:00:00 +2026-10-08T17:57:53.8862482Z Downloading kiwisolver-1.5.1-cp312-cp312-win_amd64.whl (70 kB) +2026-10-08T17:57:53.9106105Z Downloading numpy-2.5.3-cp312-cp312-win_amd64.whl (12.6 MB) +2026-10-08T17:57:54.2465174Z ---------------------------------------- 12.6/12.6 MB 37.5 MB/s 0:00:00 +2026-10-08T17:57:54.2523571Z Downloading pandas-3.0.6-cp312-cp312-win_amd64.whl (9.7 MB) +2026-10-08T17:57:54.3714314Z ---------------------------------------- 9.7/9.7 MB 86.2 MB/s 0:00:00 +2026-10-08T17:57:54.3756524Z Downloading pillow-12.3.0-cp312-cp312-win_amd64.whl (7.2 MB) +2026-10-08T17:57:54.4471987Z ---------------------------------------- 7.2/7.2 MB 112.3 MB/s 0:00:00 +2026-10-08T17:57:54.4520863Z Downloading pyarrow-25.0.1-cp312-cp312-win_amd64.whl (28.0 MB) +2026-10-08T17:57:55.2799863Z ---------------------------------------- 28.0/28.0 MB 33.4 MB/s 0:00:00 +2026-10-08T17:57:55.2837898Z Downloading pygments-2.21.0-py3-none-any.whl (1.3 MB) +2026-10-08T17:57:55.4341371Z ---------------------------------------- 1.3/1.3 MB 7.0 MB/s 0:00:00 +2026-10-08T17:57:55.4382688Z Downloading pyparsing-3.3.3-py3-none-any.whl (126 kB) +2026-10-08T17:57:55.5311098Z Downloading pyqtgraph-0.14.0-py3-none-any.whl (1.9 MB) +2026-10-08T17:57:55.5906121Z ---------------------------------------- 1.9/1.9 MB 26.8 MB/s 0:00:00 +2026-10-08T17:57:55.5944826Z Downloading python_dateutil-2.9.0.post0-py2.py3-none-any.whl (229 kB) +2026-10-08T17:57:55.6220928Z Downloading pyyaml-6.0.3-cp312-cp312-win_amd64.whl (154 kB) +2026-10-08T17:57:57.7504386Z Downloading referencing-0.37.0-py3-none-any.whl (26 kB) +2026-10-08T17:57:57.7775378Z Downloading rpds_py-2026.9.1-cp312-cp312-win_amd64.whl (222 kB) +2026-10-08T17:57:57.8089219Z Downloading scipy-1.18.1-cp312-cp312-win_amd64.whl (36.7 MB) +2026-10-08T17:57:58.6055140Z ---------------------------------------- 36.7/36.7 MB 45.7 MB/s 0:00:00 +2026-10-08T17:57:58.6096320Z Downloading six-1.17.0-py2.py3-none-any.whl (11 kB) +2026-10-08T17:57:58.6427259Z Downloading lz4-4.4.5-cp312-cp312-win_amd64.whl (99 kB) +2026-10-08T17:57:58.6858457Z Using cached setuptools-84.0.0-py3-none-any.whl (818 kB) +2026-10-08T17:57:58.7141620Z Downloading tzdata-2026.5-py2.py3-none-any.whl (347 kB) +2026-10-08T17:57:58.9202454Z Downloading zstandard-0.25.0-cp312-cp312-win_amd64.whl (506 kB) +2026-10-08T17:57:59.6239624Z Building wheels for collected packages: capture-protocol, capture-session, capture-analysis, capture-worker, capture-desktop +2026-10-08T17:57:59.6592591Z Building editable for capture-protocol (pyproject.toml): started +2026-10-08T17:58:00.0588911Z Building editable for capture-protocol (pyproject.toml): finished with status 'done' +2026-10-08T17:58:00.0632902Z Created wheel for capture-protocol: filename=capture_protocol-0.1.0-0.editable-py3-none-any.whl size=7398 sha256=eb40d3ca4a00381327e4d350b7c834440a0d54265d0ab4ef2b545057d4102d8f +2026-10-08T17:58:00.0634210Z Stored in directory: C:\Users\runneradmin\AppData\Local\Temp\pip-ephem-wheel-cache-vmtpu9vq\wheels\be\38\74\adf0f9a8f0ba8d26599b299cff33b892a58ed35959c9e09acd +2026-10-08T17:58:00.0669125Z Building editable for capture-session (pyproject.toml): started +2026-10-08T17:58:00.3160185Z Building editable for capture-session (pyproject.toml): finished with status 'done' +2026-10-08T17:58:00.3197494Z Created wheel for capture-session: filename=capture_session-0.1.0-0.editable-py3-none-any.whl size=2863 sha256=3d34023bf758619ba50ab2c6d37637c4c3af6bd9cc44ea1865bb9fccbdeda5f8 +2026-10-08T17:58:00.3198741Z Stored in directory: C:\Users\runneradmin\AppData\Local\Temp\pip-ephem-wheel-cache-vmtpu9vq\wheels\49\8f\6e\163bd066522d89fdd0906cf22a1687ebc628821c7980903be9 +2026-10-08T17:58:00.3232415Z Building editable for capture-analysis (pyproject.toml): started +2026-10-08T17:58:00.6151638Z Building editable for capture-analysis (pyproject.toml): finished with status 'done' +2026-10-08T17:58:00.6191864Z Created wheel for capture-analysis: filename=capture_analysis-0.1.0-0.editable-py3-none-any.whl size=3050 sha256=aa2fae1e9f99d272c68fcf399ca8b08c300a5766d1c77e67b8823c7205a5d3cf +2026-10-08T17:58:00.6193084Z Stored in directory: C:\Users\runneradmin\AppData\Local\Temp\pip-ephem-wheel-cache-vmtpu9vq\wheels\f4\d1\58\14e4976a0c15c2c470fc12f9a2873cc8c4bc7bd989766b97b4 +2026-10-08T17:58:00.6226773Z Building editable for capture-worker (pyproject.toml): started +2026-10-08T17:58:01.0262835Z Building editable for capture-worker (pyproject.toml): finished with status 'done' +2026-10-08T17:58:01.0302721Z Created wheel for capture-worker: filename=capture_worker-0.1.0-0.editable-py3-none-any.whl size=7659 sha256=193ead0af35a65f5cd3a3e7c2a00da5e2a28427d4914417c9dc4b2528a8927c9 +2026-10-08T17:58:01.0304193Z Stored in directory: C:\Users\runneradmin\AppData\Local\Temp\pip-ephem-wheel-cache-vmtpu9vq\wheels\91\10\bd\b56fd1c22822b4cd753ca217f259119db33a4fa54b26c297ee +2026-10-08T17:58:01.0339512Z Building editable for capture-desktop (pyproject.toml): started +2026-10-08T17:58:01.3007674Z Building editable for capture-desktop (pyproject.toml): finished with status 'done' +2026-10-08T17:58:01.3047642Z Created wheel for capture-desktop: filename=capture_desktop-0.1.0-0.editable-py3-none-any.whl size=3184 sha256=024001dd870ccbb005c848909fa84485440910e35751b764dce0ddb002d7e098 +2026-10-08T17:58:01.3048860Z Stored in directory: C:\Users\runneradmin\AppData\Local\Temp\pip-ephem-wheel-cache-vmtpu9vq\wheels\04\f4\80\083223dba330947d948f2d768e3de9f1e54ae638d0a391d614 +2026-10-08T17:58:01.3067824Z Successfully built capture-protocol capture-session capture-analysis capture-worker capture-desktop +2026-10-08T17:58:01.4356223Z Installing collected packages: zstandard, tzdata, typing-extensions, six, shiboken6, setuptools, ruff, rpds-py, pyyaml, pyparsing, pygments, pyarrow, protobuf, pluggy, pillow, numpy, lz4, kiwisolver, iniconfig, fonttools, cycler, coverage, attrs, scipy, referencing, python-dateutil, pytest, PySide6_Essentials, pyqtgraph, mcap, grpcio, contourpy, capture-protocol, pytest-cov, PySide6_Pdf, PySide6_Addons, pandas, matplotlib, jsonschema-specifications, grpcio-tools, capture-worker, PySide6_WebEngine, jsonschema, PySide6, capture-session, capture-desktop, capture-analysis +2026-10-08T17:59:18.7341538Z +2026-10-08T17:59:18.7379713Z Successfully installed PySide6-6.12.0 PySide6_Addons-6.12.0 PySide6_Essentials-6.12.0 PySide6_Pdf-6.12.0.140 PySide6_WebEngine-6.12.0.140 attrs-26.1.0 capture-analysis-0.1.0 capture-desktop-0.1.0 capture-protocol-0.1.0 capture-session-0.1.0 capture-worker-0.1.0 contourpy-1.4.0 coverage-7.16.2 cycler-0.12.1 fonttools-4.66.1 grpcio-1.84.0 grpcio-tools-1.62.3 iniconfig-2.3.1 jsonschema-4.26.0 jsonschema-specifications-2025.9.1 kiwisolver-1.5.1 lz4-4.4.5 matplotlib-3.11.2 mcap-1.5.0 numpy-2.5.3 pandas-3.0.6 pillow-12.3.0 pluggy-1.6.0 protobuf-4.25.9 pyarrow-25.0.1 pygments-2.21.0 pyparsing-3.3.3 pyqtgraph-0.14.0 pytest-9.1.1 pytest-cov-7.1.0 python-dateutil-2.9.0.post0 pyyaml-6.0.3 referencing-0.37.0 rpds-py-2026.9.1 ruff-0.16.10 scipy-1.18.1 setuptools-84.0.0 shiboken6-6.12.0 six-1.17.0 typing-extensions-4.16.0 tzdata-2026.5 zstandard-0.25.0 +2026-10-08T17:59:19.3512940Z ##[group]Run python -m pip check +2026-10-08T17:59:19.3513238Z python -m pip check +2026-10-08T17:59:19.3544085Z shell: C:\Program Files\PowerShell\7\pwsh.EXE -command ". '{0}'" +2026-10-08T17:59:19.3544365Z env: +2026-10-08T17:59:19.3544613Z pythonLocation: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T17:59:19.3544977Z PKG_CONFIG_PATH: C:\hostedtoolcache\windows\Python\3.12.10\x64/lib/pkgconfig +2026-10-08T17:59:19.3545337Z Python_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T17:59:19.3545651Z Python2_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T17:59:19.3545956Z Python3_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T17:59:19.3546199Z ##[endgroup] +2026-10-08T17:59:21.1848341Z No broken requirements found. +2026-10-08T17:59:21.3133403Z ##[group]Run python tools/check_ci_contract.py --check-environment +2026-10-08T17:59:21.3133848Z python tools/check_ci_contract.py --check-environment +2026-10-08T17:59:21.3166122Z shell: C:\Program Files\PowerShell\7\pwsh.EXE -command ". '{0}'" +2026-10-08T17:59:21.3166391Z env: +2026-10-08T17:59:21.3166613Z pythonLocation: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T17:59:21.3166981Z PKG_CONFIG_PATH: C:\hostedtoolcache\windows\Python\3.12.10\x64/lib/pkgconfig +2026-10-08T17:59:21.3167337Z Python_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T17:59:21.3167678Z Python2_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T17:59:21.3167978Z Python3_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T17:59:21.3168222Z ##[endgroup] +2026-10-08T17:59:28.3006375Z Matplotlib is building the font cache; this may take a moment. +2026-10-08T17:59:38.9629598Z { +2026-10-08T17:59:38.9629930Z "accepted": true, +2026-10-08T17:59:38.9630118Z "errors": [] +2026-10-08T17:59:38.9630264Z } +2026-10-08T17:59:39.2354882Z ##[group]Run python tools/gen_protos.py +2026-10-08T17:59:39.2355319Z python tools/gen_protos.py +2026-10-08T17:59:39.2400276Z shell: C:\Program Files\PowerShell\7\pwsh.EXE -command ". '{0}'" +2026-10-08T17:59:39.2400690Z env: +2026-10-08T17:59:39.2401016Z pythonLocation: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T17:59:39.2401609Z PKG_CONFIG_PATH: C:\hostedtoolcache\windows\Python\3.12.10\x64/lib/pkgconfig +2026-10-08T17:59:39.2402174Z Python_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T17:59:39.2403500Z Python2_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T17:59:39.2403985Z Python3_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T17:59:39.2404381Z ##[endgroup] +2026-10-08T17:59:39.5683320Z Running: C:\hostedtoolcache\windows\Python\3.12.10\x64\python.exe -m grpc_tools.protoc --proto_path=D:\a\CaptureSuite\CaptureSuite\schemas\proto --python_out=D:\a\CaptureSuite\CaptureSuite\libs\python\capture_protocol\capture_protocol\generated --descriptor_set_out=D:\a\CaptureSuite\CaptureSuite\build\generated\capture_v1.desc --include_imports --proto_path=C:\hostedtoolcache\windows\Python\3.12.10\x64\Lib\site-packages\grpc_tools\_proto capture/v1/arrays.proto capture/v1/common.proto capture/v1/control.proto capture/v1/data/emg_batch.proto capture/v1/data/imu_frame.proto capture/v1/data/numeric_batch.proto capture/v1/data/radar_doppler.proto capture/v1/data/radar_frame.proto capture/v1/data/video_timing.proto capture/v1/events.proto capture/v1/health.proto capture/v1/presets.proto capture/v1/preview.proto capture/v1/project.proto capture/v1/source.proto capture/v1/storage.proto capture/v1/worker.proto +2026-10-08T17:59:39.5686125Z Wrote Python bindings under D:\a\CaptureSuite\CaptureSuite\libs\python\capture_protocol\capture_protocol\generated +2026-10-08T17:59:39.5686644Z Wrote descriptor set D:\a\CaptureSuite\CaptureSuite\build\generated\capture_v1.desc +2026-10-08T17:59:39.6711529Z ##[group]Run git diff --exit-code -- libs/python/capture_protocol/capture_protocol/generated +2026-10-08T17:59:39.6712091Z git diff --exit-code -- libs/python/capture_protocol/capture_protocol/generated +2026-10-08T17:59:39.6743656Z shell: C:\Program Files\PowerShell\7\pwsh.EXE -command ". '{0}'" +2026-10-08T17:59:39.6743923Z env: +2026-10-08T17:59:39.6744134Z pythonLocation: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T17:59:39.6744500Z PKG_CONFIG_PATH: C:\hostedtoolcache\windows\Python\3.12.10\x64/lib/pkgconfig +2026-10-08T17:59:39.6744864Z Python_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T17:59:39.6745170Z Python2_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T17:59:39.6745471Z Python3_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T17:59:39.6745709Z ##[endgroup] +2026-10-08T17:59:39.9949878Z ##[group]Run python tools/gen_session_schemas.py +2026-10-08T17:59:39.9950237Z python tools/gen_session_schemas.py +2026-10-08T17:59:39.9980327Z shell: C:\Program Files\PowerShell\7\pwsh.EXE -command ". '{0}'" +2026-10-08T17:59:39.9980593Z env: +2026-10-08T17:59:39.9980816Z pythonLocation: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T17:59:39.9981183Z PKG_CONFIG_PATH: C:\hostedtoolcache\windows\Python\3.12.10\x64/lib/pkgconfig +2026-10-08T17:59:39.9981529Z Python_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T17:59:39.9981841Z Python2_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T17:59:39.9982164Z Python3_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T17:59:39.9982409Z ##[endgroup] +2026-10-08T17:59:40.2630390Z Wrote 19 schemas to D:\a\CaptureSuite\CaptureSuite\schemas\session\jsonschema +2026-10-08T17:59:40.3523757Z ##[group]Run git diff --exit-code -- schemas/session/jsonschema +2026-10-08T17:59:40.3524242Z git diff --exit-code -- schemas/session/jsonschema +2026-10-08T17:59:40.3554576Z shell: C:\Program Files\PowerShell\7\pwsh.EXE -command ". '{0}'" +2026-10-08T17:59:40.3554912Z env: +2026-10-08T17:59:40.3611749Z pythonLocation: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T17:59:40.3612170Z PKG_CONFIG_PATH: C:\hostedtoolcache\windows\Python\3.12.10\x64/lib/pkgconfig +2026-10-08T17:59:40.3612516Z Python_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T17:59:40.3612824Z Python2_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T17:59:40.3613122Z Python3_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T17:59:40.3613540Z ##[endgroup] +2026-10-08T17:59:40.6615896Z ##[group]Run ruff check libs/python/capture_protocol libs/python/capture_session libs/python/capture_analysis libs/python/capture_worker workers/python_host desktop/capture_desktop tools tests plugins/example_sine_py plugins/lsl_bridge +2026-10-08T17:59:40.6617187Z ruff check libs/python/capture_protocol libs/python/capture_session libs/python/capture_analysis libs/python/capture_worker workers/python_host desktop/capture_desktop tools tests plugins/example_sine_py plugins/lsl_bridge +2026-10-08T17:59:40.6647660Z shell: C:\Program Files\PowerShell\7\pwsh.EXE -command ". '{0}'" +2026-10-08T17:59:40.6647924Z env: +2026-10-08T17:59:40.6648130Z pythonLocation: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T17:59:40.6648486Z PKG_CONFIG_PATH: C:\hostedtoolcache\windows\Python\3.12.10\x64/lib/pkgconfig +2026-10-08T17:59:40.6648821Z Python_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T17:59:40.6649177Z Python2_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T17:59:40.6649483Z Python3_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T17:59:40.6649724Z ##[endgroup] +2026-10-08T17:59:40.9390900Z All checks passed! +2026-10-08T17:59:41.0231900Z ##[group]Run python tools/check_licenses.py --enforce-spdx +2026-10-08T17:59:41.0232295Z python tools/check_licenses.py --enforce-spdx +2026-10-08T17:59:41.0262968Z shell: C:\Program Files\PowerShell\7\pwsh.EXE -command ". '{0}'" +2026-10-08T17:59:41.0263241Z env: +2026-10-08T17:59:41.0263451Z pythonLocation: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T17:59:41.0263808Z PKG_CONFIG_PATH: C:\hostedtoolcache\windows\Python\3.12.10\x64/lib/pkgconfig +2026-10-08T17:59:41.0264145Z Python_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T17:59:41.0264445Z Python2_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T17:59:41.0264742Z Python3_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T17:59:41.0264995Z ##[endgroup] +2026-10-08T17:59:41.5224292Z license check OK +2026-10-08T17:59:41.6114314Z ##[group]Run python tools/run_ci_tests.py +2026-10-08T17:59:41.6114717Z python tools/run_ci_tests.py +2026-10-08T17:59:41.6144552Z shell: C:\Program Files\PowerShell\7\pwsh.EXE -command ". '{0}'" +2026-10-08T17:59:41.6144822Z env: +2026-10-08T17:59:41.6145029Z pythonLocation: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T17:59:41.6145393Z PKG_CONFIG_PATH: C:\hostedtoolcache\windows\Python\3.12.10\x64/lib/pkgconfig +2026-10-08T17:59:41.6145744Z Python_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T17:59:41.6146056Z Python2_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T17:59:41.6146357Z Python3_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T17:59:41.6146607Z QT_QPA_PLATFORM: offscreen +2026-10-08T17:59:41.6146783Z ##[endgroup] +2026-10-08T18:04:42.7442288Z ........................................................................ [ 13%] +2026-10-08T18:04:42.7443645Z ........................................................................ [ 26%] +2026-10-08T18:04:42.7444095Z ........................................................................ [ 39%] +2026-10-08T18:04:42.7444516Z ........................................................................ [ 52%] +2026-10-08T18:04:42.7444934Z ..........................................................ssssss........ [ 65%] +2026-10-08T18:04:42.7445336Z ........................................................................ [ 78%] +2026-10-08T18:04:42.7445722Z ........................................................................ [ 91%] +2026-10-08T18:04:42.7446056Z ................. +2026-10-08T18:04:42.7446274Z { +2026-10-08T18:04:42.7446505Z "schema": "capturesuite.test-receipt.v1", +2026-10-08T18:04:42.7446791Z "accepted": false, +2026-10-08T18:04:42.7447006Z "process_exit": null, +2026-10-08T18:04:42.7447477Z "counts": null, +2026-10-08T18:04:42.7447671Z "junit_sha256": null, +2026-10-08T18:04:42.7447884Z "problems": [ +2026-10-08T18:04:42.7448108Z "Test process did not exit successfully", +2026-10-08T18:04:42.7448459Z "JUnit unavailable or invalid: FileNotFoundError" +2026-10-08T18:04:42.7448761Z ], +2026-10-08T18:04:42.7449075Z "scope": "Process and test-evidence consistency, not clinical validation", +2026-10-08T18:04:42.7449488Z "seconds": 300.0128827, +2026-10-08T18:04:42.7449734Z "created_at": "2026-10-08T18:04:42.298278+00:00", +2026-10-08T18:04:42.7450355Z "run_directory": "build/evidence/python-20261008T175941Z-568e4dcc", +2026-10-08T18:04:42.7450902Z "log_sha256": "6ae57baacfa0eb399a6cbab6afb4baa9ba28c9bb333f2af5b90074d3faf02b87", +2026-10-08T18:04:42.7451449Z "source_commit": "0de94b767061ec1fe5c05d11c6baa36ec9ddf16b", +2026-10-08T18:04:42.7451862Z "source_worktree_dirty": false, +2026-10-08T18:04:42.7452368Z "source_tree_sha256": "54236876c74e30d97fb8ef1a930918dec17b2ca7d719fcdb47ca1af3bc6f1bed", +2026-10-08T18:04:42.7452926Z "source_file_count": 1129, +2026-10-08T18:04:42.7453213Z "github": { +2026-10-08T18:04:42.7453443Z "GITHUB_ACTIONS": "true", +2026-10-08T18:04:42.7453742Z "GITHUB_EVENT_NAME": "pull_request", +2026-10-08T18:04:42.7454133Z "GITHUB_SHA": "0de94b767061ec1fe5c05d11c6baa36ec9ddf16b", +2026-10-08T18:04:42.7454567Z "GITHUB_REF": "refs/pull/71/merge", +2026-10-08T18:04:42.7454927Z "GITHUB_HEAD_REF": "work/analysis-history-401c5d17da79", +2026-10-08T18:04:42.7455414Z "GITHUB_BASE_REF": "main", +2026-10-08T18:04:42.7455807Z "GITHUB_RUN_ID": "37811934426", +2026-10-08T18:04:42.7456284Z "GITHUB_WORKFLOW_REF": "Jacob-Met/CaptureSuite/.github/workflows/ci.yml@refs/pull/71/merge" +2026-10-08T18:04:42.7456730Z }, +2026-10-08T18:04:42.7456952Z "source_unchanged_during_test": true +2026-10-08T18:04:42.7457258Z } +2026-10-08T18:04:42.8248893Z ##[error]Process completed with exit code 1. +2026-10-08T18:04:42.8402516Z ##[group]Run actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a +2026-10-08T18:04:42.8402956Z with: +2026-10-08T18:04:42.8403187Z name: python-test-evidence +2026-10-08T18:04:42.8403428Z path: build/evidence/ +2026-10-08T18:04:42.8403645Z if-no-files-found: warn +2026-10-08T18:04:42.8403863Z retention-days: 7 +2026-10-08T18:04:42.8404063Z compression-level: 6 +2026-10-08T18:04:42.8404262Z overwrite: false +2026-10-08T18:04:42.8404471Z include-hidden-files: false +2026-10-08T18:04:42.8404692Z archive: true +2026-10-08T18:04:42.8404901Z env: +2026-10-08T18:04:42.8405156Z pythonLocation: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T18:04:42.8405576Z PKG_CONFIG_PATH: C:\hostedtoolcache\windows\Python\3.12.10\x64/lib/pkgconfig +2026-10-08T18:04:42.8405969Z Python_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T18:04:42.8406329Z Python2_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T18:04:42.8406743Z Python3_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T18:04:42.8407038Z ##[endgroup] +2026-10-08T18:04:43.0800408Z With the provided path, there will be 280 files uploaded +2026-10-08T18:04:43.0804884Z Artifact name is valid! +2026-10-08T18:04:43.0805923Z Root directory input is valid! +2026-10-08T18:04:43.4294150Z Uploading artifact: python-test-evidence.zip +2026-10-08T18:04:43.4326749Z Beginning upload of artifact content to blob storage +2026-10-08T18:04:44.4411734Z Uploaded bytes 1600361 +2026-10-08T18:04:44.5032176Z Finished uploading artifact content to blob storage! +2026-10-08T18:04:44.5032966Z SHA256 digest of uploaded artifact is c20b94bba34343842a0948579327285a9694f87a63520a3eab139db43cee7636 +2026-10-08T18:04:44.5033632Z Finalizing artifact upload +2026-10-08T18:04:44.8705904Z Artifact python-test-evidence successfully finalized. Artifact ID 11570120050 +2026-10-08T18:04:44.8706746Z Artifact python-test-evidence has been successfully uploaded! Final size is 1600361 bytes. Artifact ID is 11570120050 +2026-10-08T18:04:44.8713880Z Artifact download URL: https://github.com/Jacob-Met/CaptureSuite/actions/runs/37811934426/artifacts/11570120050 +2026-10-08T18:04:44.8990557Z Post job cleanup. +2026-10-08T18:04:45.0307404Z [command]"C:\Program Files\Git\bin\git.exe" version +2026-10-08T18:04:45.0528684Z git version 2.56.0.windows.1 +2026-10-08T18:04:45.0571349Z Temporarily overriding HOME='D:\a\_temp\3738bbf6-cf81-467d-808f-9d097bb790b2' before making global git config changes +2026-10-08T18:04:45.0571996Z Adding repository directory to the temporary git global config as a safe directory +2026-10-08T18:04:45.0580047Z [command]"C:\Program Files\Git\bin\git.exe" config --global --add safe.directory D:\a\CaptureSuite\CaptureSuite +2026-10-08T18:04:45.0813086Z [command]"C:\Program Files\Git\bin\git.exe" config --local --name-only --get-regexp core\.sshCommand +2026-10-08T18:04:45.1043443Z [command]"C:\Program Files\Git\bin\git.exe" submodule foreach --recursive "sh -c \"git config --local --name-only --get-regexp 'core\.sshCommand' && git config --local --unset-all 'core.sshCommand' || :\"" +2026-10-08T18:04:45.5388330Z [command]"C:\Program Files\Git\bin\git.exe" config --local --name-only --get-regexp http\.https\:\/\/github\.com\/\.extraheader +2026-10-08T18:04:45.5592511Z http.https://github.com/.extraheader +2026-10-08T18:04:45.5619040Z [command]"C:\Program Files\Git\bin\git.exe" config --local --unset-all http.https://github.com/.extraheader +2026-10-08T18:04:45.5844475Z [command]"C:\Program Files\Git\bin\git.exe" submodule foreach --recursive "sh -c \"git config --local --name-only --get-regexp 'http\.https\:\/\/github\.com\/\.extraheader' && git config --local --unset-all 'http.https://github.com/.extraheader' || :\"" +2026-10-08T18:04:45.9485421Z [command]"C:\Program Files\Git\bin\git.exe" config --local --name-only --get-regexp ^includeIf\.gitdir: +2026-10-08T18:04:45.9730943Z [command]"C:\Program Files\Git\bin\git.exe" submodule foreach --recursive "git config --local --show-origin --name-only --get-regexp remote.origin.url" +2026-10-08T18:04:46.3650177Z Cleaning up orphan processes +2026-10-08T18:04:46.3948806Z Terminate orphan process: pid (4748) (vctip) +2026-10-08T18:04:46.4003616Z Terminate orphan process: pid (5164) (MSBuild) +2026-10-08T18:04:46.4115286Z Terminate orphan process: pid (564) (conhost) +2026-10-08T18:04:46.4188897Z ##[warning]Node.js 20 is deprecated. The following actions target Node.js 20 but are being forced to run on Node.js 24: actions/checkout@v4, actions/setup-python@v5. For more information see: https://github.blog/changelog/2025-09-19-deprecation-of-node-20-on-github-actions-runners/ diff --git a/docs/receiving/analysis-workspace-composition-401c5d17da79/MANIFEST.json b/docs/receiving/analysis-workspace-composition-401c5d17da79/MANIFEST.json new file mode 100644 index 00000000..86611130 --- /dev/null +++ b/docs/receiving/analysis-workspace-composition-401c5d17da79/MANIFEST.json @@ -0,0 +1,83 @@ +{ + "runtime": "facb4af1d9277d88c233a54520b33d3c79cee174", + "runtime_tree": "09b512fc4a7ae7cc6098f4fc82d40667aa2e748f", + "parents": [ + "a2c89957c2cfe6fd5347d4ac317982449d3baa3a", + "c2e1d9c176ec058218e59e0cc8db07f62db1fd98", + "837fa1fbf2c5ad471cbb3924c212fc08d0e0f0ed" + ], + "tested_head": "5b693a54f3323c6c7604f6ecd2feb6cf9c6040b1", + "tested_tree": "31ad49114bffb0ff6d4a0b419e632f8e15cd2cb9", + "checks": 21, + "test_sha256": "418df81218407151318f17ab3e1da8d3b7eacc0e8664ed7cfe1dc3daf6732476", + "files": { + "README.md": { + "sha256": "07f6549eb51d0dc1fb5c991633f1c9f97953e26a80433229e42bcbccaf8032ca", + "bytes": 4202 + }, + "RUNTIME-CANDIDATE.json": { + "sha256": "8090e42bc1457ec3dbd1095db07ebb683eb5880135744abd258358b1cfb3a2f3", + "bytes": 51170 + }, + "TEST-CANDIDATE.json": { + "sha256": "c6443602f53091e28224f9a85dd9692481f0fc5178702c0be9c717e9b359f134", + "bytes": 37002 + }, + "composed-history-gallery.png": { + "sha256": "04130f67c888849466fdc25f18260648c62fb339d229eb0ff46ad11707a19a0a", + "bytes": 281310 + }, + "composition-review.json": { + "sha256": "329b4f5fa20251ff31e2458065c02ddfd01a6ccd2c9e75f6785691b5ea25bf88", + "bytes": 10391 + }, + "fixture-manifest.json": { + "sha256": "7fc6f8c2d7718562a9e0625b0bbf8ffb891688c4e4e75f12fe4c474ca8d62740", + "bytes": 13878 + }, + "junit.xml": { + "sha256": "7c348019fc742475d8bfb24722e57b4548d48ed8b08aeda513a4f6c4c0115b7b", + "bytes": 408 + }, + "native-runtime-probe.json": { + "sha256": "ac81e84bfde112b303c3bed6f7964a73eaf473ed5bd06c5221f640408265956a", + "bytes": 621 + }, + "process-completion.json": { + "sha256": "d2199fc855888a262f557418a0ba0cdcb3febc912d39a086a55db76d9a42c1dc", + "bytes": 216 + }, + "process-start.json": { + "sha256": "d70ac67599f8f07c670c73a934df5c6072d7586d5e943c817cf629a4ac6aac13", + "bytes": 613 + }, + "qualify-v1.py.txt": { + "sha256": "a98d50ae985c5da85aa00ef3c631d99d0a516ef79f14c6052b38b61dc1db9f2f", + "bytes": 2878 + }, + "real-mcap-fixtures.tar.gz": { + "sha256": "097d9cc548e94fce29b76d26bffb461138dc061d20db1a13e60416efa7412a9f", + "bytes": 301329 + }, + "receipt.json": { + "sha256": "57841ef966130e011b6c50ba715d01b4fb46dbd4d3032ecd9e40c8ec8a461881", + "bytes": 4298 + }, + "stderr.log": { + "sha256": "146a7f2a3b7922bbe193f123dcd79dd55f6b2e5fba6f944b628e08469479cd8f", + "bytes": 400 + }, + "stdout.log": { + "sha256": "9cf2ff1ac21ae90d8b7406ad2058d18c2e142033652f526e2078f940d7abe908", + "bytes": 871 + }, + "test-authored.json": { + "sha256": "fbca570292a9efa9e41dd39043138e16f03406e6da39ea947b164bfd3f335bf3", + "bytes": 297 + }, + "visual-review.json": { + "sha256": "d80725716cb1b1f9bd58541e7f2130f0d98f2d0e1bd43498429c6763985bdbe0", + "bytes": 533 + } + } +} diff --git a/docs/receiving/analysis-workspace-composition-401c5d17da79/README.md b/docs/receiving/analysis-workspace-composition-401c5d17da79/README.md new file mode 100644 index 00000000..33b24992 --- /dev/null +++ b/docs/receiving/analysis-workspace-composition-401c5d17da79/README.md @@ -0,0 +1,40 @@ +# Current analysis-workspace source composition + +Combines the saved analysis history in PR71 and recursive figure gallery in PR80 with current main's source picker and saved-parameter comparison. This receiving adds one maintained Qt integration test and exact new evidence. It does not copy or relabel earlier CI evidence. + +## Preserved source ancestry + +The runtime merge facb4af1d9277d88c233a54520b33d3c79cee174 has tree 09b512fc4a7ae7cc6098f4fc82d40667aa2e748f and three genuine parents: + +- main a2c89957c2cfe6fd5347d4ac317982449d3baa3a +- PR71 c2e1d9c176ec058218e59e0cc8db07f62db1fd98 +- PR80 837fa1fbf2c5ad471cbb3924c212fc08d0e0f0ed + +Runtime merges were automatic and retained verbatim. Only PROGRESS needed resolution: retain the complete current main document, then both exact original owned entries. The composition preserves the source-picker validation and immutable worker snapshot, the history busy-until-cleanup predicate, comparison clear/load lifetime, contained recursive gallery, Windows-capable link tests, original history tests, and the 600-second supported CI runner inherited from PR71. + +Receiving-only child 5b693a54f3323c6c7604f6ecd2feb6cf9c6040b1, tree 31ad49114bffb0ff6d4a0b419e632f8e15cd2cb9, adds only tests/ui/test_analysis_workspace_composition.py. This evidence successor changes no application or test byte. + +## Exact native receiving + +The single maintained test passed all 21 recorded outcomes on the existing native Python 3.12.15 / PySide6 6.12.0 environment. Pytest passed in 46.01 seconds; the complete native process exited 0 in 54.87 seconds. Every materialized source byte remained unchanged. + +It generates two actual source-filtered MCAP analysis jobs, opens a retained job through the history controls, and opens the unchanged parameter inspector. It then launches a real source-filtered features QThread, holding only the return of the already-written actual result. Changing the future source choice does not change the worker snapshot or release busy history controls. Switching packages clears history, gallery and parameter comparison; late completion stays unbound until explicitly reopened in the original package. + +The same journey compares actual saved source parameters, replaces the loaded job and clears its previous comparison dialog, verifies both nested figure path identities and original image pixels, and switches packages again. Saved/raw bytes remain exact and no view action launches another worker. Native event-loop waits settle the real QThread; the receiver does not replace a handler, result, image or output format. + +The retained stderr contains eight standard offscreen propagateSizeHints messages. Pytest reports two existing protobuf metaclass deprecations. There is no failure dialog or Qt worker failure. + +## Visual limit and qualification scope + +The actual frame shows the combined controls, both channel tabs, linked plots and comparison action. Several long output rows overlap in this immediate frame. This is recorded as a visual observation, not full-pane readability acceptance or proof of a new regression; the runtime was kept frozen. + +This is native Linux qualification of the exact composed workspace, not a new Windows, capture-device, full-suite or deployment claim. Earlier Windows/source results retain their earlier heads. The proposed branch inherits the 600-second runner so supported CI can qualify the current combined source. + +## Files and replay + +MANIFEST.json pins the exact new evidence and fixture bytes. real-mcap-fixtures.tar.gz retains only the new receiver's private generated packages/state. The tested method is maintained in tests/ui; its unchanged runner is retained as qualify-v1.py.txt with actual absolute source/runtime paths. Historical source/evidence stays in the three original parent histories. + +From an installed supported checkout, run only the new boundary with: +python -m pytest tests/ui/test_analysis_workspace_composition.py -q -s -p no:cacheprovider + +The test defaults to its own pytest temporary directory. CAPTURE_ANALYSIS_COMPOSITION_EVIDENCE optionally selects an evidence output directory. No dependency install or historical suite replay was performed during this receiving. diff --git a/docs/receiving/analysis-workspace-composition-401c5d17da79/RUNTIME-CANDIDATE.json b/docs/receiving/analysis-workspace-composition-401c5d17da79/RUNTIME-CANDIDATE.json new file mode 100644 index 00000000..4512adab --- /dev/null +++ b/docs/receiving/analysis-workspace-composition-401c5d17da79/RUNTIME-CANDIDATE.json @@ -0,0 +1,1208 @@ +{ + "head": "facb4af1d9277d88c233a54520b33d3c79cee174", + "tree": "09b512fc4a7ae7cc6098f4fc82d40667aa2e748f", + "parents": [ + "a2c89957c2cfe6fd5347d4ac317982449d3baa3a", + "c2e1d9c176ec058218e59e0cc8db07f62db1fd98", + "837fa1fbf2c5ad471cbb3924c212fc08d0e0f0ed" + ], + "resolution": "Runtime merges were automatic and preserved verbatim; only PROGRESS required retaining current document plus two exact authored additions.", + "source_pins": { + "screen": { + "path": "desktop/capture_desktop/screen_analysis.py", + "sha256": "7750ae0f5658cced9fca801d815bd530b43f19d1b37d7f775b66db681f2ebc90", + "blob": "8db154b667c7c5314e6d1a4d626b1d772f0a4823" + }, + "gallery": { + "path": "desktop/capture_desktop/widgets_analysis_plots.py", + "sha256": "5583bab90fe6c317ed063bb86f95258a60bb976f953e34db09a6b5e07461f1f0", + "blob": "263d65c8e97a746fdccded89293e223bed0a95f5" + }, + "runner": { + "path": "tools/run_ci_tests.py", + "sha256": "fa700e42e15cbec944f3571d40a44df23b8fcc2c13479ec86e39597c6cfb091c", + "blob": "ab1175fbbb318b23c6545eea1a49666633cf77bb" + } + }, + "progress_additions": { + "history": { + "sha256": "dd460d758f165990b03dd71d220aa47d0cd625b5f6da484805f55daa359303f8", + "bytes": 2591 + }, + "gallery": { + "sha256": "4c695f2c2670bcc7bff8d468411c0706064409ec2568d7607af1947648822ba9", + "bytes": 1401 + } + }, + "materialized": { + "pyproject.toml": { + "sha256": "0cb8de1ab3dfbfed84ff16b35f3c89c6440180183ee5851d5d80da83622e53d0", + "bytes": 1233 + }, + "tools/run_ci_tests.py": { + "sha256": "fa700e42e15cbec944f3571d40a44df23b8fcc2c13479ec86e39597c6cfb091c", + "bytes": 7416 + }, + "tools/check_licenses.py": { + "sha256": "c6d90c9175d2db1de0f3426128c5fb511afc35942156c9bd2b7e692afc401463", + "bytes": 5880 + }, + "tests/conftest.py": { + "sha256": "f669618fad17e906c91df7a1e9393fc7a54f458c6d62a4385436ba2622beca0e", + "bytes": 1773 + }, + "schemas/NOTICE": { + "sha256": "78581010fab3d185adf35edb8c7459bbabcb6efa5327d893307dfcddf1f1fef0", + "bytes": 115 + }, + "schemas/LICENSE": { + "sha256": "cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30", + "bytes": 11358 + }, + "desktop/pyproject.toml": { + "sha256": "3646f83dcc0764b3c8cb198b98b03201dc47808bb80bfec4837e329e47bd012f", + "bytes": 552 + }, + "desktop/capture_desktop/widgets_session_timeline.py": { + "sha256": "7671ad4b632fd83498ad0c02f9030e4f46a0ef2d99a3764c13de3996e3c2ade4", + "bytes": 10010 + }, + "desktop/capture_desktop/widgets_session_header.py": { + "sha256": "b9e11a7e3709283ed37bacbe96836d6720467f2bdcb934d75491df5dc02927fa", + "bytes": 5749 + }, + "desktop/capture_desktop/widgets_radar_array.py": { + "sha256": "be08874ade0b4d9197ea85cb6ae3b30db75273ddd3c426faaaf28b4f796653a8", + "bytes": 2965 + }, + "desktop/capture_desktop/widgets_preview.py": { + "sha256": "78d79c9af67f7e0cbcee3a3a693a22e72753256ca465bab7edb9c2037822dec4", + "bytes": 27254 + }, + "desktop/capture_desktop/widgets_modality_expanded.py": { + "sha256": "12db25b37e8b2724e5eaabdcb1810aa979633885097b6ec11c33d98a46a83a70", + "bytes": 8566 + }, + "desktop/capture_desktop/widgets_mappings.py": { + "sha256": "89808d37cb0fce476665a24766963c7a509f5b1802d05dedbf9ca44351081f4b", + "bytes": 3658 + }, + "desktop/capture_desktop/widgets_figure_export.py": { + "sha256": "a918adbb80e73c220e46e0923fa6ff86a7c2ab336c2832aacbc39a2821df72d6", + "bytes": 13246 + }, + "desktop/capture_desktop/widgets_analysis_sources.py": { + "sha256": "be4c05cbf9b0c801176668933d3bb60204f5c94ce8fea3f85da176575d42c99f", + "bytes": 7995 + }, + "desktop/capture_desktop/widgets_analysis_scope.py": { + "sha256": "3f58ffba9125d0ce88fa99317f6aa593fe8aeb4b0dc1d799c95c9c04fb0b73ff", + "bytes": 10391 + }, + "desktop/capture_desktop/widgets_analysis_plots.py": { + "sha256": "5583bab90fe6c317ed063bb86f95258a60bb976f953e34db09a6b5e07461f1f0", + "bytes": 11279 + }, + "desktop/capture_desktop/widgets_analysis_jobs.py": { + "sha256": "5cdea6045456e61a58b5525dd224a22a140962d31d2adc5b0102168444468f98", + "bytes": 6304 + }, + "desktop/capture_desktop/widgets_analysis_history.py": { + "sha256": "a3b77c87483c1412b50de7ddde1498f6bfd3968002fc3ac3bfa474a2477d9bc4", + "bytes": 8458 + }, + "desktop/capture_desktop/widgets_analysis_comparison.py": { + "sha256": "bd0adca471711350b45702bf7c625b28c348321be43c6eaecd047da33304fc1d", + "bytes": 14400 + }, + "desktop/capture_desktop/theme.py": { + "sha256": "c77f24e1afeb06400385bd0d535800f13dc15d972891e1ff8af504cbe5c818f3", + "bytes": 12072 + }, + "desktop/capture_desktop/state.py": { + "sha256": "97fc98498f4553fc7f052d0dc4db992cf2fc136ba7c4405cd275bd156c74e314", + "bytes": 17906 + }, + "desktop/capture_desktop/screen_setup.py": { + "sha256": "01eb01ffffe835fcf5d26120d508800cc3cdac1e91ffaa3d0d2fa669c6326182", + "bytes": 11452 + }, + "desktop/capture_desktop/screen_settings.py": { + "sha256": "519436946827fac53d0be68270c2929bd1ce615a58b2372e9e3fc10619a7ba6e", + "bytes": 4581 + }, + "desktop/capture_desktop/screen_review.py": { + "sha256": "e5aff59de4b194123ca4c4518b34e7b6103326fbd6b0280e2122d984d01072ec", + "bytes": 7003 + }, + "desktop/capture_desktop/screen_presets.py": { + "sha256": "b62d6f4bef6c1f0fc04b9eaf6a8afd1b2eeb17f6ce14946a06b0495ba33d402c", + "bytes": 5230 + }, + "desktop/capture_desktop/screen_capture.py": { + "sha256": "4e101ddeeaed7f7f2b4ec2ab2e4b1f4f55ebb86f73b394d25cfd2b904cd2572e", + "bytes": 34181 + }, + "desktop/capture_desktop/screen_analysis.py": { + "sha256": "7750ae0f5658cced9fca801d815bd530b43f19d1b37d7f775b66db681f2ebc90", + "bytes": 20255 + }, + "desktop/capture_desktop/schema_form.py": { + "sha256": "7d825b5dc7566d630f31775df6fcc9def1e916eaff5be17a552bf89f28b3418b", + "bytes": 12206 + }, + "desktop/capture_desktop/persistence.py": { + "sha256": "cdb1fa0094fec72543d5051435850e51d78d79d4bde8d5c83520fa072a2c74c4", + "bytes": 3379 + }, + "desktop/capture_desktop/main.py": { + "sha256": "e61c29a1925f8d85b24438f087dec360a4481a32e0dc2bd8ed8feb6629026e84", + "bytes": 1059 + }, + "desktop/capture_desktop/export_wizard.py": { + "sha256": "fb957ff184109bcb4e379dde30414048e855c93ec390f9b50c7ab603c3cd4e30", + "bytes": 6734 + }, + "desktop/capture_desktop/daemon_link.py": { + "sha256": "ab76628bbe0231c7e5e4d570f2abed01100dddd6a24bb62020b670a6b62427dd", + "bytes": 10899 + }, + "desktop/capture_desktop/app.py": { + "sha256": "e33cf4446d4edfda3634cb5445aa9456d2f243a8b710c0d9c6497b2ec28078b2", + "bytes": 47945 + }, + "desktop/capture_desktop/analysis_job_comparison.py": { + "sha256": "3fcc013cedffba87cdfdf105f80502b60bcfdca8c298e6b8feb20da2348d0966", + "bytes": 13045 + }, + "desktop/capture_desktop/analysis_history.py": { + "sha256": "2e0db8cee59ef268d3c91ea0beac7d761d83a3003862841cc9d7f1782fd3543c", + "bytes": 6375 + }, + "desktop/capture_desktop/analysis_figure_export.py": { + "sha256": "cf510ab0f9693ed6961623099be30921eb64ee1d435d00c954ef229334ffb471", + "bytes": 14037 + }, + "desktop/capture_desktop/__main__.py": { + "sha256": "8dbad73a7373565a3513ccbb613f11bffdd13a05861c3e8e07392b8d51008aa2", + "bytes": 723 + }, + "desktop/capture_desktop/__init__.py": { + "sha256": "8426c94323c4cca0879b8612345e3577d0a75f6239237a28d79d94a42004c3b5", + "bytes": 119 + }, + "libs/python/capture_worker/pyproject.toml": { + "sha256": "0cba218b59a756185fedf72fb3a3307d1d9cb9218b6189ea92972d3cec139a46", + "bytes": 487 + }, + "libs/python/capture_worker/NOTICE": { + "sha256": "2a7e69c4c7cd4e93a5cc9e9f984873a2d1276f465b91b10c71b951ebcfb2c588", + "bytes": 142 + }, + "libs/python/capture_worker/LICENSE": { + "sha256": "cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30", + "bytes": 11358 + }, + "libs/python/capture_session/pyproject.toml": { + "sha256": "3484887da96d4a2f32de8471b537d849f077b195c729ff0cc29307681e8d4895", + "bytes": 389 + }, + "libs/python/capture_protocol/pyproject.toml": { + "sha256": "61b2e33b2de2a153fb994144f532402c1b6b8ed02afb627ba0a15239e726ca71", + "bytes": 355 + }, + "libs/python/capture_protocol/NOTICE": { + "sha256": "3efb470f58c900a58deaef889527e074206274b0fd5fb0e2e62613c093064307", + "bytes": 124 + }, + "libs/python/capture_protocol/LICENSE": { + "sha256": "cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30", + "bytes": 11358 + }, + "libs/python/capture_analysis/pyproject.toml": { + "sha256": "84cd96465e48439bdd81f5fa126fea5da11ee7587b488bfaaa67a4cd8f760c75", + "bytes": 677 + }, + "libs/python/capture_analysis/capture_analysis/windows.py": { + "sha256": "5cf401b7b7d201225c966b804cfff39c3f6d59669da7e488dd68c4253a829c32", + "bytes": 5714 + }, + "libs/python/capture_analysis/capture_analysis/version.py": { + "sha256": "9e25143344b110699f68b6acdbef49576fc91c2cbda34956d7e2cb85bbbc4ae3", + "bytes": 62 + }, + "libs/python/capture_analysis/capture_analysis/types.py": { + "sha256": "e7996d02483f69265a2ef2ec0b28078c86f4f479daa53e38faf8b4a62645d02c", + "bytes": 3428 + }, + "libs/python/capture_analysis/capture_analysis/report_html.py": { + "sha256": "f2c89c7faf6e4edc265540140272396b4195eb5aed9edf05c4912aac74286f03", + "bytes": 4716 + }, + "libs/python/capture_analysis/capture_analysis/qc.py": { + "sha256": "f24e0593a3723311d41054aef40b56c4bb46d4f3ba5ef4b01afcae3a6cc4440a", + "bytes": 9187 + }, + "libs/python/capture_analysis/capture_analysis/pipeline.py": { + "sha256": "e8c0152040ba5b5f3f37ac53fb5188bac9dd9aaf0d5816d6a718be505c20898c", + "bytes": 5262 + }, + "libs/python/capture_analysis/capture_analysis/jobs.py": { + "sha256": "fa7686685f1a680eb2982191fbd03b3986487e638e95088b56de32d4c183d568", + "bytes": 19577 + }, + "libs/python/capture_analysis/capture_analysis/grids.py": { + "sha256": "936c5404783145f7a2bc4c13df22d3b85612bcb227115bba74f0b78a11c0c483", + "bytes": 1007 + }, + "libs/python/capture_analysis/capture_analysis/discover.py": { + "sha256": "344ee5d7cb0f5e95ac7524a0c1141b0a293bb9445e2bd4789c6736f39cfcb90d", + "bytes": 4023 + }, + "libs/python/capture_analysis/capture_analysis/__init__.py": { + "sha256": "14cfe6dccd33a0bda74fac3c9339e1a37a3538b2110a8ae6e307801b776eb43a", + "bytes": 497 + }, + "libs/python/capture_analysis/capture_analysis/pose/job.py": { + "sha256": "1f4c44f443c07e22e8c9ca877232c6780c4b1da7834d5565b82cf547b2f4c439", + "bytes": 6262 + }, + "libs/python/capture_analysis/capture_analysis/pose/__init__.py": { + "sha256": "d58a03cae86259b2cb0ecd0a5ce2347c6824f14cfea6871c94d76acc3541a380", + "bytes": 156 + }, + "libs/python/capture_analysis/capture_analysis/plugins/registry.py": { + "sha256": "33a4d07600db8b116fbd46b67492f62129df513df5b66a2c455dced0b2a9dc69", + "bytes": 5389 + }, + "libs/python/capture_analysis/capture_analysis/plugins/numeric.py": { + "sha256": "75b55cb453095ad5470ce2532b65d3dce771e6a2f8ad1e46a538b4291fa4cf93", + "bytes": 3390 + }, + "libs/python/capture_analysis/capture_analysis/plugins/manifest.yaml": { + "sha256": "1efe3ee2d9eeeeac03c2c03c582edf0119c9abd6d214dfdca3d827fa10a5c048", + "bytes": 3876 + }, + "libs/python/capture_analysis/capture_analysis/plugins/handlers.py": { + "sha256": "9be2e1820529b94e54d06790d53aa94cf658f982efb4063c6b64f9d07acc4b2e", + "bytes": 10646 + }, + "libs/python/capture_analysis/capture_analysis/plugins/dummy.py": { + "sha256": "facf059d247bca44f2697383e12cc1296b1d1d12bede1196f4a52a1352d60495", + "bytes": 1618 + }, + "libs/python/capture_analysis/capture_analysis/plugins/__init__.py": { + "sha256": "c511d4b9cd1cda042b781b06fbb02d2d99004de214735d6daeb459d6e41381fe", + "bytes": 225 + }, + "libs/python/capture_analysis/capture_analysis/plots/sync_dashboard.py": { + "sha256": "6f9e0c64193688eb841565729b9d1e9a64136779e892419acabdc81591afd3d5", + "bytes": 1149 + }, + "libs/python/capture_analysis/capture_analysis/plots/style.py": { + "sha256": "231e7b1c998f4349d5859295007235ffd41848f12fbb7819193bec9630cd3942", + "bytes": 1249 + }, + "libs/python/capture_analysis/capture_analysis/plots/modality.py": { + "sha256": "bc3aa15ee79d50280a6c9d6aa144fe0519f85dd2c74a0cfa99323f7d57ecd28d", + "bytes": 2419 + }, + "libs/python/capture_analysis/capture_analysis/ml_bundle/job.py": { + "sha256": "38b7161f081ef038e6ce464dd3b82ca2b49f775ad8988010243743274d6fc5e6", + "bytes": 10005 + }, + "libs/python/capture_analysis/capture_analysis/ml_bundle/__init__.py": { + "sha256": "e785a2e3bf65852018d811b38ecbaf6ff9c479648025789145218809dd50d8a1", + "bytes": 179 + }, + "libs/python/capture_analysis/capture_analysis/loaders/video.py": { + "sha256": "3c3e873ab641904a39ca649dac39072f11948031d068cc21ee459e996d1fc185", + "bytes": 2200 + }, + "libs/python/capture_analysis/capture_analysis/loaders/radar_frame.py": { + "sha256": "d071f9d95b371798974698fd0caa1fc4c865a85fb772232fd43e7227b15fad2b", + "bytes": 1828 + }, + "libs/python/capture_analysis/capture_analysis/loaders/radar_doppler.py": { + "sha256": "4942d08eb47229839e339ce7f2f8a64aee7e5fab44bac77029fcd7a3e3e490c1", + "bytes": 1539 + }, + "libs/python/capture_analysis/capture_analysis/loaders/numeric_batch.py": { + "sha256": "7c84c0425c1b9b821df711f4c40ea89ac13f267dbe6472922eb41a9263e4835c", + "bytes": 7139 + }, + "libs/python/capture_analysis/capture_analysis/loaders/mcap_iter.py": { + "sha256": "03a418e7689840e378665aac92c42769dd14ba2c88a821a5cbf0cee80766540c", + "bytes": 1196 + }, + "libs/python/capture_analysis/capture_analysis/loaders/imu.py": { + "sha256": "5ea4747145bf5588974dfd72c834766436c5a2bc0d58d34ace0f8ef403b310d6", + "bytes": 2773 + }, + "libs/python/capture_analysis/capture_analysis/loaders/emg.py": { + "sha256": "86eb7114be689cdbd2edd76affa2994e7278714916692a35381abd02ba9d599a", + "bytes": 3089 + }, + "libs/python/capture_analysis/capture_analysis/loaders/base.py": { + "sha256": "696093b31f22d2bef32fc2962c7a11249a590a0b4d776c40cef4edcbc1e48a97", + "bytes": 2461 + }, + "libs/python/capture_analysis/capture_analysis/loaders/__init__.py": { + "sha256": "2d51c509baf3c0b5c33360637d12e5ce3c7507a859e4f37030f2c3d711ef0b3d", + "bytes": 361 + }, + "libs/python/capture_analysis/capture_analysis/kinematics/registry.py": { + "sha256": "1e53fb9da4c6a2743bc1a3f0e687d94599cf995d33f2a2555e0ce5ebc3966d48", + "bytes": 1155 + }, + "libs/python/capture_analysis/capture_analysis/kinematics/job.py": { + "sha256": "d676e84f54aa1ae2b0f998c2cb37c4e02541c1fd0e3464e38e9865c0049a7239", + "bytes": 4523 + }, + "libs/python/capture_analysis/capture_analysis/kinematics/compute.py": { + "sha256": "59bdcde630edd97833349d59703dd2c3bb5ce06981bc8b311668560cbfb6b2be", + "bytes": 6993 + }, + "libs/python/capture_analysis/capture_analysis/kinematics/__init__.py": { + "sha256": "50a0f7fd39648abf269fc549d2c17eb48b1dc9add10ebdb76edc1935d6f80160", + "bytes": 178 + }, + "libs/python/capture_analysis/capture_analysis/features/video_qc.py": { + "sha256": "0e25c50e01fc2da47bc7b510d68ba3e72aba33d3e1c79c57b727f5c55c723e27", + "bytes": 1766 + }, + "libs/python/capture_analysis/capture_analysis/features/radar_frame.py": { + "sha256": "f85c5fe5e2db68606f68e36a42a0c8f323086f0b1e7f233c0ddefa24cdccb443", + "bytes": 3323 + }, + "libs/python/capture_analysis/capture_analysis/features/radar_doppler.py": { + "sha256": "cffc0ecbb8053fbc2244850c1927469366f4ae93b5439e4d194de2065877fa5c", + "bytes": 2289 + }, + "libs/python/capture_analysis/capture_analysis/features/numeric_batch.py": { + "sha256": "ecdeb88ca4dd093b973294a53954e9fa0e5d6b4b908225a52d097ef70c7d2154", + "bytes": 4030 + }, + "libs/python/capture_analysis/capture_analysis/features/io.py": { + "sha256": "c677d209292cca790ccdf1a64ba834f71a078ccce31ea57452e67ece358822ca", + "bytes": 1409 + }, + "libs/python/capture_analysis/capture_analysis/features/imu.py": { + "sha256": "246bfd1cc3ce72afa0680537062b6795e22b8a06ba6301503d7489a4440c6849", + "bytes": 2605 + }, + "libs/python/capture_analysis/capture_analysis/features/emg.py": { + "sha256": "11f8f8350464b7c7c079353ca649b4c4aad2580ef8d355fe741c025c262b168e", + "bytes": 3072 + }, + "libs/python/capture_analysis/capture_analysis/features/__init__.py": { + "sha256": "3cdd6c626b6da12b8df56d8ddf35fca27c0a744865965ec01dd89d47da476fa1", + "bytes": 66 + }, + "libs/python/capture_analysis/capture_analysis/eval/predictions.py": { + "sha256": "decff22c1e2e661a3ce21679db68b667ea44fa5b18df8501204d7d23161cc906", + "bytes": 18051 + }, + "libs/python/capture_analysis/capture_analysis/eval/job.py": { + "sha256": "0af5556304cfae0be9f40929fbe4eeba6cf8b1453f94e9ba475d66acda8bc913", + "bytes": 4342 + }, + "libs/python/capture_analysis/capture_analysis/eval/__init__.py": { + "sha256": "54661df9ed7d7e0d4b1c2ab5941f107ceb608e4fdfaff810014ef5fad1431fe1", + "bytes": 154 + }, + "libs/python/capture_protocol/capture_protocol/structured_log.py": { + "sha256": "3d7883833286ecc004248294badcc0c66e44a57ecb7844ef281828d797b3c4fc", + "bytes": 4657 + }, + "libs/python/capture_protocol/capture_protocol/handshake.py": { + "sha256": "63f740c992edf8812f666b79f9cd866d9ea33e65e5b310a5ebda2f5ef98ac115", + "bytes": 4763 + }, + "libs/python/capture_protocol/capture_protocol/framing.py": { + "sha256": "3ff7c7284d9907a2ad516c83fab383a4151996da3f2d5a1d27e24d7c7575d92e", + "bytes": 2884 + }, + "libs/python/capture_protocol/capture_protocol/control_client.py": { + "sha256": "68de412465b2eaa04886a2bb4566aa0595c898df7d7e782b3031b8ba919db7fa", + "bytes": 20823 + }, + "libs/python/capture_protocol/capture_protocol/constants.py": { + "sha256": "7f187edf873cd13f55bc09ff7972785797eb488d74dd5befcb395fc928a71d72", + "bytes": 486 + }, + "libs/python/capture_protocol/capture_protocol/config_schema.py": { + "sha256": "00d855895faec7d674cdb8e4da1ddc687888c9e9863f91d4950d24d9fb815e6e", + "bytes": 8444 + }, + "libs/python/capture_protocol/capture_protocol/codec.py": { + "sha256": "f6c09246a7b165358835e51b99b1508e68d840f4bdbd54b5fb72db33d4912712", + "bytes": 7011 + }, + "libs/python/capture_protocol/capture_protocol/__init__.py": { + "sha256": "556f474a3d740adc03c40426acde432ab7a394b947f8268bd90eecc7832dff8a", + "bytes": 698 + }, + "libs/python/capture_protocol/capture_protocol/generated/__init__.py": { + "sha256": "1fac8216894ce1a1b5362de3b59398fbd78f005a59636aea9f074951bed5c1d7", + "bytes": 90 + }, + "libs/python/capture_protocol/capture_protocol/generated/capture/__init__.py": { + "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "bytes": 0 + }, + "libs/python/capture_protocol/capture_protocol/generated/capture/v1/worker_pb2.py": { + "sha256": "112e832172913024c6fad128a9a9559bbcd14b18de06b1f2a3161ac380258dc0", + "bytes": 11165 + }, + "libs/python/capture_protocol/capture_protocol/generated/capture/v1/storage_pb2.py": { + "sha256": "f7a7b8903af9bfc2d2a419622c86cc057aed2a898949e4261475a7ac61222474", + "bytes": 5487 + }, + "libs/python/capture_protocol/capture_protocol/generated/capture/v1/source_pb2.py": { + "sha256": "d15b443f27c910c0e809af19fed81d9c1a75f7112501df85877bf4bf9bc4f7a8", + "bytes": 8053 + }, + "libs/python/capture_protocol/capture_protocol/generated/capture/v1/project_pb2.py": { + "sha256": "983bc5715147297cdcecca343b9a450f2095fcc1e895859cc3c52a3213d933f5", + "bytes": 3355 + }, + "libs/python/capture_protocol/capture_protocol/generated/capture/v1/preview_pb2.py": { + "sha256": "c992e91b9aef0aa0ec8d595eba2f7079889264d9e4de120b623afd1d8702c695", + "bytes": 5333 + }, + "libs/python/capture_protocol/capture_protocol/generated/capture/v1/presets_pb2.py": { + "sha256": "d27336594b548f2e6e7ae212fe6de198e6e699c62a5f27752f691d7928ccb27b", + "bytes": 2066 + }, + "libs/python/capture_protocol/capture_protocol/generated/capture/v1/health_pb2.py": { + "sha256": "e1e0baa7073a9886e4d982d4f00020b490bfd46c32b1b4df129fd0477c1f5e61", + "bytes": 5898 + }, + "libs/python/capture_protocol/capture_protocol/generated/capture/v1/events_pb2.py": { + "sha256": "72951a468b0480e7fefc4fd3f9b4caac5fda0abdadf4ffcca92d4f19286429ce", + "bytes": 5480 + }, + "libs/python/capture_protocol/capture_protocol/generated/capture/v1/control_pb2.py": { + "sha256": "f2eea386aebf830ec47fa7379e6fb0493e0a199efecc7b90974bc8bb8c8b96b6", + "bytes": 20028 + }, + "libs/python/capture_protocol/capture_protocol/generated/capture/v1/common_pb2.py": { + "sha256": "6736e3b86b3c8749d34065794da1c880772ce69e2f248fdd2febd003f083bbd3", + "bytes": 9746 + }, + "libs/python/capture_protocol/capture_protocol/generated/capture/v1/arrays_pb2.py": { + "sha256": "6355750076724275e49f9a5faec383b2be92c0336ed58805a88954964bd13b86", + "bytes": 2876 + }, + "libs/python/capture_protocol/capture_protocol/generated/capture/v1/__init__.py": { + "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "bytes": 0 + }, + "libs/python/capture_protocol/capture_protocol/generated/capture/v1/data/video_timing_pb2.py": { + "sha256": "002a79858ccd2d7763769a1fe1be6a16a7f6b8727d15f952d191bcd2240ba5ef", + "bytes": 1722 + }, + "libs/python/capture_protocol/capture_protocol/generated/capture/v1/data/radar_frame_pb2.py": { + "sha256": "995ddbbb0aa614afb15088cf039c741421c33ea3e3e963ef1a7361b24754b862", + "bytes": 1729 + }, + "libs/python/capture_protocol/capture_protocol/generated/capture/v1/data/radar_doppler_pb2.py": { + "sha256": "d1b85358aba0c2f4fc1745218463e9951224322604b18b068a2195359dcf790e", + "bytes": 1773 + }, + "libs/python/capture_protocol/capture_protocol/generated/capture/v1/data/numeric_batch_pb2.py": { + "sha256": "a087cc019b9849f4ef47bcdf4c789a7da90d443240b7bef97c832bb23c1d4e24", + "bytes": 1454 + }, + "libs/python/capture_protocol/capture_protocol/generated/capture/v1/data/imu_frame_pb2.py": { + "sha256": "4a2048d2a737362bf26b99166e95c457d1492fcfba8848c894fe4d2748ff9f51", + "bytes": 2222 + }, + "libs/python/capture_protocol/capture_protocol/generated/capture/v1/data/emg_batch_pb2.py": { + "sha256": "1db5ef51143a546072e34cc7be7b263db996fa5f4d0d71606b230cb75b531a14", + "bytes": 1624 + }, + "libs/python/capture_protocol/capture_protocol/generated/capture/v1/data/__init__.py": { + "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "bytes": 0 + }, + "libs/python/capture_session/capture_session/settings_store.py": { + "sha256": "7719524a1f106cc54befcd21088810f9ec28f0160c8e88f60c374e1545fdb98d", + "bytes": 4622 + }, + "libs/python/capture_session/capture_session/registry.py": { + "sha256": "809b26ce8d8efc0559a3854cf85ea74b4e486fcd77d253ebfa76bade64b0a8d1", + "bytes": 13989 + }, + "libs/python/capture_session/capture_session/package_reader.py": { + "sha256": "9a1d9e6e7d24341a083cee602af9538413e948f3369b22660e484356e3d34eb1", + "bytes": 6331 + }, + "libs/python/capture_session/capture_session/app_paths.py": { + "sha256": "363e4522240e2356cac7492589cb207a798bc1af6031139bd1fa94890f1c4bfd", + "bytes": 561 + }, + "libs/python/capture_session/capture_session/__init__.py": { + "sha256": "da530f86c0d1d584862868ddba9f7087ccf5dfbddd64dd1e577337ecfd776419", + "bytes": 2412 + }, + "libs/python/capture_worker/capture_worker/writer.py": { + "sha256": "b9e3b21ac26f2160da582a3f566a278dc4088c5a8b121d9b4e74f8d8c16cf96f", + "bytes": 6196 + }, + "libs/python/capture_worker/capture_worker/worker.py": { + "sha256": "19a0dfd16a65479de884d4359a3d65f1bc127d8a6d4b44b93c6251757510de68", + "bytes": 23439 + }, + "libs/python/capture_worker/capture_worker/transport.py": { + "sha256": "020414c74bd08ec510e88da8c2f8b9ec5091a19cb585b4c54d2656b4bf300d35", + "bytes": 5033 + }, + "libs/python/capture_worker/capture_worker/preview.py": { + "sha256": "38b483dc06c9215b73e4c56c222fe563957180a5be58761a2c6dd4ea200b8e31", + "bytes": 3202 + }, + "libs/python/capture_worker/capture_worker/cli.py": { + "sha256": "8a16c4cae0ffd11d4f9cd5d168f6abf1c6f9a4b5100e8edd18a29ce7d44d3f03", + "bytes": 1818 + }, + "libs/python/capture_worker/capture_worker/__main__.py": { + "sha256": "216422b76731bc985daa5fb0efe55a9d5ce600aa7e6081fa3df0c03afb6a893e", + "bytes": 150 + }, + "libs/python/capture_worker/capture_worker/__init__.py": { + "sha256": "c7ba88e956df8460002637eb3d8678a4c7217e680a388f833a22f073dc80f8fd", + "bytes": 503 + }, + "schemas/proto/README.md": { + "sha256": "1411f195c911b26e016d478428225b174035357e040c222946fe486185fa32e4", + "bytes": 337 + }, + "schemas/plugin/plugin_manifest.schema.json": { + "sha256": "3fa7950584bc391ccd4e67135725c6132f812350d1351e31b028ee9322b640a0", + "bytes": 3250 + }, + "schemas/ml_bundle/ml_bundle.manifest.schema.json": { + "sha256": "fb099856b1644cd71a243749dbad0b6b79e10cf678af505b39ced3517f2d6ecb", + "bytes": 3846 + }, + "schemas/kinematics/kinematics_columns.schema.json": { + "sha256": "47ff0aac138c87f2ca74e58b43c9e7b89fceb94ce68ff9bb19f13e3c25f58a83", + "bytes": 1216 + }, + "schemas/kinematics/kinematics_columns.registry.json": { + "sha256": "86e35c623b9769a019695923047cda2437c4ace6e8cc05b4b6a0009a91650693", + "bytes": 5195 + }, + "schemas/eval/predictions.schema.json": { + "sha256": "dc7de69d50d94876de42aa6671b4f922b1fa397d72418347559594ecea5fb57c", + "bytes": 1692 + }, + "schemas/activity_catalog/activity_catalog.schema.json": { + "sha256": "fa443d547e34f4bc1f4733cc03558af4516692462d9c8a11b82e39602171a8b1", + "bytes": 2125 + }, + "schemas/activity_catalog/1.json": { + "sha256": "cdba686c34c6ae8da8325eb62745856382468175558b20f97b09ce9a6c27ce18", + "bytes": 7859 + }, + "schemas/plugin/examples/sim.builtin.plugin.json": { + "sha256": "a4e3d85cbd32ee154a91952868726ac26253f0f4d652f7b60ba733b1f9f9a5de", + "bytes": 317 + }, + "schemas/plugin/examples/radar.ifx.plugin.json": { + "sha256": "f9041e61f25c798ae6ac433cfa82fa7f514504fd24c88146beb88410bf34dc9f", + "bytes": 652 + }, + "schemas/plugin/examples/camera.gstreamer.plugin.json": { + "sha256": "6f921746e815083b55f5d81d10c660e9b448ff315b48a2082090b34b350eae03", + "bytes": 674 + }, + "schemas/proto/capture/v1/worker.proto": { + "sha256": "8ae3774630330103a86137d3d7bea09f35997470d66b2829489089f4a3f7ff6d", + "bytes": 3747 + }, + "schemas/proto/capture/v1/storage.proto": { + "sha256": "4b7ac9342b0497428708299075e615698dc62846e22d0a76f7213841aec51cf1", + "bytes": 1894 + }, + "schemas/proto/capture/v1/source.proto": { + "sha256": "5f353365bbff5fec722cf3dafc8585afeded5153ce6cd9abcb29326cc9982425", + "bytes": 3092 + }, + "schemas/proto/capture/v1/project.proto": { + "sha256": "5ba4dfc4158458707b28aee6cf0a01e86798c156ae0499414be314906589c555", + "bytes": 684 + }, + "schemas/proto/capture/v1/preview.proto": { + "sha256": "ac74cd566c62b517298a228f1487103e72b6fe959eece920bc3951dc3e927c5b", + "bytes": 2688 + }, + "schemas/proto/capture/v1/presets.proto": { + "sha256": "55adc5f64d26df5b03bed14505a213fbb3ed6925861156b0cfa6e525dd67b461", + "bytes": 574 + }, + "schemas/proto/capture/v1/health.proto": { + "sha256": "4888b25c2b527b3161efa391b009eabb9ead1fd568c8ce25ffaa96f235e9bbce", + "bytes": 2679 + }, + "schemas/proto/capture/v1/events.proto": { + "sha256": "ac91ca3d1c2806342ebc5c63512b78d1e2bd1c0c7386b3bbe1f78d5049cc2072", + "bytes": 1909 + }, + "schemas/proto/capture/v1/control.proto": { + "sha256": "7a4b9ad274badc40e0139a7554164183a54ff511fce1ef780305d90642688d84", + "bytes": 7970 + }, + "schemas/proto/capture/v1/common.proto": { + "sha256": "a9f403a8835b0620eaedef1fdec7bfed09d3f649397b55b12900fe83c5a541d9", + "bytes": 6090 + }, + "schemas/proto/capture/v1/arrays.proto": { + "sha256": "06360f104803070dff7de92fa40401466d3a68e564dbe96aca839ec4fef7db50", + "bytes": 1151 + }, + "schemas/proto/capture/v1/data/video_timing.proto": { + "sha256": "717aff65762679bd4363c2c8df38c18047e6012816feb63b56f9e00a6e9e7514", + "bytes": 801 + }, + "schemas/proto/capture/v1/data/radar_frame.proto": { + "sha256": "844921a2bbc1732d2e3811d85d1d1863ade60346c2897dd6ef1bede3e9ac3156", + "bytes": 904 + }, + "schemas/proto/capture/v1/data/radar_doppler.proto": { + "sha256": "99d1549779e8ab294c6ed80e1341efc1cd612b2c13eef59fe51f32da7679d6f1", + "bytes": 699 + }, + "schemas/proto/capture/v1/data/numeric_batch.proto": { + "sha256": "068b62f517b057b448aec26c507b05044f1e9d25c91318657671558fcc8de07b", + "bytes": 628 + }, + "schemas/proto/capture/v1/data/imu_frame.proto": { + "sha256": "44c5b700c7e976b3c092b77ae49e21b383899d053d16f55e06b7bc59e2e38ff1", + "bytes": 651 + }, + "schemas/proto/capture/v1/data/emg_batch.proto": { + "sha256": "6eaed7210149c82877476cb391d73624b1bb25f7f4b2f822745224e79a743dc6", + "bytes": 490 + }, + "schemas/session/migrations/registry.py": { + "sha256": "bf31eb2684c62771809f8c3d11d27851c51287b926cefbe3de86eecdb7a6e5a8", + "bytes": 316 + }, + "schemas/session/jsonschema/timing_header.schema.json": { + "sha256": "a2cebf48ae8c79aecb4a42545f36cbe2f3ce1d83be6c82536e99287d7ae098dd", + "bytes": 947 + }, + "schemas/session/jsonschema/sync_anchor.schema.json": { + "sha256": "e6bf9f3d790faff1b1f07ab2bdf98ab9b19fb86e760af2b118a4d2f34c510a1f", + "bytes": 698 + }, + "schemas/session/jsonschema/stream_descriptor.schema.json": { + "sha256": "4a207f98752dc4d693861d3cb1e5a54ccf1eb18c496d47cf8f490962aedea738", + "bytes": 1480 + }, + "schemas/session/jsonschema/source_instance.schema.json": { + "sha256": "783bcf6ab4c6430048a4b90174ec80796fed11f0545b22ca5425b0ff14370a90", + "bytes": 1895 + }, + "schemas/session/jsonschema/session_manifest.schema.json": { + "sha256": "3ef72af1cc561fc2d4f3231e0cbd690c2c5fa223dd9027358bb79de0d9f954f4", + "bytes": 1439 + }, + "schemas/session/jsonschema/session_identity.schema.json": { + "sha256": "b60df9fe7759ae5df090838a4bd1cc7aafbb858d7a3afb2112cce02f2d315ca5", + "bytes": 537 + }, + "schemas/session/jsonschema/sensor_instance.schema.json": { + "sha256": "7eab69c1f5fb936310c1e0e3d55f2a8bbc4defcdb5be4474711701b91728a224", + "bytes": 634 + }, + "schemas/session/jsonschema/radar_array.schema.json": { + "sha256": "b72653f8508ef5536c392a0bbb16c9b7670c96223e015078ede13a32a6975434", + "bytes": 306 + }, + "schemas/session/jsonschema/preset_snapshot.schema.json": { + "sha256": "d6bb16cd2efefb107d1a797c8a190b0da503e00bcf6bad71bce9c1bec70db48e", + "bytes": 902 + }, + "schemas/session/jsonschema/physical_device.schema.json": { + "sha256": "d2e1dd32ac542ad0971ad6e971a6f2bdc9b78c757f46734c5ff0094338793fcb", + "bytes": 723 + }, + "schemas/session/jsonschema/logical_slot.schema.json": { + "sha256": "85a907ff10b5c3b1c78d4b83ace963e874ed6a6757efae4c3d41cd34dc57d0b9", + "bytes": 434 + }, + "schemas/session/jsonschema/integrity_manifest.schema.json": { + "sha256": "f843a9c88121db424afc9d2f4e25302cbc3b055c256fc118160a49b8e5195515", + "bytes": 487 + }, + "schemas/session/jsonschema/integrity_file_entry.schema.json": { + "sha256": "669b01375dd2796aa1b1bfab33f26c98a8fb63074fd4cacfc90713a463014380", + "bytes": 1140 + }, + "schemas/session/jsonschema/index.json": { + "sha256": "f5a64154dc939e9ba56eace3cd8730df7a6a1a2a862c2f74b59ac8ca36919d17", + "bytes": 1521 + }, + "schemas/session/jsonschema/health_snapshot.schema.json": { + "sha256": "de12b04b46a407ce7f6b64bbefeb22a7cf289c01c7157aa0b99b629f0f74a00f", + "bytes": 1995 + }, + "schemas/session/jsonschema/gap_event.schema.json": { + "sha256": "8b6fc4cb71aace5a97c76cf2ea2afb72af325adfa653967c97b2873bf63fe479", + "bytes": 914 + }, + "schemas/session/jsonschema/device_array.schema.json": { + "sha256": "1b8130ab3fe0653923b3ce61c48184eb77407f3c4b8767dd46f14537d2fa9373", + "bytes": 939 + }, + "schemas/session/jsonschema/clock_mapping.schema.json": { + "sha256": "d14b31281ab634a15d2c009148668e7f80dc1bbabd52135e01f18306326d180d", + "bytes": 933 + }, + "schemas/session/jsonschema/checkpoint.schema.json": { + "sha256": "4f32b55ba009e6d33395e82c645111a6c54e8b797ba78411d677cae08a1a8680", + "bytes": 1125 + }, + "schemas/session/jsonschema/annotation.schema.json": { + "sha256": "335772a3d0bc42fddf886f90579e287a33cc5b759447aef70188945af71230a3", + "bytes": 660 + }, + "schemas/session/jsonschema/analysis_job.schema.json": { + "sha256": "0f16c96cb79596f25e05f2a80545b42d080570adbcb84faaf5db5904f35b0ab1", + "bytes": 2417 + }, + "schemas/session/jsonschema/analysis_feature_schema.schema.json": { + "sha256": "3ae59b76a6aa8fdd4a9f4f99872f3c410077741d76b929591338331a9fb89188", + "bytes": 1199 + }, + "schemas/session/golden/README.md": { + "sha256": "dae2a59d25bcef6d389fb11dcacb40be0f78ea3e8057500c4c54d749caddb457", + "bytes": 117 + }, + "schemas/session/examples/minimal_session/README.md": { + "sha256": "6fb421a318df4295fbc047ee5c31425c2e4c6dcc6a928f12f743cf84657f5e6a", + "bytes": 448 + }, + "tests/ui/test_modality_phase4.py": { + "sha256": "d8e7f0e5cdacbe342f4aed94cde9d30ee486eaf1ad2681d25bc22a3bb5f0171f", + "bytes": 3564 + }, + "tests/ui/test_desktop_smoke.py": { + "sha256": "968cbf29944e5803a8789cf4dc4a44426f965a33067bf9a81582937ccb0e9b35", + "bytes": 2917 + }, + "tests/ui/test_analysis_workbench.py": { + "sha256": "71565363e22a58f9207adbfa91ee1022693c367471f86204caca19754c1f9e0e", + "bytes": 3602 + }, + "tests/ui/test_analysis_sources.py": { + "sha256": "db5430b670eafcbfb8fe5c05b3abffe31ab9eb5fc4bdcae043615dc921532d29", + "bytes": 19069 + }, + "tests/ui/test_analysis_scope.py": { + "sha256": "bf01b632cf377f09c06dedd2ac09eb9326290f0e35322e0464dc4d52a99421c5", + "bytes": 14426 + }, + "tests/ui/test_analysis_nested_gallery.py": { + "sha256": "566ff56a05014d47ffd887976751c06f259957a908ec34528725a039269b434f", + "bytes": 7291 + }, + "tests/ui/test_analysis_job_file_reads.py": { + "sha256": "2f862646186213e4f9ad4ec1427011fc009887be86bd112b4181776f2d159372", + "bytes": 3650 + }, + "tests/ui/test_analysis_job_comparison.py": { + "sha256": "81e931c5dfe9cd67b3f38117e4e2fd08d1a3b8c395c46cc02ce28839541fbfe0", + "bytes": 17558 + }, + "tests/ui/test_analysis_history.py": { + "sha256": "48175547922125c308fa49bbb84149e3dac8903902e7cc64fa7c15b4ca40eccd", + "bytes": 10465 + }, + "tests/ui/test_analysis_figure_export.py": { + "sha256": "5d11472f2b710982daa0149dd4adaeb92b64727df5ebd63710a30c3d435e102d", + "bytes": 20322 + }, + "tests/ui/test_analysis_failure_notes.py": { + "sha256": "3d8ae8c4ea3d38f9614b28a26f89e9badc7117689e8166ba410cb93c06c7a80e", + "bytes": 3450 + }, + "tests/protocol/test_structured_log.py": { + "sha256": "d920bbf3c4cdf9721ec66a95da190d50277b34c40f671d5f082827e7286bc339", + "bytes": 1028 + }, + "tests/protocol/test_soak_cleanup.py": { + "sha256": "0feabc157c2feec1a684b1d300397807de67cba5b5d6e66612cb3b1ba4da650f", + "bytes": 4052 + }, + "tests/protocol/test_sim_advertise.py": { + "sha256": "54100ce05724a23801b9c475f537b63cdd405b8d41bfc493c8640bf55083c882", + "bytes": 6117 + }, + "tests/protocol/test_settings_registry.py": { + "sha256": "840f4110417a40400faba05ff6c3f75cae8300892d201e70d2d034d0f3ae6951", + "bytes": 4765 + }, + "tests/protocol/test_session_schemas.py": { + "sha256": "da100eb39eb36e2f464dd424788e9bc4370424f1d1c3b91b7e15cdf05e85a655", + "bytes": 2537 + }, + "tests/protocol/test_schema_roundtrip.py": { + "sha256": "2a0fc260904066b070079370fc3af7a275a8a332f8f85165d2e536a62465fb5c", + "bytes": 3964 + }, + "tests/protocol/test_runtime_isolation.py": { + "sha256": "f1bf05e6743cbc7d4f2c501ea48277172d549c60964b62b9889729aee5705a11", + "bytes": 485 + }, + "tests/protocol/test_registry_readonly_receiving.py": { + "sha256": "185c956548ff7097d65705b2de94edb0e0047f9d522fea02b043aa817639a65e", + "bytes": 4112 + }, + "tests/protocol/test_python_worker_sdk.py": { + "sha256": "bf3dca9aa42062c58e6ad38e043fa1ebba83d3ba5cdd627c28b468a757a3aec8", + "bytes": 4905 + }, + "tests/protocol/test_native_support.py": { + "sha256": "e6c10cf423496a606f00767f609e4a19637fdc66c556cf0928516846352f9693", + "bytes": 3273 + }, + "tests/protocol/test_native_ci_runner.py": { + "sha256": "292872efb3ab91a83ca399110fa00d242f14998f4160975616ad11d6e3567272", + "bytes": 2898 + }, + "tests/protocol/test_lsl_bridge.py": { + "sha256": "9b6c24dcd323ef9ca578f17325edf505a7a9634c5c6dc7b6fdcc0a72526c071d", + "bytes": 730 + }, + "tests/protocol/test_handshake.py": { + "sha256": "81b3f795642888a472076f1d923b7fac1323fa42f0b756860633f1c3f487e9e7", + "bytes": 2582 + }, + "tests/protocol/test_framing_view_lifetime.py": { + "sha256": "79dc7b7a5f9711adf218ed1c46c79b44d1b04dc8aa5830a478f81f7b50795406", + "bytes": 3377 + }, + "tests/protocol/test_framing_stream_transitions.py": { + "sha256": "2115413658146077d9a48b97a8cff56e028ed6e2ec0804510396c4e738ed0d1f", + "bytes": 3217 + }, + "tests/protocol/test_framing_invalid_stream.py": { + "sha256": "d5d0a8e8495e467784901ecf3f6a87ef4422fd14b0a1d7111e7d93e8f5d3c839", + "bytes": 1100 + }, + "tests/protocol/test_framing.py": { + "sha256": "65368d9d13d67431ca8de03448dd102f0eb9758c99db34c1b270d579729f8801", + "bytes": 1763 + }, + "tests/protocol/test_diagnostic_bundle.py": { + "sha256": "43131de7a86a6de2d9e01f2428fc03c8426f767fb0ee67813c0986f8460b7667", + "bytes": 2209 + }, + "tests/protocol/test_daemon_e2e.py": { + "sha256": "81bdc167834a36599f5e36776eb087c7ad39d0e30cc3cad9eccfa9853873ca5d", + "bytes": 11263 + }, + "tests/protocol/test_cpp_portability_contract.py": { + "sha256": "7b98cbf8c1dcbbe22979ddf28a0e3a169eeb0dcc39f33b32934c077c5b8f6986", + "bytes": 1048 + }, + "tests/protocol/test_config_schema.py": { + "sha256": "a76ada212e5ae64f3c1d37eda3c8ba312ee67552630ebc99827820fdea220b91", + "bytes": 3128 + }, + "tests/protocol/test_codegen_fresh.py": { + "sha256": "c909de55e41b0937056f7e29ea13876ea0531d6fe7725c377747aa7c1547b9aa", + "bytes": 1854 + }, + "tests/protocol/test_codegen_bytes.py": { + "sha256": "eaccef5df0d7ce1f6dee0cf986f91adbe709442a74cd98f5230c01b92a3a2746", + "bytes": 1867 + }, + "tests/protocol/test_ci_evidence.py": { + "sha256": "ccf8c6b71f71580b8e911977b543847a63af1660d4e11332c463cc2b114a80bd", + "bytes": 5350 + }, + "tests/protocol/test_ci_contract.py": { + "sha256": "09cfdada9669b3c5e07cf8e26a4844bb7f7043dfc02ead62ff4f36ac8598c765", + "bytes": 7384 + }, + "tests/protocol/test_camera_ci_qualification.py": { + "sha256": "ffb8902071185d86776460bad3e7f600d0ff6b7d449d5d875254dad73cbbb2c9", + "bytes": 14479 + }, + "tests/protocol/__init__.py": { + "sha256": "005968a953091e26becb75148418187a7737a57731485eec99d23fc07a6677b9", + "bytes": 40 + }, + "tests/kill_tests/test_kill_preserves_sealed.py": { + "sha256": "0f1901475eec888531e14c5fadc29857007f0b52ed1b0cf350b89189778dec8d", + "bytes": 6459 + }, + "tests/cpp/test_worker_host.cpp": { + "sha256": "30a9dfdc1f7f32e01b88db81807b7012bdbaa50e038089eb33df706a2c6e0548", + "bytes": 11858 + }, + "tests/cpp/test_storage_posix.cpp": { + "sha256": "daab7555a3834319346db06caee40a5280c7a045ffe645f58a5a806832620393", + "bytes": 2734 + }, + "tests/cpp/test_source_fsm.cpp": { + "sha256": "a67f55fd179461b4402d00c4f795f16e14bb3e373bab83f7d2b1a2385baaf098", + "bytes": 1715 + }, + "tests/cpp/test_sim_engine.cpp": { + "sha256": "924d452da93b46b7105a80b11d95d2d2375288f70c98dddc6693ac76611a1970", + "bytes": 5906 + }, + "tests/cpp/test_session_package.cpp": { + "sha256": "94e0d8a428768f2234d302257fac54e79854f3ebfc21207359f92cf7bce412e7", + "bytes": 3993 + }, + "tests/cpp/test_session_fsm.cpp": { + "sha256": "7d22f716da0a897ef35649411b1e2774ca4b37346788d517a55d26e1ba1640c3", + "bytes": 1568 + }, + "tests/cpp/test_recovery.cpp": { + "sha256": "7cf1003bb0d420179ed685201d687987d5047f6a5a10fe9b7458dbb3ef94156e", + "bytes": 2955 + }, + "tests/cpp/test_logging.cpp": { + "sha256": "eb5f1ec38441b86d3c62941505b0f1240a191afac5e9ebb7f2f27561a71d5cc1", + "bytes": 1469 + }, + "tests/cpp/test_framing.cpp": { + "sha256": "5a90ac7cedfcca0eeff7668253491557ac7ead96860b217642444efeddf3dc57", + "bytes": 1274 + }, + "tests/cpp/test_env.cpp": { + "sha256": "26be1962f3d7b460618c401928c3938402fe70bc656dfbcde9a0bfb112d6410e", + "bytes": 833 + }, + "tests/cpp/test_clock.cpp": { + "sha256": "8dd2a640ff75ce79baef468093558f5eee77a6c4fd2f993bab0e9a6b49237a67", + "bytes": 996 + }, + "tests/cpp/test_atomic_file_windows.cpp": { + "sha256": "485af6482c6b14fc7c187b45cc366af547bf0a1fe2c0651c8b68c8d25e854cfb", + "bytes": 9852 + }, + "tests/cpp/test_atomic_file_posix_identity.cpp": { + "sha256": "347f85f5087c674199120d196c3457ae688fe698c2fd6fde119a307cc9fc9702", + "bytes": 9708 + }, + "tests/cpp/test_atomic_file_posix.cpp": { + "sha256": "ea35516f3f6c81f6701c356cab57c6d55fd0e8e273a8a771599a5f982bee2ef9", + "bytes": 8933 + }, + "tests/cpp/CMakeLists.txt": { + "sha256": "78d008caac4721076791b3d1303ceca8dac97070c8dbd12cb5a0df8bd9edd446", + "bytes": 4061 + }, + "tests/cmake/test_camera_packaging.py": { + "sha256": "caf76c4e3317525af921b3d76dc7f2d5111c2d67903d1e523c5824ba81eee383", + "bytes": 3251 + }, + "tests/cmake/camera_runtime_packaging.cmake": { + "sha256": "e13e7934d1875d4fc27dcbdd2a76638e0f721e4830a83dd2710eda7b13395093", + "bytes": 7644 + }, + "tests/analysis/test_sync_anchor_request.py": { + "sha256": "80dd9c2b3210f8198a49ba893b49b330edf345e29cc30d4f9613299db271ca30", + "bytes": 5010 + }, + "tests/analysis/test_stream_gap_scope.py": { + "sha256": "748c0c943958ffe0c90bbe2e760ae688b548290b5427b4a6ded3ed0e5db8bbab", + "bytes": 8511 + }, + "tests/analysis/test_qc_gap_details.py": { + "sha256": "9c6942a27fd37c01262d388e0834bdd49154a430b20cdf294791d6007e98f690", + "bytes": 10085 + }, + "tests/analysis/test_pose_job.py": { + "sha256": "85a5cb024c9f734c3b057a2d47c42bf22eb5c6ad9b1147c63e115e323b3e4951", + "bytes": 7964 + }, + "tests/analysis/test_plugin_registry.py": { + "sha256": "f567f641fa48307f6799e2d511c8747632083e07b0cf2ac61c7b738675a7e4b8", + "bytes": 3594 + }, + "tests/analysis/test_phase_b_features.py": { + "sha256": "60916848e6aa8b270a5ccd7e9bcbeed59450f12eadc3ee10f1a7c52e617e704d", + "bytes": 7727 + }, + "tests/analysis/test_phase_a_qc.py": { + "sha256": "0be539a3d593e1cf144f4b7f871af90082feaa19a4ac8f234f53a2b232c8cc07", + "bytes": 4085 + }, + "tests/analysis/test_offline_demo.py": { + "sha256": "9e21f77c460ad3ba599a2ca2126b89d1b21790ba43adb2f2edb37ed96c7f80bf", + "bytes": 1889 + }, + "tests/analysis/test_numeric_receiving.py": { + "sha256": "af72aac15ae863faced59b720a7f25506a7e77de44f32d74f21cc4500daccd14", + "bytes": 14363 + }, + "tests/analysis/test_numeric_cli_receiving.py": { + "sha256": "19100c6bde3cebd7d9cfedff3d1045d54814a54ad33d7562cbbd967d671b74c2", + "bytes": 23907 + }, + "tests/analysis/test_numeric_batch_pipeline.py": { + "sha256": "43369bd0fea48d2c8b7dee1d8128b3bb131b508b7b0a14512fc457fcfdb0ba3c", + "bytes": 19230 + }, + "tests/analysis/test_ml_bundle_metadata.py": { + "sha256": "b2104dd43f464629e284fe946126a65fa5423531f67b9fd165b702f888cd799d", + "bytes": 7257 + }, + "tests/analysis/test_kinematics_validity.py": { + "sha256": "f269c16f24883599e3972936f0a1e04868bf0939fbcbe1d178475eb0f197ad31", + "bytes": 8424 + }, + "tests/analysis/test_kinematics_ml_bundle.py": { + "sha256": "7b93bbe85208f53aa3f0b4f2b2a2069c9091fbd816b2eae4ba3eae6c2dea1d0c", + "bytes": 8414 + }, + "tests/analysis/test_job_replacement.py": { + "sha256": "e4480546d7e0653d3ad40cf52ad3f1489499c3810c9814f84145e1000b2b9ebd", + "bytes": 12573 + }, + "tests/analysis/test_job_output_provenance.py": { + "sha256": "9f041284a595312cd7d75fc36a959d16205bb4cebf6f90bf0f098ef574bf8d0f", + "bytes": 6047 + }, + "tests/analysis/test_job_failure_cli.py": { + "sha256": "77f62b52bc01b6325c2349f6482d407465869587ecc3380c01303e0398b226f6", + "bytes": 2008 + }, + "tests/analysis/test_job_destinations.py": { + "sha256": "4cd647bee435fd26e21fb9d6a87051b3d2e79ddac95750852f891ef1a3a0f0eb", + "bytes": 5091 + }, + "tests/analysis/test_external_predictions.py": { + "sha256": "83f4c799720ae9cdffcc1cb81fa010ea0ec5d91c655309f2137a3594370579a7", + "bytes": 16588 + }, + "tests/analysis/test_export_sidecar.py": { + "sha256": "b1332b08d505978876f39793ad4cd2fc3c2cc0ea56f3a70c66eab24cac914790", + "bytes": 10273 + }, + "tests/analysis/test_export_selection_mcap.py": { + "sha256": "c40a2dc8b4b67a615a1e3e75a24db366336fecb8be94168dd4948c34ea568525", + "bytes": 13131 + }, + "tests/analysis/test_checkpoint_sections.py": { + "sha256": "f08db026af80f802b0c8a491095e86bcd3436945def56f0d2f4899e2c22c368f", + "bytes": 15085 + }, + "tests/cmake/warning_boundary/owned_conversion.cpp": { + "sha256": "b485576035a8380202fb5f630443244b9701c7e6565006e93d0e1164ca7a4718", + "bytes": 110 + }, + "tests/cmake/warning_boundary/generated_header.cpp": { + "sha256": "e8a5ab64f8e938567e568b6daa1d26469901813fb06ea1284efaf5228d805530", + "bytes": 114 + }, + "tests/cmake/warning_boundary/env_helper.cpp": { + "sha256": "d2586b74518ce6548ca7275bd21bbd4432d7d248edafca62e280bc18fd2c5e75", + "bytes": 241 + }, + "tests/cmake/warning_boundary/control.cpp": { + "sha256": "cc064c237c531dd12e9f8d0a94ffec53976b7c73ac10149793d27ef3259ae543", + "bytes": 69 + }, + "tests/cmake/warning_boundary/CMakeLists.txt": { + "sha256": "7f9e0f853edc8549deb970eb31b052b2881d4285ce5b95d75fc5ceeca43efff5", + "bytes": 773 + }, + "tests/cmake/portable_storage/session_doctor.cmake": { + "sha256": "afc37e9f36b94309b807e46c8f0fc3b338c458448a83e2f7ec2a08386e8bedbe", + "bytes": 3852 + }, + "tests/cmake/portable_storage/fixture_isolation.cmake": { + "sha256": "ad04e619453d94a10e04d5a11bc4155d6f6f62c47dbbe5b2f3e958f151f89a27", + "bytes": 1745 + }, + "tests/cmake/camera_packaging/probe.cpp": { + "sha256": "589b638fa7c213e6db05ba1e04eeda6f437ca3b71ba407f138ef0ee041124e48", + "bytes": 448 + }, + "tests/cmake/camera_packaging/check_packaging.py": { + "sha256": "8973e4e67cae02ddf9abadfbafa76df3481015ef24db6064877d6430972812b0", + "bytes": 6633 + }, + "tests/cmake/camera_packaging/README.md": { + "sha256": "1b8bd553537820097b3b3d2e39e21a28acb8ed8778b4b91f84ef91b2ddb3d0a9", + "bytes": 1474 + }, + "tests/cmake/camera_packaging/CMakeLists.txt": { + "sha256": "84e3c12336d99d92bab625c9dcf66edb14eae3a4a6d96e0ae722303230b95ae0", + "bytes": 1789 + }, + "tests/cmake/warning_boundary/generated/protoc_pattern.hpp": { + "sha256": "8c9677961aac1169a5505d7515fa06aca60ab418cbee63d51b840088a5607050", + "bytes": 213 + }, + "tests/fixtures/mini_session/manifest.json": { + "sha256": "c5254d3e4c0bc6a0ecaef124dc12d88117d647928a8e1725b71429097438d380", + "bytes": 235 + }, + "tests/fixtures/mini_session/integrity.json": { + "sha256": "af5d9bacd3eace7e831d48dee83eb5d9f578f4f4819d92218c4b55b0cb3ed556", + "bytes": 227 + }, + "tests/fixtures/mini_session/processing/.gitkeep": { + "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "bytes": 0 + }, + "tests/fixtures/mini_session/events/sync_anchors.json": { + "sha256": "37517e5f3dc66819f61f5a7bb8ace1921282415f10551d2defa5c3eb0985b570", + "bytes": 3 + }, + "tests/fixtures/mini_session/events/checkpoints.json": { + "sha256": "37517e5f3dc66819f61f5a7bb8ace1921282415f10551d2defa5c3eb0985b570", + "bytes": 3 + }, + "tests/fixtures/mini_session/events/annotations.json": { + "sha256": "37517e5f3dc66819f61f5a7bb8ace1921282415f10551d2defa5c3eb0985b570", + "bytes": 3 + }, + "tests/fixtures/mini_session/sources/sim.imu.upper/source.json": { + "sha256": "a6198f509edc557c1e1d8583a767a540962977751c80a1b6491e3d594b60c7a8", + "bytes": 118 + }, + "tests/fixtures/mini_session/sources/sim.emg.main/source.json": { + "sha256": "4e7626e51bfb804c27f83bf98ee186a47ec9f36fec0cbd7863ea8ecb1ecfbd10", + "bytes": 112 + }, + "tests/fixtures/mini_session/sources/sim.emg.main/health/gaps.jsonl": { + "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "bytes": 0 + }, + "tests/fixtures/mini_session/sources/sim.emg.main/streams/sim.emg.main.batch/stream.json": { + "sha256": "8f8c02b89fd93e55643151e5222488e1174dd97a6b7a74f3ae5da8215b4d68e1", + "bytes": 216 + }, + "tests/fixtures/mini_session/sources/sim.emg.main/streams/sim.emg.main.batch/segments/000000.mcap": { + "sha256": "3c4d91b3bf5d48dcf54a598fff5b1b4ee42260b756d6f5df3986da496c6a9649", + "bytes": 28 + }, + "tests/fixtures/mini_session/sources/sim.imu.upper/streams/sim.imu.upper.frames/stream.json": { + "sha256": "ec39026bed1b833d4decb0ef7b0efb94c5557a5647bc50addc060bef3a30d50d", + "bytes": 219 + }, + "tests/fixtures/mini_session/sources/sim.imu.upper/streams/sim.imu.upper.frames/segments/000000.mcap": { + "sha256": "3c4d91b3bf5d48dcf54a598fff5b1b4ee42260b756d6f5df3986da496c6a9649", + "bytes": 28 + }, + "tests/fixtures/vendor_replay/emg/sample_batches.jsonl": { + "sha256": "3652e7bb3774374637abfe51a414d8aace94152af64166eb915bb7ddd0b30ce7", + "bytes": 364 + } + }, + "qualification": "Unexecuted native integration candidate; inherited earlier results retain their original heads." +} diff --git a/docs/receiving/analysis-workspace-composition-401c5d17da79/TEST-CANDIDATE.json b/docs/receiving/analysis-workspace-composition-401c5d17da79/TEST-CANDIDATE.json new file mode 100644 index 00000000..81317031 --- /dev/null +++ b/docs/receiving/analysis-workspace-composition-401c5d17da79/TEST-CANDIDATE.json @@ -0,0 +1,302 @@ +{ + "head": "5b693a54f3323c6c7604f6ecd2feb6cf9c6040b1", + "tree": "31ad49114bffb0ff6d4a0b419e632f8e15cd2cb9", + "runtime": "facb4af1d9277d88c233a54520b33d3c79cee174", + "test_blob": "8cc550237cefe6d50081547655045abaf275911d", + "test_sha256": "418df81218407151318f17ab3e1da8d3b7eacc0e8664ed7cfe1dc3daf6732476", + "sources": { + "pyproject.toml": "0cb8de1ab3dfbfed84ff16b35f3c89c6440180183ee5851d5d80da83622e53d0", + "tools/run_ci_tests.py": "fa700e42e15cbec944f3571d40a44df23b8fcc2c13479ec86e39597c6cfb091c", + "tools/check_licenses.py": "c6d90c9175d2db1de0f3426128c5fb511afc35942156c9bd2b7e692afc401463", + "tests/conftest.py": "f669618fad17e906c91df7a1e9393fc7a54f458c6d62a4385436ba2622beca0e", + "schemas/NOTICE": "78581010fab3d185adf35edb8c7459bbabcb6efa5327d893307dfcddf1f1fef0", + "schemas/LICENSE": "cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30", + "desktop/pyproject.toml": "3646f83dcc0764b3c8cb198b98b03201dc47808bb80bfec4837e329e47bd012f", + "desktop/capture_desktop/widgets_session_timeline.py": "7671ad4b632fd83498ad0c02f9030e4f46a0ef2d99a3764c13de3996e3c2ade4", + "desktop/capture_desktop/widgets_session_header.py": "b9e11a7e3709283ed37bacbe96836d6720467f2bdcb934d75491df5dc02927fa", + "desktop/capture_desktop/widgets_radar_array.py": "be08874ade0b4d9197ea85cb6ae3b30db75273ddd3c426faaaf28b4f796653a8", + "desktop/capture_desktop/widgets_preview.py": "78d79c9af67f7e0cbcee3a3a693a22e72753256ca465bab7edb9c2037822dec4", + "desktop/capture_desktop/widgets_modality_expanded.py": "12db25b37e8b2724e5eaabdcb1810aa979633885097b6ec11c33d98a46a83a70", + "desktop/capture_desktop/widgets_mappings.py": "89808d37cb0fce476665a24766963c7a509f5b1802d05dedbf9ca44351081f4b", + "desktop/capture_desktop/widgets_figure_export.py": "a918adbb80e73c220e46e0923fa6ff86a7c2ab336c2832aacbc39a2821df72d6", + "desktop/capture_desktop/widgets_analysis_sources.py": "be4c05cbf9b0c801176668933d3bb60204f5c94ce8fea3f85da176575d42c99f", + "desktop/capture_desktop/widgets_analysis_scope.py": "3f58ffba9125d0ce88fa99317f6aa593fe8aeb4b0dc1d799c95c9c04fb0b73ff", + "desktop/capture_desktop/widgets_analysis_plots.py": "5583bab90fe6c317ed063bb86f95258a60bb976f953e34db09a6b5e07461f1f0", + "desktop/capture_desktop/widgets_analysis_jobs.py": "5cdea6045456e61a58b5525dd224a22a140962d31d2adc5b0102168444468f98", + "desktop/capture_desktop/widgets_analysis_history.py": "a3b77c87483c1412b50de7ddde1498f6bfd3968002fc3ac3bfa474a2477d9bc4", + "desktop/capture_desktop/widgets_analysis_comparison.py": "bd0adca471711350b45702bf7c625b28c348321be43c6eaecd047da33304fc1d", + "desktop/capture_desktop/theme.py": "c77f24e1afeb06400385bd0d535800f13dc15d972891e1ff8af504cbe5c818f3", + "desktop/capture_desktop/state.py": "97fc98498f4553fc7f052d0dc4db992cf2fc136ba7c4405cd275bd156c74e314", + "desktop/capture_desktop/screen_setup.py": "01eb01ffffe835fcf5d26120d508800cc3cdac1e91ffaa3d0d2fa669c6326182", + "desktop/capture_desktop/screen_settings.py": "519436946827fac53d0be68270c2929bd1ce615a58b2372e9e3fc10619a7ba6e", + "desktop/capture_desktop/screen_review.py": "e5aff59de4b194123ca4c4518b34e7b6103326fbd6b0280e2122d984d01072ec", + "desktop/capture_desktop/screen_presets.py": "b62d6f4bef6c1f0fc04b9eaf6a8afd1b2eeb17f6ce14946a06b0495ba33d402c", + "desktop/capture_desktop/screen_capture.py": "4e101ddeeaed7f7f2b4ec2ab2e4b1f4f55ebb86f73b394d25cfd2b904cd2572e", + "desktop/capture_desktop/screen_analysis.py": "7750ae0f5658cced9fca801d815bd530b43f19d1b37d7f775b66db681f2ebc90", + "desktop/capture_desktop/schema_form.py": "7d825b5dc7566d630f31775df6fcc9def1e916eaff5be17a552bf89f28b3418b", + "desktop/capture_desktop/persistence.py": "cdb1fa0094fec72543d5051435850e51d78d79d4bde8d5c83520fa072a2c74c4", + "desktop/capture_desktop/main.py": "e61c29a1925f8d85b24438f087dec360a4481a32e0dc2bd8ed8feb6629026e84", + "desktop/capture_desktop/export_wizard.py": "fb957ff184109bcb4e379dde30414048e855c93ec390f9b50c7ab603c3cd4e30", + "desktop/capture_desktop/daemon_link.py": "ab76628bbe0231c7e5e4d570f2abed01100dddd6a24bb62020b670a6b62427dd", + "desktop/capture_desktop/app.py": "e33cf4446d4edfda3634cb5445aa9456d2f243a8b710c0d9c6497b2ec28078b2", + "desktop/capture_desktop/analysis_job_comparison.py": "3fcc013cedffba87cdfdf105f80502b60bcfdca8c298e6b8feb20da2348d0966", + "desktop/capture_desktop/analysis_history.py": "2e0db8cee59ef268d3c91ea0beac7d761d83a3003862841cc9d7f1782fd3543c", + "desktop/capture_desktop/analysis_figure_export.py": "cf510ab0f9693ed6961623099be30921eb64ee1d435d00c954ef229334ffb471", + "desktop/capture_desktop/__main__.py": "8dbad73a7373565a3513ccbb613f11bffdd13a05861c3e8e07392b8d51008aa2", + "desktop/capture_desktop/__init__.py": "8426c94323c4cca0879b8612345e3577d0a75f6239237a28d79d94a42004c3b5", + "libs/python/capture_worker/pyproject.toml": "0cba218b59a756185fedf72fb3a3307d1d9cb9218b6189ea92972d3cec139a46", + "libs/python/capture_worker/NOTICE": "2a7e69c4c7cd4e93a5cc9e9f984873a2d1276f465b91b10c71b951ebcfb2c588", + "libs/python/capture_worker/LICENSE": "cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30", + "libs/python/capture_session/pyproject.toml": "3484887da96d4a2f32de8471b537d849f077b195c729ff0cc29307681e8d4895", + "libs/python/capture_protocol/pyproject.toml": "61b2e33b2de2a153fb994144f532402c1b6b8ed02afb627ba0a15239e726ca71", + "libs/python/capture_protocol/NOTICE": "3efb470f58c900a58deaef889527e074206274b0fd5fb0e2e62613c093064307", + "libs/python/capture_protocol/LICENSE": "cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30", + "libs/python/capture_analysis/pyproject.toml": "84cd96465e48439bdd81f5fa126fea5da11ee7587b488bfaaa67a4cd8f760c75", + "libs/python/capture_analysis/capture_analysis/windows.py": "5cf401b7b7d201225c966b804cfff39c3f6d59669da7e488dd68c4253a829c32", + "libs/python/capture_analysis/capture_analysis/version.py": "9e25143344b110699f68b6acdbef49576fc91c2cbda34956d7e2cb85bbbc4ae3", + "libs/python/capture_analysis/capture_analysis/types.py": "e7996d02483f69265a2ef2ec0b28078c86f4f479daa53e38faf8b4a62645d02c", + "libs/python/capture_analysis/capture_analysis/report_html.py": "f2c89c7faf6e4edc265540140272396b4195eb5aed9edf05c4912aac74286f03", + "libs/python/capture_analysis/capture_analysis/qc.py": "f24e0593a3723311d41054aef40b56c4bb46d4f3ba5ef4b01afcae3a6cc4440a", + "libs/python/capture_analysis/capture_analysis/pipeline.py": "e8c0152040ba5b5f3f37ac53fb5188bac9dd9aaf0d5816d6a718be505c20898c", + "libs/python/capture_analysis/capture_analysis/jobs.py": "fa7686685f1a680eb2982191fbd03b3986487e638e95088b56de32d4c183d568", + "libs/python/capture_analysis/capture_analysis/grids.py": "936c5404783145f7a2bc4c13df22d3b85612bcb227115bba74f0b78a11c0c483", + "libs/python/capture_analysis/capture_analysis/discover.py": "344ee5d7cb0f5e95ac7524a0c1141b0a293bb9445e2bd4789c6736f39cfcb90d", + "libs/python/capture_analysis/capture_analysis/__init__.py": "14cfe6dccd33a0bda74fac3c9339e1a37a3538b2110a8ae6e307801b776eb43a", + "libs/python/capture_analysis/capture_analysis/pose/job.py": "1f4c44f443c07e22e8c9ca877232c6780c4b1da7834d5565b82cf547b2f4c439", + "libs/python/capture_analysis/capture_analysis/pose/__init__.py": "d58a03cae86259b2cb0ecd0a5ce2347c6824f14cfea6871c94d76acc3541a380", + "libs/python/capture_analysis/capture_analysis/plugins/registry.py": "33a4d07600db8b116fbd46b67492f62129df513df5b66a2c455dced0b2a9dc69", + "libs/python/capture_analysis/capture_analysis/plugins/numeric.py": "75b55cb453095ad5470ce2532b65d3dce771e6a2f8ad1e46a538b4291fa4cf93", + "libs/python/capture_analysis/capture_analysis/plugins/manifest.yaml": "1efe3ee2d9eeeeac03c2c03c582edf0119c9abd6d214dfdca3d827fa10a5c048", + "libs/python/capture_analysis/capture_analysis/plugins/handlers.py": "9be2e1820529b94e54d06790d53aa94cf658f982efb4063c6b64f9d07acc4b2e", + "libs/python/capture_analysis/capture_analysis/plugins/dummy.py": "facf059d247bca44f2697383e12cc1296b1d1d12bede1196f4a52a1352d60495", + "libs/python/capture_analysis/capture_analysis/plugins/__init__.py": "c511d4b9cd1cda042b781b06fbb02d2d99004de214735d6daeb459d6e41381fe", + "libs/python/capture_analysis/capture_analysis/plots/sync_dashboard.py": "6f9e0c64193688eb841565729b9d1e9a64136779e892419acabdc81591afd3d5", + "libs/python/capture_analysis/capture_analysis/plots/style.py": "231e7b1c998f4349d5859295007235ffd41848f12fbb7819193bec9630cd3942", + "libs/python/capture_analysis/capture_analysis/plots/modality.py": "bc3aa15ee79d50280a6c9d6aa144fe0519f85dd2c74a0cfa99323f7d57ecd28d", + "libs/python/capture_analysis/capture_analysis/ml_bundle/job.py": "38b7161f081ef038e6ce464dd3b82ca2b49f775ad8988010243743274d6fc5e6", + "libs/python/capture_analysis/capture_analysis/ml_bundle/__init__.py": "e785a2e3bf65852018d811b38ecbaf6ff9c479648025789145218809dd50d8a1", + "libs/python/capture_analysis/capture_analysis/loaders/video.py": "3c3e873ab641904a39ca649dac39072f11948031d068cc21ee459e996d1fc185", + "libs/python/capture_analysis/capture_analysis/loaders/radar_frame.py": "d071f9d95b371798974698fd0caa1fc4c865a85fb772232fd43e7227b15fad2b", + "libs/python/capture_analysis/capture_analysis/loaders/radar_doppler.py": "4942d08eb47229839e339ce7f2f8a64aee7e5fab44bac77029fcd7a3e3e490c1", + "libs/python/capture_analysis/capture_analysis/loaders/numeric_batch.py": "7c84c0425c1b9b821df711f4c40ea89ac13f267dbe6472922eb41a9263e4835c", + "libs/python/capture_analysis/capture_analysis/loaders/mcap_iter.py": "03a418e7689840e378665aac92c42769dd14ba2c88a821a5cbf0cee80766540c", + "libs/python/capture_analysis/capture_analysis/loaders/imu.py": "5ea4747145bf5588974dfd72c834766436c5a2bc0d58d34ace0f8ef403b310d6", + "libs/python/capture_analysis/capture_analysis/loaders/emg.py": "86eb7114be689cdbd2edd76affa2994e7278714916692a35381abd02ba9d599a", + "libs/python/capture_analysis/capture_analysis/loaders/base.py": "696093b31f22d2bef32fc2962c7a11249a590a0b4d776c40cef4edcbc1e48a97", + "libs/python/capture_analysis/capture_analysis/loaders/__init__.py": "2d51c509baf3c0b5c33360637d12e5ce3c7507a859e4f37030f2c3d711ef0b3d", + "libs/python/capture_analysis/capture_analysis/kinematics/registry.py": "1e53fb9da4c6a2743bc1a3f0e687d94599cf995d33f2a2555e0ce5ebc3966d48", + "libs/python/capture_analysis/capture_analysis/kinematics/job.py": "d676e84f54aa1ae2b0f998c2cb37c4e02541c1fd0e3464e38e9865c0049a7239", + "libs/python/capture_analysis/capture_analysis/kinematics/compute.py": "59bdcde630edd97833349d59703dd2c3bb5ce06981bc8b311668560cbfb6b2be", + "libs/python/capture_analysis/capture_analysis/kinematics/__init__.py": "50a0f7fd39648abf269fc549d2c17eb48b1dc9add10ebdb76edc1935d6f80160", + "libs/python/capture_analysis/capture_analysis/features/video_qc.py": "0e25c50e01fc2da47bc7b510d68ba3e72aba33d3e1c79c57b727f5c55c723e27", + "libs/python/capture_analysis/capture_analysis/features/radar_frame.py": "f85c5fe5e2db68606f68e36a42a0c8f323086f0b1e7f233c0ddefa24cdccb443", + "libs/python/capture_analysis/capture_analysis/features/radar_doppler.py": "cffc0ecbb8053fbc2244850c1927469366f4ae93b5439e4d194de2065877fa5c", + "libs/python/capture_analysis/capture_analysis/features/numeric_batch.py": "ecdeb88ca4dd093b973294a53954e9fa0e5d6b4b908225a52d097ef70c7d2154", + "libs/python/capture_analysis/capture_analysis/features/io.py": "c677d209292cca790ccdf1a64ba834f71a078ccce31ea57452e67ece358822ca", + "libs/python/capture_analysis/capture_analysis/features/imu.py": "246bfd1cc3ce72afa0680537062b6795e22b8a06ba6301503d7489a4440c6849", + "libs/python/capture_analysis/capture_analysis/features/emg.py": "11f8f8350464b7c7c079353ca649b4c4aad2580ef8d355fe741c025c262b168e", + "libs/python/capture_analysis/capture_analysis/features/__init__.py": "3cdd6c626b6da12b8df56d8ddf35fca27c0a744865965ec01dd89d47da476fa1", + "libs/python/capture_analysis/capture_analysis/eval/predictions.py": "decff22c1e2e661a3ce21679db68b667ea44fa5b18df8501204d7d23161cc906", + "libs/python/capture_analysis/capture_analysis/eval/job.py": "0af5556304cfae0be9f40929fbe4eeba6cf8b1453f94e9ba475d66acda8bc913", + "libs/python/capture_analysis/capture_analysis/eval/__init__.py": "54661df9ed7d7e0d4b1c2ab5941f107ceb608e4fdfaff810014ef5fad1431fe1", + "libs/python/capture_protocol/capture_protocol/structured_log.py": "3d7883833286ecc004248294badcc0c66e44a57ecb7844ef281828d797b3c4fc", + "libs/python/capture_protocol/capture_protocol/handshake.py": "63f740c992edf8812f666b79f9cd866d9ea33e65e5b310a5ebda2f5ef98ac115", + "libs/python/capture_protocol/capture_protocol/framing.py": "3ff7c7284d9907a2ad516c83fab383a4151996da3f2d5a1d27e24d7c7575d92e", + "libs/python/capture_protocol/capture_protocol/control_client.py": "68de412465b2eaa04886a2bb4566aa0595c898df7d7e782b3031b8ba919db7fa", + "libs/python/capture_protocol/capture_protocol/constants.py": "7f187edf873cd13f55bc09ff7972785797eb488d74dd5befcb395fc928a71d72", + "libs/python/capture_protocol/capture_protocol/config_schema.py": "00d855895faec7d674cdb8e4da1ddc687888c9e9863f91d4950d24d9fb815e6e", + "libs/python/capture_protocol/capture_protocol/codec.py": "f6c09246a7b165358835e51b99b1508e68d840f4bdbd54b5fb72db33d4912712", + "libs/python/capture_protocol/capture_protocol/__init__.py": "556f474a3d740adc03c40426acde432ab7a394b947f8268bd90eecc7832dff8a", + "libs/python/capture_protocol/capture_protocol/generated/__init__.py": "1fac8216894ce1a1b5362de3b59398fbd78f005a59636aea9f074951bed5c1d7", + "libs/python/capture_protocol/capture_protocol/generated/capture/__init__.py": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "libs/python/capture_protocol/capture_protocol/generated/capture/v1/worker_pb2.py": "112e832172913024c6fad128a9a9559bbcd14b18de06b1f2a3161ac380258dc0", + "libs/python/capture_protocol/capture_protocol/generated/capture/v1/storage_pb2.py": "f7a7b8903af9bfc2d2a419622c86cc057aed2a898949e4261475a7ac61222474", + "libs/python/capture_protocol/capture_protocol/generated/capture/v1/source_pb2.py": "d15b443f27c910c0e809af19fed81d9c1a75f7112501df85877bf4bf9bc4f7a8", + "libs/python/capture_protocol/capture_protocol/generated/capture/v1/project_pb2.py": "983bc5715147297cdcecca343b9a450f2095fcc1e895859cc3c52a3213d933f5", + "libs/python/capture_protocol/capture_protocol/generated/capture/v1/preview_pb2.py": "c992e91b9aef0aa0ec8d595eba2f7079889264d9e4de120b623afd1d8702c695", + "libs/python/capture_protocol/capture_protocol/generated/capture/v1/presets_pb2.py": "d27336594b548f2e6e7ae212fe6de198e6e699c62a5f27752f691d7928ccb27b", + "libs/python/capture_protocol/capture_protocol/generated/capture/v1/health_pb2.py": "e1e0baa7073a9886e4d982d4f00020b490bfd46c32b1b4df129fd0477c1f5e61", + "libs/python/capture_protocol/capture_protocol/generated/capture/v1/events_pb2.py": "72951a468b0480e7fefc4fd3f9b4caac5fda0abdadf4ffcca92d4f19286429ce", + "libs/python/capture_protocol/capture_protocol/generated/capture/v1/control_pb2.py": "f2eea386aebf830ec47fa7379e6fb0493e0a199efecc7b90974bc8bb8c8b96b6", + "libs/python/capture_protocol/capture_protocol/generated/capture/v1/common_pb2.py": "6736e3b86b3c8749d34065794da1c880772ce69e2f248fdd2febd003f083bbd3", + "libs/python/capture_protocol/capture_protocol/generated/capture/v1/arrays_pb2.py": "6355750076724275e49f9a5faec383b2be92c0336ed58805a88954964bd13b86", + "libs/python/capture_protocol/capture_protocol/generated/capture/v1/__init__.py": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "libs/python/capture_protocol/capture_protocol/generated/capture/v1/data/video_timing_pb2.py": "002a79858ccd2d7763769a1fe1be6a16a7f6b8727d15f952d191bcd2240ba5ef", + "libs/python/capture_protocol/capture_protocol/generated/capture/v1/data/radar_frame_pb2.py": "995ddbbb0aa614afb15088cf039c741421c33ea3e3e963ef1a7361b24754b862", + "libs/python/capture_protocol/capture_protocol/generated/capture/v1/data/radar_doppler_pb2.py": "d1b85358aba0c2f4fc1745218463e9951224322604b18b068a2195359dcf790e", + "libs/python/capture_protocol/capture_protocol/generated/capture/v1/data/numeric_batch_pb2.py": "a087cc019b9849f4ef47bcdf4c789a7da90d443240b7bef97c832bb23c1d4e24", + "libs/python/capture_protocol/capture_protocol/generated/capture/v1/data/imu_frame_pb2.py": "4a2048d2a737362bf26b99166e95c457d1492fcfba8848c894fe4d2748ff9f51", + "libs/python/capture_protocol/capture_protocol/generated/capture/v1/data/emg_batch_pb2.py": "1db5ef51143a546072e34cc7be7b263db996fa5f4d0d71606b230cb75b531a14", + "libs/python/capture_protocol/capture_protocol/generated/capture/v1/data/__init__.py": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "libs/python/capture_session/capture_session/settings_store.py": "7719524a1f106cc54befcd21088810f9ec28f0160c8e88f60c374e1545fdb98d", + "libs/python/capture_session/capture_session/registry.py": "809b26ce8d8efc0559a3854cf85ea74b4e486fcd77d253ebfa76bade64b0a8d1", + "libs/python/capture_session/capture_session/package_reader.py": "9a1d9e6e7d24341a083cee602af9538413e948f3369b22660e484356e3d34eb1", + "libs/python/capture_session/capture_session/app_paths.py": "363e4522240e2356cac7492589cb207a798bc1af6031139bd1fa94890f1c4bfd", + "libs/python/capture_session/capture_session/__init__.py": "da530f86c0d1d584862868ddba9f7087ccf5dfbddd64dd1e577337ecfd776419", + "libs/python/capture_worker/capture_worker/writer.py": "b9e3b21ac26f2160da582a3f566a278dc4088c5a8b121d9b4e74f8d8c16cf96f", + "libs/python/capture_worker/capture_worker/worker.py": "19a0dfd16a65479de884d4359a3d65f1bc127d8a6d4b44b93c6251757510de68", + "libs/python/capture_worker/capture_worker/transport.py": "020414c74bd08ec510e88da8c2f8b9ec5091a19cb585b4c54d2656b4bf300d35", + "libs/python/capture_worker/capture_worker/preview.py": "38b483dc06c9215b73e4c56c222fe563957180a5be58761a2c6dd4ea200b8e31", + "libs/python/capture_worker/capture_worker/cli.py": "8a16c4cae0ffd11d4f9cd5d168f6abf1c6f9a4b5100e8edd18a29ce7d44d3f03", + "libs/python/capture_worker/capture_worker/__main__.py": "216422b76731bc985daa5fb0efe55a9d5ce600aa7e6081fa3df0c03afb6a893e", + "libs/python/capture_worker/capture_worker/__init__.py": "c7ba88e956df8460002637eb3d8678a4c7217e680a388f833a22f073dc80f8fd", + "schemas/proto/README.md": "1411f195c911b26e016d478428225b174035357e040c222946fe486185fa32e4", + "schemas/plugin/plugin_manifest.schema.json": "3fa7950584bc391ccd4e67135725c6132f812350d1351e31b028ee9322b640a0", + "schemas/ml_bundle/ml_bundle.manifest.schema.json": "fb099856b1644cd71a243749dbad0b6b79e10cf678af505b39ced3517f2d6ecb", + "schemas/kinematics/kinematics_columns.schema.json": "47ff0aac138c87f2ca74e58b43c9e7b89fceb94ce68ff9bb19f13e3c25f58a83", + "schemas/kinematics/kinematics_columns.registry.json": "86e35c623b9769a019695923047cda2437c4ace6e8cc05b4b6a0009a91650693", + "schemas/eval/predictions.schema.json": "dc7de69d50d94876de42aa6671b4f922b1fa397d72418347559594ecea5fb57c", + "schemas/activity_catalog/activity_catalog.schema.json": "fa443d547e34f4bc1f4733cc03558af4516692462d9c8a11b82e39602171a8b1", + "schemas/activity_catalog/1.json": "cdba686c34c6ae8da8325eb62745856382468175558b20f97b09ce9a6c27ce18", + "schemas/plugin/examples/sim.builtin.plugin.json": "a4e3d85cbd32ee154a91952868726ac26253f0f4d652f7b60ba733b1f9f9a5de", + "schemas/plugin/examples/radar.ifx.plugin.json": "f9041e61f25c798ae6ac433cfa82fa7f514504fd24c88146beb88410bf34dc9f", + "schemas/plugin/examples/camera.gstreamer.plugin.json": "6f921746e815083b55f5d81d10c660e9b448ff315b48a2082090b34b350eae03", + "schemas/proto/capture/v1/worker.proto": "8ae3774630330103a86137d3d7bea09f35997470d66b2829489089f4a3f7ff6d", + "schemas/proto/capture/v1/storage.proto": "4b7ac9342b0497428708299075e615698dc62846e22d0a76f7213841aec51cf1", + "schemas/proto/capture/v1/source.proto": "5f353365bbff5fec722cf3dafc8585afeded5153ce6cd9abcb29326cc9982425", + "schemas/proto/capture/v1/project.proto": "5ba4dfc4158458707b28aee6cf0a01e86798c156ae0499414be314906589c555", + "schemas/proto/capture/v1/preview.proto": "ac74cd566c62b517298a228f1487103e72b6fe959eece920bc3951dc3e927c5b", + "schemas/proto/capture/v1/presets.proto": "55adc5f64d26df5b03bed14505a213fbb3ed6925861156b0cfa6e525dd67b461", + "schemas/proto/capture/v1/health.proto": "4888b25c2b527b3161efa391b009eabb9ead1fd568c8ce25ffaa96f235e9bbce", + "schemas/proto/capture/v1/events.proto": "ac91ca3d1c2806342ebc5c63512b78d1e2bd1c0c7386b3bbe1f78d5049cc2072", + "schemas/proto/capture/v1/control.proto": "7a4b9ad274badc40e0139a7554164183a54ff511fce1ef780305d90642688d84", + "schemas/proto/capture/v1/common.proto": "a9f403a8835b0620eaedef1fdec7bfed09d3f649397b55b12900fe83c5a541d9", + "schemas/proto/capture/v1/arrays.proto": "06360f104803070dff7de92fa40401466d3a68e564dbe96aca839ec4fef7db50", + "schemas/proto/capture/v1/data/video_timing.proto": "717aff65762679bd4363c2c8df38c18047e6012816feb63b56f9e00a6e9e7514", + "schemas/proto/capture/v1/data/radar_frame.proto": "844921a2bbc1732d2e3811d85d1d1863ade60346c2897dd6ef1bede3e9ac3156", + "schemas/proto/capture/v1/data/radar_doppler.proto": "99d1549779e8ab294c6ed80e1341efc1cd612b2c13eef59fe51f32da7679d6f1", + "schemas/proto/capture/v1/data/numeric_batch.proto": "068b62f517b057b448aec26c507b05044f1e9d25c91318657671558fcc8de07b", + "schemas/proto/capture/v1/data/imu_frame.proto": "44c5b700c7e976b3c092b77ae49e21b383899d053d16f55e06b7bc59e2e38ff1", + "schemas/proto/capture/v1/data/emg_batch.proto": "6eaed7210149c82877476cb391d73624b1bb25f7f4b2f822745224e79a743dc6", + "schemas/session/migrations/registry.py": "bf31eb2684c62771809f8c3d11d27851c51287b926cefbe3de86eecdb7a6e5a8", + "schemas/session/jsonschema/timing_header.schema.json": "a2cebf48ae8c79aecb4a42545f36cbe2f3ce1d83be6c82536e99287d7ae098dd", + "schemas/session/jsonschema/sync_anchor.schema.json": "e6bf9f3d790faff1b1f07ab2bdf98ab9b19fb86e760af2b118a4d2f34c510a1f", + "schemas/session/jsonschema/stream_descriptor.schema.json": "4a207f98752dc4d693861d3cb1e5a54ccf1eb18c496d47cf8f490962aedea738", + "schemas/session/jsonschema/source_instance.schema.json": "783bcf6ab4c6430048a4b90174ec80796fed11f0545b22ca5425b0ff14370a90", + "schemas/session/jsonschema/session_manifest.schema.json": "3ef72af1cc561fc2d4f3231e0cbd690c2c5fa223dd9027358bb79de0d9f954f4", + "schemas/session/jsonschema/session_identity.schema.json": "b60df9fe7759ae5df090838a4bd1cc7aafbb858d7a3afb2112cce02f2d315ca5", + "schemas/session/jsonschema/sensor_instance.schema.json": "7eab69c1f5fb936310c1e0e3d55f2a8bbc4defcdb5be4474711701b91728a224", + "schemas/session/jsonschema/radar_array.schema.json": "b72653f8508ef5536c392a0bbb16c9b7670c96223e015078ede13a32a6975434", + "schemas/session/jsonschema/preset_snapshot.schema.json": "d6bb16cd2efefb107d1a797c8a190b0da503e00bcf6bad71bce9c1bec70db48e", + "schemas/session/jsonschema/physical_device.schema.json": "d2e1dd32ac542ad0971ad6e971a6f2bdc9b78c757f46734c5ff0094338793fcb", + "schemas/session/jsonschema/logical_slot.schema.json": "85a907ff10b5c3b1c78d4b83ace963e874ed6a6757efae4c3d41cd34dc57d0b9", + "schemas/session/jsonschema/integrity_manifest.schema.json": "f843a9c88121db424afc9d2f4e25302cbc3b055c256fc118160a49b8e5195515", + "schemas/session/jsonschema/integrity_file_entry.schema.json": "669b01375dd2796aa1b1bfab33f26c98a8fb63074fd4cacfc90713a463014380", + "schemas/session/jsonschema/index.json": "f5a64154dc939e9ba56eace3cd8730df7a6a1a2a862c2f74b59ac8ca36919d17", + "schemas/session/jsonschema/health_snapshot.schema.json": "de12b04b46a407ce7f6b64bbefeb22a7cf289c01c7157aa0b99b629f0f74a00f", + "schemas/session/jsonschema/gap_event.schema.json": "8b6fc4cb71aace5a97c76cf2ea2afb72af325adfa653967c97b2873bf63fe479", + "schemas/session/jsonschema/device_array.schema.json": "1b8130ab3fe0653923b3ce61c48184eb77407f3c4b8767dd46f14537d2fa9373", + "schemas/session/jsonschema/clock_mapping.schema.json": "d14b31281ab634a15d2c009148668e7f80dc1bbabd52135e01f18306326d180d", + "schemas/session/jsonschema/checkpoint.schema.json": "4f32b55ba009e6d33395e82c645111a6c54e8b797ba78411d677cae08a1a8680", + "schemas/session/jsonschema/annotation.schema.json": "335772a3d0bc42fddf886f90579e287a33cc5b759447aef70188945af71230a3", + "schemas/session/jsonschema/analysis_job.schema.json": "0f16c96cb79596f25e05f2a80545b42d080570adbcb84faaf5db5904f35b0ab1", + "schemas/session/jsonschema/analysis_feature_schema.schema.json": "3ae59b76a6aa8fdd4a9f4f99872f3c410077741d76b929591338331a9fb89188", + "schemas/session/golden/README.md": "dae2a59d25bcef6d389fb11dcacb40be0f78ea3e8057500c4c54d749caddb457", + "schemas/session/examples/minimal_session/README.md": "6fb421a318df4295fbc047ee5c31425c2e4c6dcc6a928f12f743cf84657f5e6a", + "tests/ui/test_analysis_workspace_composition.py": "418df81218407151318f17ab3e1da8d3b7eacc0e8664ed7cfe1dc3daf6732476", + "tests/ui/test_modality_phase4.py": "d8e7f0e5cdacbe342f4aed94cde9d30ee486eaf1ad2681d25bc22a3bb5f0171f", + "tests/ui/test_desktop_smoke.py": "968cbf29944e5803a8789cf4dc4a44426f965a33067bf9a81582937ccb0e9b35", + "tests/ui/test_analysis_workbench.py": "71565363e22a58f9207adbfa91ee1022693c367471f86204caca19754c1f9e0e", + "tests/ui/test_analysis_sources.py": "db5430b670eafcbfb8fe5c05b3abffe31ab9eb5fc4bdcae043615dc921532d29", + "tests/ui/test_analysis_scope.py": "bf01b632cf377f09c06dedd2ac09eb9326290f0e35322e0464dc4d52a99421c5", + "tests/ui/test_analysis_nested_gallery.py": "566ff56a05014d47ffd887976751c06f259957a908ec34528725a039269b434f", + "tests/ui/test_analysis_job_file_reads.py": "2f862646186213e4f9ad4ec1427011fc009887be86bd112b4181776f2d159372", + "tests/ui/test_analysis_job_comparison.py": "81e931c5dfe9cd67b3f38117e4e2fd08d1a3b8c395c46cc02ce28839541fbfe0", + "tests/ui/test_analysis_history.py": "48175547922125c308fa49bbb84149e3dac8903902e7cc64fa7c15b4ca40eccd", + "tests/ui/test_analysis_figure_export.py": "5d11472f2b710982daa0149dd4adaeb92b64727df5ebd63710a30c3d435e102d", + "tests/ui/test_analysis_failure_notes.py": "3d8ae8c4ea3d38f9614b28a26f89e9badc7117689e8166ba410cb93c06c7a80e", + "tests/protocol/test_structured_log.py": "d920bbf3c4cdf9721ec66a95da190d50277b34c40f671d5f082827e7286bc339", + "tests/protocol/test_soak_cleanup.py": "0feabc157c2feec1a684b1d300397807de67cba5b5d6e66612cb3b1ba4da650f", + "tests/protocol/test_sim_advertise.py": "54100ce05724a23801b9c475f537b63cdd405b8d41bfc493c8640bf55083c882", + "tests/protocol/test_settings_registry.py": "840f4110417a40400faba05ff6c3f75cae8300892d201e70d2d034d0f3ae6951", + "tests/protocol/test_session_schemas.py": "da100eb39eb36e2f464dd424788e9bc4370424f1d1c3b91b7e15cdf05e85a655", + "tests/protocol/test_schema_roundtrip.py": "2a0fc260904066b070079370fc3af7a275a8a332f8f85165d2e536a62465fb5c", + "tests/protocol/test_runtime_isolation.py": "f1bf05e6743cbc7d4f2c501ea48277172d549c60964b62b9889729aee5705a11", + "tests/protocol/test_registry_readonly_receiving.py": "185c956548ff7097d65705b2de94edb0e0047f9d522fea02b043aa817639a65e", + "tests/protocol/test_python_worker_sdk.py": "bf3dca9aa42062c58e6ad38e043fa1ebba83d3ba5cdd627c28b468a757a3aec8", + "tests/protocol/test_native_support.py": "e6c10cf423496a606f00767f609e4a19637fdc66c556cf0928516846352f9693", + "tests/protocol/test_native_ci_runner.py": "292872efb3ab91a83ca399110fa00d242f14998f4160975616ad11d6e3567272", + "tests/protocol/test_lsl_bridge.py": "9b6c24dcd323ef9ca578f17325edf505a7a9634c5c6dc7b6fdcc0a72526c071d", + "tests/protocol/test_handshake.py": "81b3f795642888a472076f1d923b7fac1323fa42f0b756860633f1c3f487e9e7", + "tests/protocol/test_framing_view_lifetime.py": "79dc7b7a5f9711adf218ed1c46c79b44d1b04dc8aa5830a478f81f7b50795406", + "tests/protocol/test_framing_stream_transitions.py": "2115413658146077d9a48b97a8cff56e028ed6e2ec0804510396c4e738ed0d1f", + "tests/protocol/test_framing_invalid_stream.py": "d5d0a8e8495e467784901ecf3f6a87ef4422fd14b0a1d7111e7d93e8f5d3c839", + "tests/protocol/test_framing.py": "65368d9d13d67431ca8de03448dd102f0eb9758c99db34c1b270d579729f8801", + "tests/protocol/test_diagnostic_bundle.py": "43131de7a86a6de2d9e01f2428fc03c8426f767fb0ee67813c0986f8460b7667", + "tests/protocol/test_daemon_e2e.py": "81bdc167834a36599f5e36776eb087c7ad39d0e30cc3cad9eccfa9853873ca5d", + "tests/protocol/test_cpp_portability_contract.py": "7b98cbf8c1dcbbe22979ddf28a0e3a169eeb0dcc39f33b32934c077c5b8f6986", + "tests/protocol/test_config_schema.py": "a76ada212e5ae64f3c1d37eda3c8ba312ee67552630ebc99827820fdea220b91", + "tests/protocol/test_codegen_fresh.py": "c909de55e41b0937056f7e29ea13876ea0531d6fe7725c377747aa7c1547b9aa", + "tests/protocol/test_codegen_bytes.py": "eaccef5df0d7ce1f6dee0cf986f91adbe709442a74cd98f5230c01b92a3a2746", + "tests/protocol/test_ci_evidence.py": "ccf8c6b71f71580b8e911977b543847a63af1660d4e11332c463cc2b114a80bd", + "tests/protocol/test_ci_contract.py": "09cfdada9669b3c5e07cf8e26a4844bb7f7043dfc02ead62ff4f36ac8598c765", + "tests/protocol/test_camera_ci_qualification.py": "ffb8902071185d86776460bad3e7f600d0ff6b7d449d5d875254dad73cbbb2c9", + "tests/protocol/__init__.py": "005968a953091e26becb75148418187a7737a57731485eec99d23fc07a6677b9", + "tests/kill_tests/test_kill_preserves_sealed.py": "0f1901475eec888531e14c5fadc29857007f0b52ed1b0cf350b89189778dec8d", + "tests/cpp/test_worker_host.cpp": "30a9dfdc1f7f32e01b88db81807b7012bdbaa50e038089eb33df706a2c6e0548", + "tests/cpp/test_storage_posix.cpp": "daab7555a3834319346db06caee40a5280c7a045ffe645f58a5a806832620393", + "tests/cpp/test_source_fsm.cpp": "a67f55fd179461b4402d00c4f795f16e14bb3e373bab83f7d2b1a2385baaf098", + "tests/cpp/test_sim_engine.cpp": "924d452da93b46b7105a80b11d95d2d2375288f70c98dddc6693ac76611a1970", + "tests/cpp/test_session_package.cpp": "94e0d8a428768f2234d302257fac54e79854f3ebfc21207359f92cf7bce412e7", + "tests/cpp/test_session_fsm.cpp": "7d22f716da0a897ef35649411b1e2774ca4b37346788d517a55d26e1ba1640c3", + "tests/cpp/test_recovery.cpp": "7cf1003bb0d420179ed685201d687987d5047f6a5a10fe9b7458dbb3ef94156e", + "tests/cpp/test_logging.cpp": "eb5f1ec38441b86d3c62941505b0f1240a191afac5e9ebb7f2f27561a71d5cc1", + "tests/cpp/test_framing.cpp": "5a90ac7cedfcca0eeff7668253491557ac7ead96860b217642444efeddf3dc57", + "tests/cpp/test_env.cpp": "26be1962f3d7b460618c401928c3938402fe70bc656dfbcde9a0bfb112d6410e", + "tests/cpp/test_clock.cpp": "8dd2a640ff75ce79baef468093558f5eee77a6c4fd2f993bab0e9a6b49237a67", + "tests/cpp/test_atomic_file_windows.cpp": "485af6482c6b14fc7c187b45cc366af547bf0a1fe2c0651c8b68c8d25e854cfb", + "tests/cpp/test_atomic_file_posix_identity.cpp": "347f85f5087c674199120d196c3457ae688fe698c2fd6fde119a307cc9fc9702", + "tests/cpp/test_atomic_file_posix.cpp": "ea35516f3f6c81f6701c356cab57c6d55fd0e8e273a8a771599a5f982bee2ef9", + "tests/cpp/CMakeLists.txt": "78d008caac4721076791b3d1303ceca8dac97070c8dbd12cb5a0df8bd9edd446", + "tests/cmake/test_camera_packaging.py": "caf76c4e3317525af921b3d76dc7f2d5111c2d67903d1e523c5824ba81eee383", + "tests/cmake/camera_runtime_packaging.cmake": "e13e7934d1875d4fc27dcbdd2a76638e0f721e4830a83dd2710eda7b13395093", + "tests/analysis/test_sync_anchor_request.py": "80dd9c2b3210f8198a49ba893b49b330edf345e29cc30d4f9613299db271ca30", + "tests/analysis/test_stream_gap_scope.py": "748c0c943958ffe0c90bbe2e760ae688b548290b5427b4a6ded3ed0e5db8bbab", + "tests/analysis/test_qc_gap_details.py": "9c6942a27fd37c01262d388e0834bdd49154a430b20cdf294791d6007e98f690", + "tests/analysis/test_pose_job.py": "85a5cb024c9f734c3b057a2d47c42bf22eb5c6ad9b1147c63e115e323b3e4951", + "tests/analysis/test_plugin_registry.py": "f567f641fa48307f6799e2d511c8747632083e07b0cf2ac61c7b738675a7e4b8", + "tests/analysis/test_phase_b_features.py": "60916848e6aa8b270a5ccd7e9bcbeed59450f12eadc3ee10f1a7c52e617e704d", + "tests/analysis/test_phase_a_qc.py": "0be539a3d593e1cf144f4b7f871af90082feaa19a4ac8f234f53a2b232c8cc07", + "tests/analysis/test_offline_demo.py": "9e21f77c460ad3ba599a2ca2126b89d1b21790ba43adb2f2edb37ed96c7f80bf", + "tests/analysis/test_numeric_receiving.py": "af72aac15ae863faced59b720a7f25506a7e77de44f32d74f21cc4500daccd14", + "tests/analysis/test_numeric_cli_receiving.py": "19100c6bde3cebd7d9cfedff3d1045d54814a54ad33d7562cbbd967d671b74c2", + "tests/analysis/test_numeric_batch_pipeline.py": "43369bd0fea48d2c8b7dee1d8128b3bb131b508b7b0a14512fc457fcfdb0ba3c", + "tests/analysis/test_ml_bundle_metadata.py": "b2104dd43f464629e284fe946126a65fa5423531f67b9fd165b702f888cd799d", + "tests/analysis/test_kinematics_validity.py": "f269c16f24883599e3972936f0a1e04868bf0939fbcbe1d178475eb0f197ad31", + "tests/analysis/test_kinematics_ml_bundle.py": "7b93bbe85208f53aa3f0b4f2b2a2069c9091fbd816b2eae4ba3eae6c2dea1d0c", + "tests/analysis/test_job_replacement.py": "e4480546d7e0653d3ad40cf52ad3f1489499c3810c9814f84145e1000b2b9ebd", + "tests/analysis/test_job_output_provenance.py": "9f041284a595312cd7d75fc36a959d16205bb4cebf6f90bf0f098ef574bf8d0f", + "tests/analysis/test_job_failure_cli.py": "77f62b52bc01b6325c2349f6482d407465869587ecc3380c01303e0398b226f6", + "tests/analysis/test_job_destinations.py": "4cd647bee435fd26e21fb9d6a87051b3d2e79ddac95750852f891ef1a3a0f0eb", + "tests/analysis/test_external_predictions.py": "83f4c799720ae9cdffcc1cb81fa010ea0ec5d91c655309f2137a3594370579a7", + "tests/analysis/test_export_sidecar.py": "b1332b08d505978876f39793ad4cd2fc3c2cc0ea56f3a70c66eab24cac914790", + "tests/analysis/test_export_selection_mcap.py": "c40a2dc8b4b67a615a1e3e75a24db366336fecb8be94168dd4948c34ea568525", + "tests/analysis/test_checkpoint_sections.py": "f08db026af80f802b0c8a491095e86bcd3436945def56f0d2f4899e2c22c368f", + "tests/cmake/warning_boundary/owned_conversion.cpp": "b485576035a8380202fb5f630443244b9701c7e6565006e93d0e1164ca7a4718", + "tests/cmake/warning_boundary/generated_header.cpp": "e8a5ab64f8e938567e568b6daa1d26469901813fb06ea1284efaf5228d805530", + "tests/cmake/warning_boundary/env_helper.cpp": "d2586b74518ce6548ca7275bd21bbd4432d7d248edafca62e280bc18fd2c5e75", + "tests/cmake/warning_boundary/control.cpp": "cc064c237c531dd12e9f8d0a94ffec53976b7c73ac10149793d27ef3259ae543", + "tests/cmake/warning_boundary/CMakeLists.txt": "7f9e0f853edc8549deb970eb31b052b2881d4285ce5b95d75fc5ceeca43efff5", + "tests/cmake/portable_storage/session_doctor.cmake": "afc37e9f36b94309b807e46c8f0fc3b338c458448a83e2f7ec2a08386e8bedbe", + "tests/cmake/portable_storage/fixture_isolation.cmake": "ad04e619453d94a10e04d5a11bc4155d6f6f62c47dbbe5b2f3e958f151f89a27", + "tests/cmake/camera_packaging/probe.cpp": "589b638fa7c213e6db05ba1e04eeda6f437ca3b71ba407f138ef0ee041124e48", + "tests/cmake/camera_packaging/check_packaging.py": "8973e4e67cae02ddf9abadfbafa76df3481015ef24db6064877d6430972812b0", + "tests/cmake/camera_packaging/README.md": "1b8bd553537820097b3b3d2e39e21a28acb8ed8778b4b91f84ef91b2ddb3d0a9", + "tests/cmake/camera_packaging/CMakeLists.txt": "84e3c12336d99d92bab625c9dcf66edb14eae3a4a6d96e0ae722303230b95ae0", + "tests/cmake/warning_boundary/generated/protoc_pattern.hpp": "8c9677961aac1169a5505d7515fa06aca60ab418cbee63d51b840088a5607050", + "tests/fixtures/mini_session/manifest.json": "c5254d3e4c0bc6a0ecaef124dc12d88117d647928a8e1725b71429097438d380", + "tests/fixtures/mini_session/integrity.json": "af5d9bacd3eace7e831d48dee83eb5d9f578f4f4819d92218c4b55b0cb3ed556", + "tests/fixtures/mini_session/processing/.gitkeep": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "tests/fixtures/mini_session/events/sync_anchors.json": "37517e5f3dc66819f61f5a7bb8ace1921282415f10551d2defa5c3eb0985b570", + "tests/fixtures/mini_session/events/checkpoints.json": "37517e5f3dc66819f61f5a7bb8ace1921282415f10551d2defa5c3eb0985b570", + "tests/fixtures/mini_session/events/annotations.json": "37517e5f3dc66819f61f5a7bb8ace1921282415f10551d2defa5c3eb0985b570", + "tests/fixtures/mini_session/sources/sim.imu.upper/source.json": "a6198f509edc557c1e1d8583a767a540962977751c80a1b6491e3d594b60c7a8", + "tests/fixtures/mini_session/sources/sim.emg.main/source.json": "4e7626e51bfb804c27f83bf98ee186a47ec9f36fec0cbd7863ea8ecb1ecfbd10", + "tests/fixtures/mini_session/sources/sim.emg.main/health/gaps.jsonl": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "tests/fixtures/mini_session/sources/sim.emg.main/streams/sim.emg.main.batch/stream.json": "8f8c02b89fd93e55643151e5222488e1174dd97a6b7a74f3ae5da8215b4d68e1", + "tests/fixtures/mini_session/sources/sim.emg.main/streams/sim.emg.main.batch/segments/000000.mcap": "3c4d91b3bf5d48dcf54a598fff5b1b4ee42260b756d6f5df3986da496c6a9649", + "tests/fixtures/mini_session/sources/sim.imu.upper/streams/sim.imu.upper.frames/stream.json": "ec39026bed1b833d4decb0ef7b0efb94c5557a5647bc50addc060bef3a30d50d", + "tests/fixtures/mini_session/sources/sim.imu.upper/streams/sim.imu.upper.frames/segments/000000.mcap": "3c4d91b3bf5d48dcf54a598fff5b1b4ee42260b756d6f5df3986da496c6a9649", + "tests/fixtures/vendor_replay/emg/sample_batches.jsonl": "3652e7bb3774374637abfe51a414d8aace94152af64166eb915bb7ddd0b30ce7" + } +} diff --git a/docs/receiving/analysis-workspace-composition-401c5d17da79/composed-history-gallery.png b/docs/receiving/analysis-workspace-composition-401c5d17da79/composed-history-gallery.png new file mode 100644 index 00000000..c9b86540 Binary files /dev/null and b/docs/receiving/analysis-workspace-composition-401c5d17da79/composed-history-gallery.png differ diff --git a/docs/receiving/analysis-workspace-composition-401c5d17da79/composition-review.json b/docs/receiving/analysis-workspace-composition-401c5d17da79/composition-review.json new file mode 100644 index 00000000..71a9b1ed --- /dev/null +++ b/docs/receiving/analysis-workspace-composition-401c5d17da79/composition-review.json @@ -0,0 +1,146 @@ +{ + "automatic_trees": { + "history": "e0ea58ce197fc80fb874e82811d3034efe23109e", + "gallery": "19b28e5852f47a2b777fa253b850e5f027f23d07" + }, + "progress": { + "main": { + "bytes": 67264, + "base_prefix": false + }, + "history": { + "bytes": 58255, + "base_prefix": true + }, + "gallery": { + "bytes": 57065, + "base_prefix": true + } + }, + "changed_paths": { + "history": [ + "README.md", + "desktop/capture_desktop/analysis_history.py", + "desktop/capture_desktop/screen_analysis.py", + "desktop/capture_desktop/widgets_analysis_history.py", + "docs/design/research/PROGRESS.md", + "docs/evidence/analysis-history-401c5d17da79/README.md", + "docs/evidence/analysis-history-401c5d17da79/artifact-manifest.json", + "docs/evidence/analysis-history-401c5d17da79/author/author-correction-process.json", + "docs/evidence/analysis-history-401c5d17da79/author/author-correction.log", + "docs/evidence/analysis-history-401c5d17da79/author/author-focused-2.log", + "docs/evidence/analysis-history-401c5d17da79/author/baseline-history.py", + "docs/evidence/analysis-history-401c5d17da79/author/baseline-receipt.json", + "docs/evidence/analysis-history-401c5d17da79/author/candidate-correction-freeze.json", + "docs/evidence/analysis-history-401c5d17da79/author/candidate-source-freeze.json", + "docs/evidence/analysis-history-401c5d17da79/author/harness-observations.json", + "docs/evidence/analysis-history-401c5d17da79/author/thread-event-loop.log", + "docs/evidence/analysis-history-401c5d17da79/author/thread-isolated.log", + "docs/evidence/analysis-history-401c5d17da79/current-numeric/README.md", + "docs/evidence/analysis-history-401c5d17da79/current-numeric/check_numeric_gallery.py", + "docs/evidence/analysis-history-401c5d17da79/current-numeric/numeric-run/numeric-history-gap.png", + "docs/evidence/analysis-history-401c5d17da79/current-numeric/numeric-run/receipt.json", + "docs/evidence/analysis-history-401c5d17da79/current-numeric/numeric.stderr.log", + "docs/evidence/analysis-history-401c5d17da79/current-numeric/numeric.stdout.log", + "docs/evidence/analysis-history-401c5d17da79/current-numeric/process.json", + "docs/evidence/analysis-history-401c5d17da79/current-numeric/source-inputs.json", + "docs/evidence/analysis-history-401c5d17da79/current-qc/README.md", + "docs/evidence/analysis-history-401c5d17da79/current-qc/check_current_qc_history.py", + "docs/evidence/analysis-history-401c5d17da79/current-qc/current-run/artifacts/qc.html", + "docs/evidence/analysis-history-401c5d17da79/current-qc/current-run/artifacts/qc.json", + "docs/evidence/analysis-history-401c5d17da79/current-qc/current-run/receipt.json", + "docs/evidence/analysis-history-401c5d17da79/current-qc/current.stderr.log", + "docs/evidence/analysis-history-401c5d17da79/current-qc/current.stdout.log", + "docs/evidence/analysis-history-401c5d17da79/current-qc/process.json", + "docs/evidence/analysis-history-401c5d17da79/current-qc/source-inputs.json", + "docs/evidence/analysis-history-401c5d17da79/current-scope/README.md", + "docs/evidence/analysis-history-401c5d17da79/current-scope/candidate-source-inputs.json", + "docs/evidence/analysis-history-401c5d17da79/current-scope/check_scope_history.py", + "docs/evidence/analysis-history-401c5d17da79/current-scope/custody.json", + "docs/evidence/analysis-history-401c5d17da79/current-scope/freshness-d43.json", + "docs/evidence/analysis-history-401c5d17da79/current-scope/native.stderr.log", + "docs/evidence/analysis-history-401c5d17da79/current-scope/nonaccepting-continuation/check_scope_history.py", + "docs/evidence/analysis-history-401c5d17da79/current-scope/nonaccepting-continuation/receipt-state.json", + "docs/evidence/analysis-history-401c5d17da79/current-scope/process.json", + "docs/evidence/analysis-history-401c5d17da79/current-scope/receipt.json", + "docs/evidence/analysis-history-401c5d17da79/current-scope/receiving.json", + "docs/evidence/analysis-history-401c5d17da79/current-scope/scope-history-reopened.png", + "docs/evidence/analysis-history-401c5d17da79/current-scope/startup-negative/check_scope_history.py", + "docs/evidence/analysis-history-401c5d17da79/current-scope/startup-negative/native.stderr.log", + "docs/evidence/analysis-history-401c5d17da79/current-scope/startup-negative/native.stdout.log", + "docs/evidence/analysis-history-401c5d17da79/current-scope/startup-negative/process.json", + "docs/evidence/analysis-history-401c5d17da79/current-scope/startup-negative/receipt.json", + "docs/evidence/analysis-history-401c5d17da79/current-scope/startup-negative/screen_analysis.py.txt", + "docs/evidence/analysis-history-401c5d17da79/current-scope/startup-negative/source-inputs.json", + "docs/evidence/analysis-history-401c5d17da79/independent/37443-candidate.log", + "docs/evidence/analysis-history-401c5d17da79/independent/37443-manual-stall-receipt.json", + "docs/evidence/analysis-history-401c5d17da79/independent/baseline-receipt.json", + "docs/evidence/analysis-history-401c5d17da79/independent/baseline.log", + "docs/evidence/analysis-history-401c5d17da79/independent/c0b5530-candidate.log", + "docs/evidence/analysis-history-401c5d17da79/independent/c0b5530-eventloop-receipt.json", + "docs/evidence/analysis-history-401c5d17da79/independent/c0b5530-eventloop.log", + "docs/evidence/analysis-history-401c5d17da79/independent/c0b5530-failure-receipt.json", + "docs/evidence/analysis-history-401c5d17da79/independent/methods/receive_history.py", + "docs/evidence/analysis-history-401c5d17da79/independent/methods/receive_history_native.py", + "docs/evidence/analysis-history-401c5d17da79/independent/methods/receive_qt_eventloop.py", + "docs/evidence/analysis-history-401c5d17da79/independent/native-candidate-receipt.json", + "docs/evidence/analysis-history-401c5d17da79/independent/native-candidate.log", + "docs/evidence/analysis-history-401c5d17da79/publication-composition.json", + "docs/evidence/analysis-history-401c5d17da79/publication-license-check.json", + "docs/evidence/analysis-history-401c5d17da79/publication-method-adjustments.json", + "docs/evidence/analysis-history-401c5d17da79/visual/details-log.png", + "docs/evidence/analysis-history-401c5d17da79/visual/details-parameters.png", + "docs/evidence/analysis-history-401c5d17da79/visual/details-visual-receipt.json", + "docs/evidence/analysis-history-401c5d17da79/visual/details-visual.py", + "docs/evidence/analysis-history-401c5d17da79/visual/native-reopened-b.png", + "docs/operator/README.md", + "docs/receiving/analysis-history-ci-budget-401c5d17da79/README.md", + "docs/receiving/analysis-history-ci-budget-401c5d17da79/diagnostic-receipt.json", + "docs/receiving/analysis-history-ci-budget-401c5d17da79/diagnostic-windows-success.log", + "docs/receiving/analysis-history-ci-budget-401c5d17da79/original-windows-timeout.log", + "docs/receiving/analysis-history-ci-budget-401c5d17da79/retry-windows-timeout.log", + "tests/ui/test_analysis_history.py", + "tools/run_ci_tests.py" + ], + "gallery": [ + "desktop/capture_desktop/widgets_analysis_plots.py", + "docs/design/research/PROGRESS.md", + "docs/evidence/nested-figure-gallery-401c5d17da79/README.md", + "docs/evidence/nested-figure-gallery-401c5d17da79/artifact-manifest.json", + "docs/evidence/nested-figure-gallery-401c5d17da79/current-main70.json", + "docs/evidence/nested-figure-gallery-401c5d17da79/methods/receive_retained_gallery.py", + "docs/evidence/nested-figure-gallery-401c5d17da79/qualification/baseline-numeric-receipt.json", + "docs/evidence/nested-figure-gallery-401c5d17da79/qualification/containment-before-process.json", + "docs/evidence/nested-figure-gallery-401c5d17da79/qualification/containment-before.log", + "docs/evidence/nested-figure-gallery-401c5d17da79/qualification/license-sparse-process.json", + "docs/evidence/nested-figure-gallery-401c5d17da79/qualification/native-final-process.json", + "docs/evidence/nested-figure-gallery-401c5d17da79/qualification/native-final.log", + "docs/evidence/nested-figure-gallery-401c5d17da79/qualification/native-initial-process.json", + "docs/evidence/nested-figure-gallery-401c5d17da79/qualification/native-initial.log", + "docs/evidence/nested-figure-gallery-401c5d17da79/qualification/retained-final-process.json", + "docs/evidence/nested-figure-gallery-401c5d17da79/qualification/retained-final-receipt.json", + "docs/evidence/nested-figure-gallery-401c5d17da79/qualification/retained-initial-process.json", + "docs/evidence/nested-figure-gallery-401c5d17da79/qualification/retained-initial-receipt.json", + "docs/evidence/nested-figure-gallery-401c5d17da79/source-input.json", + "docs/evidence/nested-figure-gallery-401c5d17da79/visual/legacy-flat-figure.png", + "docs/evidence/nested-figure-gallery-401c5d17da79/visual/legacy-linked-plots.png", + "docs/evidence/nested-figure-gallery-401c5d17da79/visual/numeric-channel.png", + "docs/receiving/windows-nested-gallery-e46e74cdc4f4/.gitattributes", + "docs/receiving/windows-nested-gallery-e46e74cdc4f4/INDEPENDENT_RECEIVING.md", + "docs/receiving/windows-nested-gallery-e46e74cdc4f4/README.md", + "docs/receiving/windows-nested-gallery-e46e74cdc4f4/github-job-113430762650.log", + "docs/receiving/windows-nested-gallery-e46e74cdc4f4/manifest.json", + "docs/receiving/windows-nested-gallery-e46e74cdc4f4/native/process-completion.json", + "docs/receiving/windows-nested-gallery-e46e74cdc4f4/native/process-start.json", + "docs/receiving/windows-nested-gallery-e46e74cdc4f4/native/receipt.json", + "docs/receiving/windows-nested-gallery-e46e74cdc4f4/native/receive_windows_links.py", + "docs/receiving/windows-nested-gallery-e46e74cdc4f4/native/source-payload.json", + "docs/receiving/windows-nested-gallery-e46e74cdc4f4/root-review.json", + "docs/receiving/windows-nested-gallery-e46e74cdc4f4/test_analysis_nested_gallery.original.py", + "tests/ui/test_analysis_nested_gallery.py" + ] + }, + "shared": [ + "docs/design/research/PROGRESS.md" + ] +} diff --git a/docs/receiving/analysis-workspace-composition-401c5d17da79/current-9e920-source-review.json b/docs/receiving/analysis-workspace-composition-401c5d17da79/current-9e920-source-review.json new file mode 100644 index 00000000..67acc2a5 --- /dev/null +++ b/docs/receiving/analysis-workspace-composition-401c5d17da79/current-9e920-source-review.json @@ -0,0 +1,40 @@ +{ + "schema": "capture.analysis-current-source-composition/1", + "recorded_at": "2026-10-08T21:00:15.467595+00:00", + "qualified_native": "8bd83e18f12d1082c21b9cfcbe3d2e9cedf717a3", + "qualified_published": "5c7200a61fafa29ae4881e9274c82c2af24a714f", + "current_main": "9e9204f76b105426b0affaa74733175c052f27ba", + "current_tree": "a1b37ec1ab291a90cb2a383aa8f50b797ac09932", + "parents": [ + "5c7200a61fafa29ae4881e9274c82c2af24a714f", + "9e9204f76b105426b0affaa74733175c052f27ba" + ], + "resolved": [ + { + "path": "desktop/capture_desktop/screen_analysis.py", + "bytes": 21408, + "sha256": "a2b87b92bf0dd7de31a28ca47fc7e1e3b0a53662b6f17831a6cd8726b26a2e4a", + "git_blob": "b312929bca3cb5758ca857c3c51318b46ffb6f52" + }, + { + "path": "docs/design/research/PROGRESS.md", + "bytes": 78286, + "sha256": "5339ca6f783b26a74f2e82efcd5ae301d941e4bbbc21ea9b0a5e4427c61b4f4c", + "git_blob": "3007e06ecf19c2cc5e8cc81b2ac5f58ae2ebe997" + }, + { + "path": "tools/run_ci_tests.py", + "bytes": 7443, + "sha256": "058acad972ebf04c737fd1d97dae4f17b5f60a4dd050b30f48d0915773eb49cd", + "git_blob": "358ae41879427e03331699bf563d709407b20a41" + } + ], + "decision": [ + "Preserve the exact current busy block, including the external-prediction set_eval_busy hook. The shared retained-thread predicate matches both branches. All history hooks remain in the automatic merge.", + "Keep the complete current PROGRESS document, then the exact 3992-byte history/gallery append from the qualified composition.", + "The runner merges automatically. Its complete current bytes, including verbose progress and duration reporting, are unchanged after replacing only timeout=600 with timeout=300.", + "Keep current native Space button handling, control-scroll container, external prediction mode, literal chooser and named Windows workbench verifier. No production behavior is intentionally removed." + ], + "source_verification": "Both merged Python sources parse. Complete leaf/mode readback and current hosted Windows receiving remain required.", + "prior_native": "21/21 on the separately pinned a2c composition. The original source and test bytes, receipts and observed inspector row overlap stay preserved; no new native run is asserted for this current merge." +} diff --git a/docs/receiving/analysis-workspace-composition-401c5d17da79/fixture-manifest.json b/docs/receiving/analysis-workspace-composition-401c5d17da79/fixture-manifest.json new file mode 100644 index 00000000..d000d84f --- /dev/null +++ b/docs/receiving/analysis-workspace-composition-401c5d17da79/fixture-manifest.json @@ -0,0 +1,254 @@ +{ + "test_sources_history_compariso0/first \u03bc.mmsession/events/annotations.json": { + "sha256": "37517e5f3dc66819f61f5a7bb8ace1921282415f10551d2defa5c3eb0985b570", + "bytes": 3 + }, + "test_sources_history_compariso0/first \u03bc.mmsession/events/checkpoints.json": { + "sha256": "37517e5f3dc66819f61f5a7bb8ace1921282415f10551d2defa5c3eb0985b570", + "bytes": 3 + }, + "test_sources_history_compariso0/first \u03bc.mmsession/events/sync_anchors.json": { + "sha256": "37517e5f3dc66819f61f5a7bb8ace1921282415f10551d2defa5c3eb0985b570", + "bytes": 3 + }, + "test_sources_history_compariso0/first \u03bc.mmsession/integrity.json": { + "sha256": "64828d1836c01d154355917a0281acb093f582e04b75bff3c4421bc288b8f1a4", + "bytes": 1186 + }, + "test_sources_history_compariso0/first \u03bc.mmsession/manifest.json": { + "sha256": "77d52177df967781e855cb78ef991f680842582ebd988ded9c02e04b77a05a97", + "bytes": 242 + }, + "test_sources_history_compariso0/first \u03bc.mmsession/processing/jobs/20261008T201756Z_9b785559/features/_schema.json": { + "sha256": "4ba1fb81418cd9ce53568f52915398a0c3fa89415b29867442dd891ce10ee3c6", + "bytes": 2123 + }, + "test_sources_history_compariso0/first \u03bc.mmsession/processing/jobs/20261008T201756Z_9b785559/features/numeric/source-73616d706c65722e62/stream-74656d7065726174757265/windows.csv": { + "sha256": "4a97478272349a7a6dbfbfa15a60310501373a053c8efb148987448cde428f33", + "bytes": 401 + }, + "test_sources_history_compariso0/first \u03bc.mmsession/processing/jobs/20261008T201756Z_9b785559/features/numeric/source-73616d706c65722e62/stream-74656d7065726174757265/windows.parquet": { + "sha256": "f3474539ae5399f36bb979f7ce3ea7ad3de555e553763353f66ba382a0b0dae3", + "bytes": 4214 + }, + "test_sources_history_compariso0/first \u03bc.mmsession/processing/jobs/20261008T201756Z_9b785559/job_manifest.json": { + "sha256": "46ad00bafcb79aadab6c92e7ee433b97a5d521ed84d4e4803e7fa8933a5d22df", + "bytes": 3313 + }, + "test_sources_history_compariso0/first \u03bc.mmsession/processing/jobs/20261008T201756Z_9b785559/logs/job.log": { + "sha256": "5e554ec91b76b1110262b83bf891ff33ed82a335d9755105cfe1be88c7c5efa4", + "bytes": 220 + }, + "test_sources_history_compariso0/first \u03bc.mmsession/processing/jobs/20261008T201756Z_9b785559/params.json": { + "sha256": "b81f8da8f4a6c399c6aa884d7770fcd26630e2135ccc116d6824fe35b34d6c98", + "bytes": 264 + }, + "test_sources_history_compariso0/first \u03bc.mmsession/processing/jobs/20261008T201756Z_9b785559/reports/qc.html": { + "sha256": "3ad9e2bc5235a049f688c2b499c2c88343ea4d5e0997ec483565c5b0f980d873", + "bytes": 2368 + }, + "test_sources_history_compariso0/first \u03bc.mmsession/processing/jobs/20261008T201756Z_9b785559/reports/qc.json": { + "sha256": "135294466cba809b5cfb6e7195f4cc653a78afc518d1f1557311f9dbb226c879", + "bytes": 1646 + }, + "test_sources_history_compariso0/first \u03bc.mmsession/processing/jobs/retained-a/features/_schema.json": { + "sha256": "5ca5504a590df140267cd071e44fe7574542786c904fd417310299274eaa704b", + "bytes": 4139 + }, + "test_sources_history_compariso0/first \u03bc.mmsession/processing/jobs/retained-a/features/numeric/source-73616d706c65722e61/stream-666f726365/windows.csv": { + "sha256": "f2b965d97682cd7c53da3b0080a1c8cb3fa3d21b1f3e75200753cb9c285288f1", + "bytes": 341 + }, + "test_sources_history_compariso0/first \u03bc.mmsession/processing/jobs/retained-a/features/numeric/source-73616d706c65722e61/stream-666f726365/windows.parquet": { + "sha256": "bc2d49b74f36240aa70f8ab56ee72c0846428be6bd5a6f9406338d4f817a4c5a", + "bytes": 4214 + }, + "test_sources_history_compariso0/first \u03bc.mmsession/processing/jobs/retained-a/features/numeric/source-73616d706c65722e61/stream-766f6c74616765/windows.csv": { + "sha256": "871a48598c75f54b8b6b6d8fcc6995a11a930e3d92c2deba3ee6bd4c392fd316", + "bytes": 341 + }, + "test_sources_history_compariso0/first \u03bc.mmsession/processing/jobs/retained-a/features/numeric/source-73616d706c65722e61/stream-766f6c74616765/windows.parquet": { + "sha256": "44189482a3880f498cd89ce5f806c4bfdc3a6b4ea9f740dbedd36d7f88d4b8bc", + "bytes": 4214 + }, + "test_sources_history_compariso0/first \u03bc.mmsession/processing/jobs/retained-a/figures/numeric/source-73616d706c65722e61/stream-666f726365/channel_0.png": { + "sha256": "55eaaa67e218856432f9c42cc7c35cd956176862b6f18ac5b3a579475e3997fc", + "bytes": 60900 + }, + "test_sources_history_compariso0/first \u03bc.mmsession/processing/jobs/retained-a/figures/numeric/source-73616d706c65722e61/stream-766f6c74616765/channel_0.png": { + "sha256": "70d09942d4db4129ff82c98e82e9fce6928a1bdbe293854481b9dfedc24ace9d", + "bytes": 60299 + }, + "test_sources_history_compariso0/first \u03bc.mmsession/processing/jobs/retained-a/figures/sync_dashboard.png": { + "sha256": "5e4f287e2912967c65d7448efe64849e48c71f9abf7e4905467f293351bbf8b2", + "bytes": 78069 + }, + "test_sources_history_compariso0/first \u03bc.mmsession/processing/jobs/retained-a/figures/sync_dashboard_series.json": { + "sha256": "d2c87cd8fd3be0271eadf83ba8fbd8c2af4bbc9de8a6d18e892d9fe9e56427f0", + "bytes": 4482 + }, + "test_sources_history_compariso0/first \u03bc.mmsession/processing/jobs/retained-a/job_manifest.json": { + "sha256": "c921a8e0bcafffd7adaa4ce64b6aa0b8ad786d81ac101db28954410d109eda69", + "bytes": 4819 + }, + "test_sources_history_compariso0/first \u03bc.mmsession/processing/jobs/retained-a/logs/job.log": { + "sha256": "23d3c006ee9a1afaa9c5b503532589ebe9445697e75f09b759832d0ac196165c", + "bytes": 200 + }, + "test_sources_history_compariso0/first \u03bc.mmsession/processing/jobs/retained-a/params.json": { + "sha256": "e6191e9dc799876ba22a5e5c6f157cf0aea77875df7bb7e8ef53760f47d87f80", + "bytes": 267 + }, + "test_sources_history_compariso0/first \u03bc.mmsession/processing/jobs/retained-a/reports/qc.html": { + "sha256": "3ad9e2bc5235a049f688c2b499c2c88343ea4d5e0997ec483565c5b0f980d873", + "bytes": 2368 + }, + "test_sources_history_compariso0/first \u03bc.mmsession/processing/jobs/retained-a/reports/qc.json": { + "sha256": "135294466cba809b5cfb6e7195f4cc653a78afc518d1f1557311f9dbb226c879", + "bytes": 1646 + }, + "test_sources_history_compariso0/first \u03bc.mmsession/processing/jobs/retained-b/features/_schema.json": { + "sha256": "4ba1fb81418cd9ce53568f52915398a0c3fa89415b29867442dd891ce10ee3c6", + "bytes": 2123 + }, + "test_sources_history_compariso0/first \u03bc.mmsession/processing/jobs/retained-b/features/numeric/source-73616d706c65722e62/stream-74656d7065726174757265/windows.csv": { + "sha256": "4a97478272349a7a6dbfbfa15a60310501373a053c8efb148987448cde428f33", + "bytes": 401 + }, + "test_sources_history_compariso0/first \u03bc.mmsession/processing/jobs/retained-b/features/numeric/source-73616d706c65722e62/stream-74656d7065726174757265/windows.parquet": { + "sha256": "f3474539ae5399f36bb979f7ce3ea7ad3de555e553763353f66ba382a0b0dae3", + "bytes": 4214 + }, + "test_sources_history_compariso0/first \u03bc.mmsession/processing/jobs/retained-b/figures/numeric/source-73616d706c65722e62/stream-74656d7065726174757265/channel_0.png": { + "sha256": "b69e24eed498f0c0cdde2d34168562831784e58fc4ca80e339d211cfdb40f710", + "bytes": 62096 + }, + "test_sources_history_compariso0/first \u03bc.mmsession/processing/jobs/retained-b/figures/sync_dashboard.png": { + "sha256": "94c17b2647f415a8fe437262ac25edf42d38a76ae6a68269a4573f9b6fd7775b", + "bytes": 45853 + }, + "test_sources_history_compariso0/first \u03bc.mmsession/processing/jobs/retained-b/figures/sync_dashboard_series.json": { + "sha256": "7cc9d6bcc6b12f58fd082f59368de63daf23891241c0bc3ebfa96e170852ae90", + "bytes": 2366 + }, + "test_sources_history_compariso0/first \u03bc.mmsession/processing/jobs/retained-b/job_manifest.json": { + "sha256": "4f19f7da6e35f464559b1653ddf8cc4a8c3ab3e0529645f3a34a171a270aa2d1", + "bytes": 3951 + }, + "test_sources_history_compariso0/first \u03bc.mmsession/processing/jobs/retained-b/logs/job.log": { + "sha256": "ccb072557cc9c2af5914b199c5608502d0190ae90137b8dd1a42dfff4d2efd6b", + "bytes": 200 + }, + "test_sources_history_compariso0/first \u03bc.mmsession/processing/jobs/retained-b/params.json": { + "sha256": "ccbf5dbf306325be1b597065c2adec1158e90433cb1d691041cfcfbce82b065f", + "bytes": 267 + }, + "test_sources_history_compariso0/first \u03bc.mmsession/processing/jobs/retained-b/reports/qc.html": { + "sha256": "3ad9e2bc5235a049f688c2b499c2c88343ea4d5e0997ec483565c5b0f980d873", + "bytes": 2368 + }, + "test_sources_history_compariso0/first \u03bc.mmsession/processing/jobs/retained-b/reports/qc.json": { + "sha256": "135294466cba809b5cfb6e7195f4cc653a78afc518d1f1557311f9dbb226c879", + "bytes": 1646 + }, + "test_sources_history_compariso0/first \u03bc.mmsession/sources/folder-a/health/gaps.jsonl": { + "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "bytes": 0 + }, + "test_sources_history_compariso0/first \u03bc.mmsession/sources/folder-a/source.json": { + "sha256": "ded4b0b0994a6f370b23cea9d2182bfee6dc36525f7890e7f8e34519271ba4ab", + "bytes": 30 + }, + "test_sources_history_compariso0/first \u03bc.mmsession/sources/folder-a/streams/force/segments/000000.mcap": { + "sha256": "9467807bbd26f27129ab88b98d18365343c03c7a712fa7434fb234a7973f6400", + "bytes": 1540 + }, + "test_sources_history_compariso0/first \u03bc.mmsession/sources/folder-a/streams/force/stream.json": { + "sha256": "7b5f368f899b5e8d9b40265d8c9ada3e344f689c3185defabd8918334115f9a6", + "bytes": 317 + }, + "test_sources_history_compariso0/first \u03bc.mmsession/sources/folder-a/streams/voltage/segments/000000.mcap": { + "sha256": "08a2f0ae5432bf5117707e27297063ea65c727b51f1113a587c76a58ec50eeb5", + "bytes": 1542 + }, + "test_sources_history_compariso0/first \u03bc.mmsession/sources/folder-a/streams/voltage/stream.json": { + "sha256": "d9534fcd83e3539b38a4c471f912aadfdd4a7cd87d8069b69a8111741a737c01", + "bytes": 320 + }, + "test_sources_history_compariso0/first \u03bc.mmsession/sources/sampler.b/health/gaps.jsonl": { + "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "bytes": 0 + }, + "test_sources_history_compariso0/first \u03bc.mmsession/sources/sampler.b/source.json": { + "sha256": "51b11206a43ab0590baa31e0cf19b8f7194fac5875bc73f900f1417bd1d55b23", + "bytes": 30 + }, + "test_sources_history_compariso0/first \u03bc.mmsession/sources/sampler.b/streams/temperature/segments/000000.mcap": { + "sha256": "237560fe806bf7576bfe9723c09307038c01d9048d32a4a29f9b09711864c8c7", + "bytes": 1551 + }, + "test_sources_history_compariso0/first \u03bc.mmsession/sources/sampler.b/streams/temperature/stream.json": { + "sha256": "a6e2152bd7d97aa6fc3ca23175d84fdb898ce91803c2147de52dc2a9f76c051d", + "bytes": 323 + }, + "test_sources_history_compariso0/second \u03bc.mmsession/events/annotations.json": { + "sha256": "37517e5f3dc66819f61f5a7bb8ace1921282415f10551d2defa5c3eb0985b570", + "bytes": 3 + }, + "test_sources_history_compariso0/second \u03bc.mmsession/events/checkpoints.json": { + "sha256": "37517e5f3dc66819f61f5a7bb8ace1921282415f10551d2defa5c3eb0985b570", + "bytes": 3 + }, + "test_sources_history_compariso0/second \u03bc.mmsession/events/sync_anchors.json": { + "sha256": "37517e5f3dc66819f61f5a7bb8ace1921282415f10551d2defa5c3eb0985b570", + "bytes": 3 + }, + "test_sources_history_compariso0/second \u03bc.mmsession/integrity.json": { + "sha256": "64828d1836c01d154355917a0281acb093f582e04b75bff3c4421bc288b8f1a4", + "bytes": 1186 + }, + "test_sources_history_compariso0/second \u03bc.mmsession/manifest.json": { + "sha256": "77d52177df967781e855cb78ef991f680842582ebd988ded9c02e04b77a05a97", + "bytes": 242 + }, + "test_sources_history_compariso0/second \u03bc.mmsession/sources/folder-a/health/gaps.jsonl": { + "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "bytes": 0 + }, + "test_sources_history_compariso0/second \u03bc.mmsession/sources/folder-a/source.json": { + "sha256": "ded4b0b0994a6f370b23cea9d2182bfee6dc36525f7890e7f8e34519271ba4ab", + "bytes": 30 + }, + "test_sources_history_compariso0/second \u03bc.mmsession/sources/folder-a/streams/force/segments/000000.mcap": { + "sha256": "9467807bbd26f27129ab88b98d18365343c03c7a712fa7434fb234a7973f6400", + "bytes": 1540 + }, + "test_sources_history_compariso0/second \u03bc.mmsession/sources/folder-a/streams/force/stream.json": { + "sha256": "7b5f368f899b5e8d9b40265d8c9ada3e344f689c3185defabd8918334115f9a6", + "bytes": 317 + }, + "test_sources_history_compariso0/second \u03bc.mmsession/sources/folder-a/streams/voltage/segments/000000.mcap": { + "sha256": "08a2f0ae5432bf5117707e27297063ea65c727b51f1113a587c76a58ec50eeb5", + "bytes": 1542 + }, + "test_sources_history_compariso0/second \u03bc.mmsession/sources/folder-a/streams/voltage/stream.json": { + "sha256": "d9534fcd83e3539b38a4c471f912aadfdd4a7cd87d8069b69a8111741a737c01", + "bytes": 320 + }, + "test_sources_history_compariso0/second \u03bc.mmsession/sources/sampler.b/health/gaps.jsonl": { + "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "bytes": 0 + }, + "test_sources_history_compariso0/second \u03bc.mmsession/sources/sampler.b/source.json": { + "sha256": "51b11206a43ab0590baa31e0cf19b8f7194fac5875bc73f900f1417bd1d55b23", + "bytes": 30 + }, + "test_sources_history_compariso0/second \u03bc.mmsession/sources/sampler.b/streams/temperature/segments/000000.mcap": { + "sha256": "237560fe806bf7576bfe9723c09307038c01d9048d32a4a29f9b09711864c8c7", + "bytes": 1551 + }, + "test_sources_history_compariso0/second \u03bc.mmsession/sources/sampler.b/streams/temperature/stream.json": { + "sha256": "a6e2152bd7d97aa6fc3ca23175d84fdb898ce91803c2147de52dc2a9f76c051d", + "bytes": 323 + } +} diff --git a/docs/receiving/analysis-workspace-composition-401c5d17da79/junit.xml b/docs/receiving/analysis-workspace-composition-401c5d17da79/junit.xml new file mode 100644 index 00000000..333c1096 --- /dev/null +++ b/docs/receiving/analysis-workspace-composition-401c5d17da79/junit.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/receiving/analysis-workspace-composition-401c5d17da79/native-runtime-probe.json b/docs/receiving/analysis-workspace-composition-401c5d17da79/native-runtime-probe.json new file mode 100644 index 00000000..f8ef375f --- /dev/null +++ b/docs/receiving/analysis-workspace-composition-401c5d17da79/native-runtime-probe.json @@ -0,0 +1,11 @@ +{ + "argv": [ + "/home/jacob/hamon-capture-composition-f5c5ccd6-tools/venv/bin/python", + "-B", + "-c", + "import sys,importlib.metadata,json; print(json.dumps({'python':sys.version,'packages':{n:importlib.metadata.version(n) for n in ['PySide6','pyqtgraph','mcap','numpy','pandas','pyarrow','pytest']}}))" + ], + "exit": 0, + "stdout": "{\"python\": \"3.12.15 (main, Oct 3 2026, 01:03:07) [Clang 22.1.3 ]\", \"packages\": {\"PySide6\": \"6.12.0\", \"pyqtgraph\": \"0.14.0\", \"mcap\": \"1.5.0\", \"numpy\": \"2.5.3\", \"pandas\": \"3.0.6\", \"pyarrow\": \"25.0.1\", \"pytest\": \"9.1.1\"}}\n", + "stderr": "" +} diff --git a/docs/receiving/analysis-workspace-composition-401c5d17da79/process-completion.json b/docs/receiving/analysis-workspace-composition-401c5d17da79/process-completion.json new file mode 100644 index 00000000..da4ee795 --- /dev/null +++ b/docs/receiving/analysis-workspace-composition-401c5d17da79/process-completion.json @@ -0,0 +1,9 @@ +{ + "exit": 0, + "seconds": 54.87013101577759, + "source_unchanged": true, + "added": [], + "changed": [], + "head": "5b693a54f3323c6c7604f6ecd2feb6cf9c6040b1", + "tree": "31ad49114bffb0ff6d4a0b419e632f8e15cd2cb9" +} diff --git a/docs/receiving/analysis-workspace-composition-401c5d17da79/process-start.json b/docs/receiving/analysis-workspace-composition-401c5d17da79/process-start.json new file mode 100644 index 00000000..a2974d0a --- /dev/null +++ b/docs/receiving/analysis-workspace-composition-401c5d17da79/process-start.json @@ -0,0 +1,21 @@ +{ + "pid": 1247741, + "head": "5b693a54f3323c6c7604f6ecd2feb6cf9c6040b1", + "tree": "31ad49114bffb0ff6d4a0b419e632f8e15cd2cb9", + "runtime": "facb4af1d9277d88c233a54520b33d3c79cee174", + "argv": [ + "/home/jacob/hamon-capture-composition-f5c5ccd6-tools/venv/bin/python", + "-B", + "-m", + "pytest", + "tests/ui/test_analysis_workspace_composition.py", + "-q", + "-s", + "--maxfail=1", + "-p", + "no:cacheprovider", + "--basetemp=/dev/shm/hamon-401c5d17da79-capture-a2c/native-v1/tmp", + "--junitxml=/dev/shm/hamon-401c5d17da79-capture-a2c/native-v1/junit.xml" + ], + "source_files": 293 +} diff --git a/docs/receiving/analysis-workspace-composition-401c5d17da79/qualify-v1.py.txt b/docs/receiving/analysis-workspace-composition-401c5d17da79/qualify-v1.py.txt new file mode 100644 index 00000000..d015fa22 --- /dev/null +++ b/docs/receiving/analysis-workspace-composition-401c5d17da79/qualify-v1.py.txt @@ -0,0 +1,27 @@ +import pathlib,subprocess,json,hashlib,os,time +r=pathlib.Path('/dev/shm/hamon-401c5d17da79-capture-a2c');g=r/'source.git';source=r/'source' +def git(*a,input=None):return subprocess.check_output(['git','--git-dir',str(g),*a],input=input) +runtime='facb4af1d9277d88c233a54520b33d3c79cee174' +test='tests/ui/test_analysis_workspace_composition.py';data=(source/test).read_bytes() +git('read-tree',runtime) +blob=git('hash-object','-w','--stdin',input=data).decode().strip() +git('update-index','--add','--cacheinfo','100644',blob,test) +tree=git('write-tree').decode().strip() +head=git('-c','user.name=estate-401c5d17da79/production_discovery','-c','user.email=estate-401c5d17da79@hamon.local', + 'commit-tree',tree,'-p',runtime,input=b'Receive the composed analysis workspace through native Qt\n\nExercise real source-filtered MCAP output, held QThread completion across a package switch, saved-result reopen, parameter comparison and exact nested image pixels. Keep all production bytes fixed.\n').decode().strip() +git('update-ref','refs/heads/integration/analysis-workspace-a2c-401c5d17da79',head) +out=r/'native-v1';out.mkdir() +manifest={str(p.relative_to(source)):hashlib.sha256(p.read_bytes()).hexdigest() for p in source.rglob('*') if p.is_file()} +(r/'TEST-CANDIDATE.json').write_text(json.dumps({'head':head,'tree':tree,'runtime':runtime,'test_blob':blob,'test_sha256':hashlib.sha256(data).hexdigest(),'sources':manifest},indent=2)+'\n') +env=dict(os.environ);env.update(PYTHONDONTWRITEBYTECODE='1',QT_QPA_PLATFORM='offscreen',MPLBACKEND='Agg', + MPLCONFIGDIR=str(out/'mpl-cache'),CAPTURE_ANALYSIS_COMPOSITION_EVIDENCE=str(out/'evidence'), + PYTHONPATH=os.pathsep.join([str(source),str(source/'desktop')]+[str(p) for p in (source/'libs/python').iterdir() if p.is_dir()])) +argv=['/home/jacob/hamon-capture-composition-f5c5ccd6-tools/venv/bin/python','-B','-m','pytest',test,'-q','-s','--maxfail=1','-p','no:cacheprovider','--basetemp='+str(out/'tmp'),'--junitxml='+str(out/'junit.xml')] +started=time.time() +with (out/'stdout.log').open('x') as stdout,(out/'stderr.log').open('x') as stderr: + proc=subprocess.Popen(argv,cwd=source,env=env,stdout=stdout,stderr=stderr) + (out/'process-start.json').write_text(json.dumps({'pid':proc.pid,'head':head,'tree':tree,'runtime':runtime,'argv':argv,'source_files':len(manifest)},indent=2)+'\n') + status=proc.wait(timeout=240) +after={str(p.relative_to(source)):hashlib.sha256(p.read_bytes()).hexdigest() for p in source.rglob('*') if p.is_file()} +(out/'process-completion.json').write_text(json.dumps({'exit':status,'seconds':time.time()-started,'source_unchanged':manifest==after,'added':sorted(set(after)-set(manifest)),'changed':[p for p in manifest if manifest[p]!=after.get(p)],'head':head,'tree':tree},indent=2)+'\n') +print(json.dumps({'head':head,'tree':tree,'exit':status,'seconds':time.time()-started,'source_unchanged':manifest==after})) diff --git a/docs/receiving/analysis-workspace-composition-401c5d17da79/real-mcap-fixtures.tar.gz b/docs/receiving/analysis-workspace-composition-401c5d17da79/real-mcap-fixtures.tar.gz new file mode 100644 index 00000000..66a9ea1f Binary files /dev/null and b/docs/receiving/analysis-workspace-composition-401c5d17da79/real-mcap-fixtures.tar.gz differ diff --git a/docs/receiving/analysis-workspace-composition-401c5d17da79/receipt.json b/docs/receiving/analysis-workspace-composition-401c5d17da79/receipt.json new file mode 100644 index 00000000..9789a485 --- /dev/null +++ b/docs/receiving/analysis-workspace-composition-401c5d17da79/receipt.json @@ -0,0 +1,152 @@ +{ + "checks": [ + { + "name": "actual source-filtered retained jobs contain nested numeric figures", + "passed": true, + "details": null + }, + { + "name": "history binds the retained job to the gallery and comparison inspector", + "passed": true, + "details": null + }, + { + "name": "retained parameters can be opened from the history-loaded inspector", + "passed": true, + "details": null + }, + { + "name": "run owns the source snapshot and disables history before thread startup", + "passed": true, + "details": null + }, + { + "name": "starting an actual job clears all previously loaded result associations", + "passed": true, + "details": null + }, + { + "name": "future source selection refresh cannot re-enable busy history controls", + "passed": true, + "details": null + }, + { + "name": "the real persisted job used the selected source snapshot", + "passed": true, + "details": { + "job": "20261008T201756Z_9b785559", + "params_sources": [ + "sampler.b" + ] + } + }, + { + "name": "written output does not release busy controls before QThread cleanup", + "passed": true, + "details": null + }, + { + "name": "package change clears history, figures and comparison while resetting sources", + "passed": true, + "details": null + }, + { + "name": "late source-filtered completion stays unbound to the current package", + "passed": true, + "details": null + }, + { + "name": "real worker completed without a failure dialog", + "passed": true, + "details": [] + }, + { + "name": "returning to the original package reopens the actual late result", + "passed": true, + "details": null + }, + { + "name": "comparison reads the current producer's exact source parameters", + "passed": true, + "details": { + "/command": [ + "\"all\"", + "\"features\"" + ], + "/overwriteJobId": [ + "\"retained-a\"", + "null" + ], + "/sources/0": [ + "\"sampler.a\"", + "\"sampler.b\"" + ] + } + }, + { + "name": "opening another retained job clears the previous comparison dialog", + "passed": true, + "details": null + }, + { + "name": "reopened nested gallery identifies exactly the selected-source figures", + "passed": true, + "details": [ + "numeric/source-73616d706c65722e61/stream-666f726365/channel_0.png", + "numeric/source-73616d706c65722e61/stream-766f6c74616765/channel_0.png" + ] + }, + { + "name": "both reopened image widgets retain the exact actual saved pixels", + "passed": true, + "details": null + }, + { + "name": "gallery navigation preserves the independent future source choice", + "passed": true, + "details": null + }, + { + "name": "the replacement inspector opens only its own parameter source", + "passed": true, + "details": null + }, + { + "name": "another package switch clears the current comparison and gallery together", + "passed": true, + "details": null + }, + { + "name": "all saved jobs and raw bytes remain unchanged through history and comparison", + "passed": true, + "details": null + }, + { + "name": "receiving view actions never start a second analysis job", + "passed": true, + "details": null + } + ], + "passed": 21, + "failed": 0, + "worker_calls": [ + { + "package": "/dev/shm/hamon-401c5d17da79-capture-a2c/native-v1/tmp/test_sources_history_compariso0/first μ.mmsession", + "params": { + "command": "features", + "gapPolicy": "mask", + "maxRamBytes": 2147483648, + "startSessionNs": null, + "endSessionNs": null, + "sources": [ + "sampler.b" + ], + "applySyncAnchors": false, + "overwriteJobId": null, + "checkpointSection": null, + "extra": {} + } + } + ], + "methodology": "Real numeric MCAP jobs and QThread; receiver holds only the return of an already-persisted real feature job. Native Qt event loop, unchanged source chooser and history Open buttons, unchanged comparison read action." +} diff --git a/docs/receiving/analysis-workspace-composition-401c5d17da79/stderr.log b/docs/receiving/analysis-workspace-composition-401c5d17da79/stderr.log new file mode 100644 index 00000000..ca300910 --- /dev/null +++ b/docs/receiving/analysis-workspace-composition-401c5d17da79/stderr.log @@ -0,0 +1,8 @@ +This plugin does not support propagateSizeHints() +This plugin does not support propagateSizeHints() +This plugin does not support propagateSizeHints() +This plugin does not support propagateSizeHints() +This plugin does not support propagateSizeHints() +This plugin does not support propagateSizeHints() +This plugin does not support propagateSizeHints() +This plugin does not support propagateSizeHints() diff --git a/docs/receiving/analysis-workspace-composition-401c5d17da79/stdout.log b/docs/receiving/analysis-workspace-composition-401c5d17da79/stdout.log new file mode 100644 index 00000000..febb153d --- /dev/null +++ b/docs/receiving/analysis-workspace-composition-401c5d17da79/stdout.log @@ -0,0 +1,10 @@ +. +=============================== warnings summary =============================== +tests/ui/test_analysis_workspace_composition.py::test_sources_history_comparison_and_gallery_share_package_lifetime + :488: DeprecationWarning: Type google._upb._message.MessageMapContainer uses PyType_Spec with a metaclass that has custom tp_new. This is deprecated and will no longer be allowed in Python 3.14. + +tests/ui/test_analysis_workspace_composition.py::test_sources_history_comparison_and_gallery_share_package_lifetime + :488: DeprecationWarning: Type google._upb._message.ScalarMapContainer uses PyType_Spec with a metaclass that has custom tp_new. This is deprecated and will no longer be allowed in Python 3.14. + +-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html +1 passed, 2 warnings in 46.01s diff --git a/docs/receiving/analysis-workspace-composition-401c5d17da79/test-authored.json b/docs/receiving/analysis-workspace-composition-401c5d17da79/test-authored.json new file mode 100644 index 00000000..0cc8e0ec --- /dev/null +++ b/docs/receiving/analysis-workspace-composition-401c5d17da79/test-authored.json @@ -0,0 +1,7 @@ +{ + "path": "/dev/shm/hamon-401c5d17da79-capture-a2c/source/tests/ui/test_analysis_workspace_composition.py", + "sha256": "418df81218407151318f17ab3e1da8d3b7eacc0e8664ed7cfe1dc3daf6732476", + "runtime": "facb4af1d9277d88c233a54520b33d3c79cee174", + "new_tests": 1, + "production_changed": false +} diff --git a/docs/receiving/analysis-workspace-composition-401c5d17da79/visual-review.json b/docs/receiving/analysis-workspace-composition-401c5d17da79/visual-review.json new file mode 100644 index 00000000..0db19143 --- /dev/null +++ b/docs/receiving/analysis-workspace-composition-401c5d17da79/visual-review.json @@ -0,0 +1,5 @@ +{ + "frame": "composed-history-gallery.png", + "review": "The actual frame shows saved-job history, current source selector, both nested channel tabs, linked plots, selected-figure export and Parameters / compare together. Long incumbent output rows overlap in this immediate single frame; it does not establish full-pane readability or attribute a new regression. Functional source/pixel assertions are independently recorded. No runtime modification or further run followed this observation.", + "no_new_visual_acceptance": true +} diff --git a/docs/receiving/windows-nested-gallery-e46e74cdc4f4/.gitattributes b/docs/receiving/windows-nested-gallery-e46e74cdc4f4/.gitattributes new file mode 100644 index 00000000..c804d578 --- /dev/null +++ b/docs/receiving/windows-nested-gallery-e46e74cdc4f4/.gitattributes @@ -0,0 +1 @@ +github-job-113430762650.log -text diff --git a/docs/receiving/windows-nested-gallery-e46e74cdc4f4/INDEPENDENT_RECEIVING.md b/docs/receiving/windows-nested-gallery-e46e74cdc4f4/INDEPENDENT_RECEIVING.md new file mode 100644 index 00000000..86d28b63 --- /dev/null +++ b/docs/receiving/windows-nested-gallery-e46e74cdc4f4/INDEPENDENT_RECEIVING.md @@ -0,0 +1,70 @@ +# Independent receiving: CaptureSuite PR80 Windows link assertion + +## Result + +Accept the narrow test correction at candidate Git blob `746084780e126b103489902f119b8e46c2fd8c98` for integration through the existing PR80 owner's branch. The candidate establishes that the newly created link refers to the intended fixture file, captures the filesystem's actual stored target, then requires that target to remain exactly unchanged after the gallery call. + +This receiving does not mark the whole PR green. The required updated-head hosted suite remains pending. No Qt/gallery invocation or Python 3.12 execution was performed in this native receiver. + +## Actual hosted baseline + +- Repository: `Jacob-Met/CaptureSuite` +- PR: [80](https://github.com/Jacob-Met/CaptureSuite/pull/80) +- Head: `bd390a9d497e567cd868ba4029b74bbd509b4a78` +- Hosted merge checkout: `e0a45debe5e2a331ba5aee242ac985c9f604b31b` +- Run: [37811945519](https://github.com/Jacob-Met/CaptureSuite/actions/runs/37811945519) +- Python job: [113430762650](https://github.com/Jacob-Met/CaptureSuite/actions/runs/37811945519/job/113430762650) +- Python 3.12.10 / Windows: **545 passed, 6 skipped, 1 failed**, 252.87 seconds. +- The six skips explicitly concern the unbuilt `capture_daemon.exe` in that Python leg. +- Ruff and license checks passed. The distinct CMake check `113430763041` completed successfully. +- The only Python failure was `tests/ui/test_analysis_nested_gallery.py::test_png_discovery_refuses_external_file_links_and_directories`, at `assert foreign.readlink() == outside`. Its preceding gallery title, pixel, and relative-path assertions had passed. +- The unchanged link's returned spelling has Windows' extended-length prefix (`\\?\\`), whereas the authored `Path` does not. Comparing these lexical representations is not a valid unchanged-link assertion. +- Complete fetched job-log content is retained at `github-job-113430762650.log`: **57,921 bytes**, SHA256 `e9bbc99cb596b4016de2cfa7ab0729d8daff846e6e97459a8f2dec11af93a074`. Original CRLF bytes were preserved. + +## Exact source identities + +| Source | Git blob | Bytes | SHA256 | +| --- | --- | ---: | --- | +| Original test | `0874d6b51b22cbbeaa8b1e309ed92418efcec2c6` | 7,142 | `727340556a0d8e4178b62157ba9680a59d1c43158abb1bf979b21be8c98c591f` | +| Root's candidate test | `746084780e126b103489902f119b8e46c2fd8c98` | 7,291 | `566ff56a05014d47ffd887976751c06f259957a908ec34528725a039269b434f` | +| Unchanged gallery | `28e907de7c7c9a7945249796b61b325853f6de88` | 10,821 | `002327b8e6303412269c0ca8c4a105d9e8eeb96491eec0836e39ce199e2c18fd` | + +The receiver hashes the full original and candidate test bytes to both their Git blob identities and SHA256 before invoking any extracted statement. It uses the exact AST statements for the original assertion, candidate identity/capture guard, and candidate preservation assertion. All other AST nodes in the affected test function compare equal. Full original/candidate source bytes remain unchanged after receiving. + +## Native receiving + +The actual authorized LA7 Windows surface executed the receiver with existing Python **3.11.9**, platform **Windows-10-10.0.19045-SP0**, on **2026-10-08 at 17:16:44 UTC**. Process **50068** completed with exit **0** in **0.32 seconds**. + +The native fixture creates only owned disposable files. There is no substituted gallery, stub Qt result, installed-service call, or change to another worker's workspace. + +| Case | Actual result | +| --- | --- | +| Original assertion on a real absolute Windows link | Fails with `AssertionError`; `samefile(outside)` is true and the returned target has the extended-length prefix. | +| Candidate statements on the unchanged absolute link | Identity guard and exact stored-target assertion pass. | +| Candidate statements on an unchanged relative link | Identity guard and exact stored-target assertion pass; original relative spelling remains retained. | +| Link retargeted to a different file with identical bytes | Candidate preservation assertion rejects the changed target. | +| Link replaced by a regular file with identical bytes | Candidate preservation assertion rejects with Windows error 4390. | +| Initially wrong link target with identical bytes | Candidate identity guard rejects before the notional gallery boundary. | + +Healthy fixture target bytes and exact original/candidate source bytes were checked unchanged. + +## Retained native evidence + +Native workspace: + +`C:\Users\minec\hamon-cs80-receiving-e46e74cdc4f4` + +The completed run remains under `native-20261008T171644Z` there, alongside exact source copies and the original authored fixtures. It is an isolated receiving workspace; no shared cleanup was performed. + +- `native/receipt.json`: **2,981 bytes**, SHA256 `a47567302f0e0b5b3cf2b205527856aaa1d1a5d48e87ba4d2c22d20027afab48`. +- `native/receive_windows_links.py`: **6,850 bytes**, SHA256 `314a5b53ec2ac56a05a57f0ff6ba7e29a7f49a048ec5ab65adf1c160e5cfba9b`. +- `native/process-start.json` and `native/process-completion.json` retain the tool-reported output and successful exit. +- Exact native receipt and receiver bytes were copied back through base64 and independently checked against their native byte counts and hashes. + +One initial source-payload write failed because the new receiving directory did not yet exist. The directory was then created normally and the write succeeded; no fixture or test had run at the time of that setup error. + +## Ownership and remaining gate + +Original product owner remains `estate-401c5d17da79`, claim CaptureSuite #64, PR80 branch `fix/nested-figure-gallery-401c5d17da79`. This packet qualifies only the narrow portability correction in that contribution's test. It does not take ownership of the gallery implementation, history/export behavior, native deployment, or final integration. + +The owner route must preserve its current source and evidence, apply the exact correction, and receive the unchanged hosted platform gates on the resulting proposed head. The successful native fixture result cannot substitute for that full updated-head hosted gate. diff --git a/docs/receiving/windows-nested-gallery-e46e74cdc4f4/README.md b/docs/receiving/windows-nested-gallery-e46e74cdc4f4/README.md new file mode 100644 index 00000000..3f6dd4a5 --- /dev/null +++ b/docs/receiving/windows-nested-gallery-e46e74cdc4f4/README.md @@ -0,0 +1,15 @@ +# Windows nested-gallery test receiving + +[Independent receiving](INDEPENDENT_RECEIVING.md) records the exact source, failed hosted baseline, actual Windows assertion runs, negative controls and remaining hosted gate. + +## Reproduce the filesystem witness + +On Windows with Python 3.11 or later, copy the complete native directory to a new disposable receiving workspace and run: + +~~~powershell +py -3.11 receive_windows_links.py +~~~ + +The receiver uses the accompanying source-payload.json to reconstruct and hash both exact source versions, then executes their affected assertion statements against real links. It creates a new timestamped directory for each run. This is a filesystem assertion witness; it does not import Qt or invoke the gallery, and it cannot replace the required proposed-head Python 3.12 platform suite. + +Original raw evidence remains unchanged. The raw hosted log is explicitly marked non-text for Git so its original CRLF content is retained. diff --git a/docs/receiving/windows-nested-gallery-e46e74cdc4f4/github-job-113430762650.log b/docs/receiving/windows-nested-gallery-e46e74cdc4f4/github-job-113430762650.log new file mode 100644 index 00000000..79e771d1 --- /dev/null +++ b/docs/receiving/windows-nested-gallery-e46e74cdc4f4/github-job-113430762650.log @@ -0,0 +1,599 @@ +2026-10-08T16:50:45.4210704Z Current runner version: '2.337.0' +2026-10-08T16:50:45.4235214Z ##[group]Runner Image Provisioner +2026-10-08T16:50:45.4236031Z Hosted Compute Agent +2026-10-08T16:50:45.4236535Z Version: 20261002.596 +2026-10-08T16:50:45.4237079Z Commit: c3d12f3313a95f25162a1503be624f3b0617f8c0 +2026-10-08T16:50:45.4237775Z Build Date: 2026-10-02T22:28:27Z +2026-10-08T16:50:45.4238411Z Worker ID: {c48cee9f-7b8e-4cb1-bcca-a69b9e2ada57} +2026-10-08T16:50:45.4239079Z Region: westus3 +2026-10-08T16:50:45.4239558Z Cloud: Azure +2026-10-08T16:50:45.4240008Z ##[endgroup] +2026-10-08T16:50:45.4241269Z ##[group]Operating System +2026-10-08T16:50:45.4241838Z Microsoft Windows Server 2022 +2026-10-08T16:50:45.4242379Z 10.0.20348 +2026-10-08T16:50:45.4242837Z Datacenter +2026-10-08T16:50:45.4243281Z ##[endgroup] +2026-10-08T16:50:45.4243751Z ##[group]Runner Image +2026-10-08T16:50:45.4244264Z Image: windows-2022 +2026-10-08T16:50:45.4244751Z Version: 20261004.326.1 +2026-10-08T16:50:45.4246129Z Included Software: https://github.com/actions/runner-images/blob/win22/20261004.326/images/windows/Windows2022-Readme.md +2026-10-08T16:50:45.4247563Z Image Release: https://github.com/actions/runner-images/releases/tag/win22%2F20261004.326 +2026-10-08T16:50:45.4248387Z ##[endgroup] +2026-10-08T16:50:45.4249484Z ##[group]GITHUB_TOKEN Permissions +2026-10-08T16:50:45.4251349Z Contents: read +2026-10-08T16:50:45.4251876Z Metadata: read +2026-10-08T16:50:45.4252337Z Packages: read +2026-10-08T16:50:45.4252808Z ##[endgroup] +2026-10-08T16:50:45.4254837Z Secret source: Actions +2026-10-08T16:50:45.4255652Z Cache mode: write +2026-10-08T16:50:45.4256266Z Prepare workflow directory +2026-10-08T16:50:45.4637236Z Prepare all required actions +2026-10-08T16:50:45.4706258Z Getting action download info +2026-10-08T16:50:45.8292788Z Download action repository 'actions/checkout@v4' (SHA:11d5960a326750d5838078e36cf38b85af677262) +2026-10-08T16:50:45.9735031Z Download action repository 'actions/setup-python@v5' (SHA:a26af69be951a213d495a4c3e4e4022e16d87065) +2026-10-08T16:50:46.1907980Z Download action repository 'actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a' (SHA:043fb46d1a93c77aae656e7c1c64a875d1fc6a0a) +2026-10-08T16:50:46.4118396Z Complete job name: python +2026-10-08T16:50:46.5862269Z ##[group]Run actions/checkout@v4 +2026-10-08T16:50:46.5863342Z with: +2026-10-08T16:50:46.5863730Z repository: Jacob-Met/CaptureSuite +2026-10-08T16:50:46.5867344Z token: *** +2026-10-08T16:50:46.5867696Z ssh-strict: true +2026-10-08T16:50:46.5868056Z ssh-user: git +2026-10-08T16:50:46.5868421Z persist-credentials: true +2026-10-08T16:50:46.5868824Z clean: true +2026-10-08T16:50:46.5869201Z sparse-checkout-cone-mode: true +2026-10-08T16:50:46.5869648Z fetch-depth: 1 +2026-10-08T16:50:46.5870012Z fetch-tags: false +2026-10-08T16:50:46.5870381Z show-progress: true +2026-10-08T16:50:46.5870748Z lfs: false +2026-10-08T16:50:46.5871089Z submodules: false +2026-10-08T16:50:46.5871466Z set-safe-directory: true +2026-10-08T16:50:46.5871895Z allow-unsafe-pr-checkout: false +2026-10-08T16:50:46.5872586Z ##[endgroup] +2026-10-08T16:50:46.7297989Z Syncing repository: Jacob-Met/CaptureSuite +2026-10-08T16:50:46.7299624Z ##[group]Getting Git version info +2026-10-08T16:50:46.7300292Z Working directory is 'D:\a\CaptureSuite\CaptureSuite' +2026-10-08T16:50:46.8126119Z [command]"C:\Program Files\Git\bin\git.exe" version +2026-10-08T16:50:47.1225306Z git version 2.56.0.windows.1 +2026-10-08T16:50:47.1283004Z ##[endgroup] +2026-10-08T16:50:47.1302763Z Temporarily overriding HOME='D:\a\_temp\f684de22-d6ff-46f2-bc9a-b7e627ea0749' before making global git config changes +2026-10-08T16:50:47.1304173Z Adding repository directory to the temporary git global config as a safe directory +2026-10-08T16:50:47.1321247Z [command]"C:\Program Files\Git\bin\git.exe" config --global --add safe.directory D:\a\CaptureSuite\CaptureSuite +2026-10-08T16:50:47.1871905Z Deleting the contents of 'D:\a\CaptureSuite\CaptureSuite' +2026-10-08T16:50:47.1876833Z ##[group]Initializing the repository +2026-10-08T16:50:47.1886461Z [command]"C:\Program Files\Git\bin\git.exe" init D:\a\CaptureSuite\CaptureSuite +2026-10-08T16:50:47.2676056Z Initialized empty Git repository in D:/a/CaptureSuite/CaptureSuite/.git/ +2026-10-08T16:50:47.2719501Z [command]"C:\Program Files\Git\bin\git.exe" remote add origin https://github.com/Jacob-Met/CaptureSuite +2026-10-08T16:50:47.3297906Z ##[endgroup] +2026-10-08T16:50:47.3299446Z ##[group]Disabling automatic garbage collection +2026-10-08T16:50:47.3306146Z [command]"C:\Program Files\Git\bin\git.exe" config --local gc.auto 0 +2026-10-08T16:50:47.3604666Z ##[endgroup] +2026-10-08T16:50:47.3606096Z ##[group]Setting up auth +2026-10-08T16:50:47.3616747Z [command]"C:\Program Files\Git\bin\git.exe" config --local --name-only --get-regexp core\.sshCommand +2026-10-08T16:50:47.3917773Z [command]"C:\Program Files\Git\bin\git.exe" submodule foreach --recursive "sh -c \"git config --local --name-only --get-regexp 'core\.sshCommand' && git config --local --unset-all 'core.sshCommand' || :\"" +2026-10-08T16:50:48.6925271Z [command]"C:\Program Files\Git\bin\git.exe" config --local --name-only --get-regexp http\.https\:\/\/github\.com\/\.extraheader +2026-10-08T16:50:48.7229471Z [command]"C:\Program Files\Git\bin\git.exe" submodule foreach --recursive "sh -c \"git config --local --name-only --get-regexp 'http\.https\:\/\/github\.com\/\.extraheader' && git config --local --unset-all 'http.https://github.com/.extraheader' || :\"" +2026-10-08T16:50:49.4066511Z [command]"C:\Program Files\Git\bin\git.exe" config --local --name-only --get-regexp ^includeIf\.gitdir: +2026-10-08T16:50:49.4365311Z [command]"C:\Program Files\Git\bin\git.exe" submodule foreach --recursive "git config --local --show-origin --name-only --get-regexp remote.origin.url" +2026-10-08T16:50:49.9086410Z [command]"C:\Program Files\Git\bin\git.exe" config --local http.https://github.com/.extraheader "AUTHORIZATION: basic ***" +2026-10-08T16:50:49.9396564Z ##[endgroup] +2026-10-08T16:50:49.9397418Z ##[group]Fetching the repository +2026-10-08T16:50:49.9413113Z [command]"C:\Program Files\Git\bin\git.exe" -c protocol.version=2 fetch --no-tags --prune --no-recurse-submodules --depth=1 origin +e0a45debe5e2a331ba5aee242ac985c9f604b31b:refs/remotes/pull/80/merge +2026-10-08T16:50:51.5200194Z From https://github.com/Jacob-Met/CaptureSuite +2026-10-08T16:50:51.5201120Z * [new ref] e0a45debe5e2a331ba5aee242ac985c9f604b31b -> pull/80/merge +2026-10-08T16:50:51.5237919Z ##[endgroup] +2026-10-08T16:50:51.5238551Z ##[group]Determining the checkout info +2026-10-08T16:50:51.5240905Z ##[endgroup] +2026-10-08T16:50:51.5249927Z [command]"C:\Program Files\Git\bin\git.exe" sparse-checkout disable +2026-10-08T16:50:51.5703410Z [command]"C:\Program Files\Git\bin\git.exe" config --local --unset-all extensions.worktreeConfig +2026-10-08T16:50:51.5992781Z ##[group]Checking out the ref +2026-10-08T16:50:51.6001697Z [command]"C:\Program Files\Git\bin\git.exe" checkout --progress --force refs/remotes/pull/80/merge +2026-10-08T16:50:51.8495563Z Note: switching to 'refs/remotes/pull/80/merge'. +2026-10-08T16:50:51.8496969Z +2026-10-08T16:50:51.8497202Z You are in 'detached HEAD' state. You can look around, make experimental +2026-10-08T16:50:51.8497853Z changes and commit them, and you can discard any commits you make in this +2026-10-08T16:50:51.8498297Z state without impacting any branches by switching back to a branch. +2026-10-08T16:50:51.8498569Z +2026-10-08T16:50:51.8498757Z If you want to create a new branch to retain commits you create, you may +2026-10-08T16:50:51.8499287Z do so (now or later) by using -c with the switch command. Example: +2026-10-08T16:50:51.8499518Z +2026-10-08T16:50:51.8499683Z git switch -c +2026-10-08T16:50:51.8499980Z +2026-10-08T16:50:51.8500113Z Or undo this operation with: +2026-10-08T16:50:51.8500337Z +2026-10-08T16:50:51.8500412Z git switch - +2026-10-08T16:50:51.8500524Z +2026-10-08T16:50:51.8500716Z Turn off this advice by setting config variable advice.detachedHead to false +2026-10-08T16:50:51.8502017Z +2026-10-08T16:50:51.8502353Z HEAD is now at e0a45de Merge bd390a9d497e567cd868ba4029b74bbd509b4a78 into 3cbb5300bdc79c157370d1b3e599a6c82752d54a +2026-10-08T16:50:51.8569008Z ##[endgroup] +2026-10-08T16:50:51.8951186Z [command]"C:\Program Files\Git\bin\git.exe" log -1 --format=%H +2026-10-08T16:50:51.9228557Z e0a45debe5e2a331ba5aee242ac985c9f604b31b +2026-10-08T16:50:51.9660730Z ##[group]Run actions/setup-python@v5 +2026-10-08T16:50:51.9661100Z with: +2026-10-08T16:50:51.9661305Z python-version: 3.12 +2026-10-08T16:50:51.9661521Z check-latest: false +2026-10-08T16:50:51.9663804Z token: *** +2026-10-08T16:50:51.9664015Z update-environment: true +2026-10-08T16:50:51.9664253Z allow-prereleases: false +2026-10-08T16:50:51.9664463Z freethreaded: false +2026-10-08T16:50:51.9664664Z ##[endgroup] +2026-10-08T16:50:52.1208694Z ##[group]Installed versions +2026-10-08T16:50:52.1475222Z (node:3692) [DEP0040] DeprecationWarning: The `punycode` module is deprecated. Please use a userland alternative instead. +2026-10-08T16:50:52.1476062Z (Use `node --trace-deprecation ...` to show where the warning was created) +2026-10-08T16:50:52.1477324Z Successfully set up CPython (3.12.10) +2026-10-08T16:50:52.1478342Z ##[endgroup] +2026-10-08T16:50:52.1779601Z ##[group]Run python -m pip install -r requirements-ci.txt +2026-10-08T16:50:52.1780185Z python -m pip install -r requirements-ci.txt +2026-10-08T16:50:52.1880845Z shell: C:\Program Files\PowerShell\7\pwsh.EXE -command ". '{0}'" +2026-10-08T16:50:52.1881210Z env: +2026-10-08T16:50:52.1881485Z pythonLocation: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:50:52.1881949Z PKG_CONFIG_PATH: C:\hostedtoolcache\windows\Python\3.12.10\x64/lib/pkgconfig +2026-10-08T16:50:52.1882374Z Python_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:50:52.1882752Z Python2_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:50:52.1883119Z Python3_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:50:52.1883446Z ##[endgroup] +2026-10-08T16:51:04.5928818Z Obtaining file:///D:/a/CaptureSuite/CaptureSuite/libs/python/capture_protocol (from -r requirements-ci.txt (line 3)) +2026-10-08T16:51:04.5955827Z Installing build dependencies: started +2026-10-08T16:51:07.4378324Z Installing build dependencies: finished with status 'done' +2026-10-08T16:51:07.4395020Z Checking if build backend supports build_editable: started +2026-10-08T16:51:08.0311464Z Checking if build backend supports build_editable: finished with status 'done' +2026-10-08T16:51:08.0336471Z Getting requirements to build editable: started +2026-10-08T16:51:08.5557979Z Getting requirements to build editable: finished with status 'done' +2026-10-08T16:51:08.5583430Z Preparing editable metadata (pyproject.toml): started +2026-10-08T16:51:08.8619437Z Preparing editable metadata (pyproject.toml): finished with status 'done' +2026-10-08T16:51:08.8658661Z Obtaining file:///D:/a/CaptureSuite/CaptureSuite/libs/python/capture_session (from -r requirements-ci.txt (line 4)) +2026-10-08T16:51:08.8682170Z Installing build dependencies: started +2026-10-08T16:51:10.3876651Z Installing build dependencies: finished with status 'done' +2026-10-08T16:51:10.3890170Z Checking if build backend supports build_editable: started +2026-10-08T16:51:10.8391878Z Checking if build backend supports build_editable: finished with status 'done' +2026-10-08T16:51:10.8416051Z Getting requirements to build editable: started +2026-10-08T16:51:11.4285325Z Getting requirements to build editable: finished with status 'done' +2026-10-08T16:51:11.4311638Z Preparing editable metadata (pyproject.toml): started +2026-10-08T16:51:11.7329200Z Preparing editable metadata (pyproject.toml): finished with status 'done' +2026-10-08T16:51:11.7368252Z Obtaining file:///D:/a/CaptureSuite/CaptureSuite/libs/python/capture_analysis +2026-10-08T16:51:11.7392097Z Installing build dependencies: started +2026-10-08T16:51:13.4070984Z Installing build dependencies: finished with status 'done' +2026-10-08T16:51:13.4087585Z Checking if build backend supports build_editable: started +2026-10-08T16:51:13.8575081Z Checking if build backend supports build_editable: finished with status 'done' +2026-10-08T16:51:13.8594270Z Getting requirements to build editable: started +2026-10-08T16:51:14.3634119Z Getting requirements to build editable: finished with status 'done' +2026-10-08T16:51:14.3660495Z Preparing editable metadata (pyproject.toml): started +2026-10-08T16:51:14.6781798Z Preparing editable metadata (pyproject.toml): finished with status 'done' +2026-10-08T16:51:14.6826638Z Obtaining file:///D:/a/CaptureSuite/CaptureSuite/libs/python/capture_worker (from -r requirements-ci.txt (line 6)) +2026-10-08T16:51:14.6856662Z Installing build dependencies: started +2026-10-08T16:51:16.2021425Z Installing build dependencies: finished with status 'done' +2026-10-08T16:51:16.2036229Z Checking if build backend supports build_editable: started +2026-10-08T16:51:16.6559278Z Checking if build backend supports build_editable: finished with status 'done' +2026-10-08T16:51:16.6579338Z Getting requirements to build editable: started +2026-10-08T16:51:17.3108610Z Getting requirements to build editable: finished with status 'done' +2026-10-08T16:51:17.3135594Z Preparing editable metadata (pyproject.toml): started +2026-10-08T16:51:17.6163231Z Preparing editable metadata (pyproject.toml): finished with status 'done' +2026-10-08T16:51:17.6200017Z Obtaining file:///D:/a/CaptureSuite/CaptureSuite/desktop +2026-10-08T16:51:17.6227847Z Installing build dependencies: started +2026-10-08T16:51:19.2715518Z Installing build dependencies: finished with status 'done' +2026-10-08T16:51:19.2731070Z Checking if build backend supports build_editable: started +2026-10-08T16:51:19.7477364Z Checking if build backend supports build_editable: finished with status 'done' +2026-10-08T16:51:19.7501439Z Getting requirements to build editable: started +2026-10-08T16:51:20.2406903Z Getting requirements to build editable: finished with status 'done' +2026-10-08T16:51:20.2432036Z Preparing editable metadata (pyproject.toml): started +2026-10-08T16:51:20.5394154Z Preparing editable metadata (pyproject.toml): finished with status 'done' +2026-10-08T16:51:21.2896826Z Collecting grpcio-tools<1.63,>=1.62 (from -r requirements-ci.txt (line 8)) +2026-10-08T16:51:21.4686549Z Downloading grpcio_tools-1.62.3-cp312-cp312-win_amd64.whl.metadata (6.4 kB) +2026-10-08T16:51:21.5122615Z Collecting mcap<2,>=1.1 (from -r requirements-ci.txt (line 9)) +2026-10-08T16:51:21.5252590Z Downloading mcap-1.5.0-py3-none-any.whl.metadata (380 bytes) +2026-10-08T16:51:21.5765987Z Collecting pytest>=8 (from -r requirements-ci.txt (line 10)) +2026-10-08T16:51:21.5882604Z Downloading pytest-9.1.1-py3-none-any.whl.metadata (7.6 kB) +2026-10-08T16:51:21.6393655Z Collecting pytest-cov>=5 (from -r requirements-ci.txt (line 11)) +2026-10-08T16:51:21.6519523Z Downloading pytest_cov-7.1.0-py3-none-any.whl.metadata (32 kB) +2026-10-08T16:51:22.0072657Z Collecting ruff<1,>=0.6 (from -r requirements-ci.txt (line 12)) +2026-10-08T16:51:22.0192780Z Downloading ruff-0.16.10-py3-none-win_amd64.whl.metadata (21 kB) +2026-10-08T16:51:22.1782091Z Collecting protobuf<5,>=4.25 (from capture-protocol==0.1.0->-r requirements-ci.txt (line 3)) +2026-10-08T16:51:22.1902237Z Downloading protobuf-4.25.9-cp310-abi3-win_amd64.whl.metadata (541 bytes) +2026-10-08T16:51:22.2403335Z Collecting jsonschema>=4.21 (from capture-session==0.1.0->-r requirements-ci.txt (line 4)) +2026-10-08T16:51:22.2521524Z Downloading jsonschema-4.26.0-py3-none-any.whl.metadata (7.6 kB) +2026-10-08T16:51:22.3568641Z Collecting pyyaml>=6.0 (from capture-analysis==0.1.0) +2026-10-08T16:51:22.3692664Z Downloading pyyaml-6.0.3-cp312-cp312-win_amd64.whl.metadata (2.4 kB) +2026-10-08T16:51:22.4280253Z Collecting PySide6<7,>=6.6 (from capture-desktop==0.1.0) +2026-10-08T16:51:22.4435080Z Downloading pyside6-6.12.0-cp310-abi3-win_amd64.whl.metadata (5.7 kB) +2026-10-08T16:51:22.6476574Z Collecting numpy>=1.26 (from capture-analysis==0.1.0) +2026-10-08T16:51:22.6599066Z Downloading numpy-2.5.3-cp312-cp312-win_amd64.whl.metadata (6.6 kB) +2026-10-08T16:51:22.7980134Z Collecting scipy>=1.11 (from capture-analysis==0.1.0) +2026-10-08T16:51:22.8099680Z Downloading scipy-1.18.1-cp312-cp312-win_amd64.whl.metadata (61 kB) +2026-10-08T16:51:22.9850602Z Collecting pandas>=2.1 (from capture-analysis==0.1.0) +2026-10-08T16:51:22.9989992Z Downloading pandas-3.0.6-cp312-cp312-win_amd64.whl.metadata (19 kB) +2026-10-08T16:51:23.1243634Z Collecting pyarrow>=14.0 (from capture-analysis==0.1.0) +2026-10-08T16:51:23.1370593Z Downloading pyarrow-25.0.1-cp312-cp312-win_amd64.whl.metadata (3.0 kB) +2026-10-08T16:51:23.2860625Z Collecting matplotlib>=3.8 (from capture-analysis==0.1.0) +2026-10-08T16:51:23.2985490Z Downloading matplotlib-3.11.2-cp312-cp312-win_amd64.whl.metadata (80 kB) +2026-10-08T16:51:23.3576988Z Collecting pyqtgraph>=0.13 (from capture-desktop==0.1.0) +2026-10-08T16:51:23.3693447Z Downloading pyqtgraph-0.14.0-py3-none-any.whl.metadata (1.5 kB) +2026-10-08T16:51:23.8781000Z Collecting grpcio>=1.62.3 (from grpcio-tools<1.63,>=1.62->-r requirements-ci.txt (line 8)) +2026-10-08T16:51:23.8906757Z Downloading grpcio-1.84.0-cp312-cp312-win_amd64.whl.metadata (3.9 kB) +2026-10-08T16:51:24.1078733Z Collecting setuptools (from grpcio-tools<1.63,>=1.62->-r requirements-ci.txt (line 8)) +2026-10-08T16:51:24.1101210Z Using cached setuptools-84.0.0-py3-none-any.whl.metadata (6.6 kB) +2026-10-08T16:51:24.1854323Z Collecting lz4 (from mcap<2,>=1.1->-r requirements-ci.txt (line 9)) +2026-10-08T16:51:24.2079294Z Downloading lz4-4.4.5-cp312-cp312-win_amd64.whl.metadata (3.9 kB) +2026-10-08T16:51:24.3143002Z Collecting zstandard (from mcap<2,>=1.1->-r requirements-ci.txt (line 9)) +2026-10-08T16:51:24.3270067Z Downloading zstandard-0.25.0-cp312-cp312-win_amd64.whl.metadata (3.3 kB) +2026-10-08T16:51:24.4183664Z Collecting PySide6_Essentials==6.12.0 (from PySide6<7,>=6.6->capture-desktop==0.1.0) +2026-10-08T16:51:24.4307372Z Downloading pyside6_essentials-6.12.0-cp310-abi3-win_amd64.whl.metadata (3.9 kB) +2026-10-08T16:51:24.4967692Z Collecting PySide6_Addons==6.12.0 (from PySide6<7,>=6.6->capture-desktop==0.1.0) +2026-10-08T16:51:24.5138828Z Downloading pyside6_addons-6.12.0-cp310-abi3-win_amd64.whl.metadata (4.4 kB) +2026-10-08T16:51:24.5525805Z Collecting PySide6_WebEngine==6.12.0.140 (from PySide6<7,>=6.6->capture-desktop==0.1.0) +2026-10-08T16:51:24.5650645Z Downloading pyside6_webengine-6.12.0.140-cp310-abi3-win_amd64.whl.metadata (3.7 kB) +2026-10-08T16:51:24.6200213Z Collecting PySide6_Pdf==6.12.0.140 (from PySide6<7,>=6.6->capture-desktop==0.1.0) +2026-10-08T16:51:24.6356152Z Downloading pyside6_pdf-6.12.0.140-cp310-abi3-win_amd64.whl.metadata (3.6 kB) +2026-10-08T16:51:24.7101447Z Collecting shiboken6==6.12.0 (from PySide6_Essentials==6.12.0->PySide6<7,>=6.6->capture-desktop==0.1.0) +2026-10-08T16:51:24.7229983Z Downloading shiboken6-6.12.0-cp310-abi3-win_amd64.whl.metadata (2.6 kB) +2026-10-08T16:51:24.7454640Z Requirement already satisfied: colorama>=0.4 in C:\hostedtoolcache\windows\Python\3.12.10\x64\Lib\site-packages (from pytest>=8->-r requirements-ci.txt (line 10)) (0.4.6) +2026-10-08T16:51:24.7722488Z Collecting iniconfig>=1.0.1 (from pytest>=8->-r requirements-ci.txt (line 10)) +2026-10-08T16:51:24.7929052Z Downloading iniconfig-2.3.1-py3-none-any.whl.metadata (2.8 kB) +2026-10-08T16:51:24.8340805Z Requirement already satisfied: packaging>=22 in C:\hostedtoolcache\windows\Python\3.12.10\x64\Lib\site-packages (from pytest>=8->-r requirements-ci.txt (line 10)) (26.3) +2026-10-08T16:51:24.8659814Z Collecting pluggy<2,>=1.5 (from pytest>=8->-r requirements-ci.txt (line 10)) +2026-10-08T16:51:24.8774992Z Downloading pluggy-1.6.0-py3-none-any.whl.metadata (4.8 kB) +2026-10-08T16:51:24.9297225Z Collecting pygments>=2.7.2 (from pytest>=8->-r requirements-ci.txt (line 10)) +2026-10-08T16:51:24.9417418Z Downloading pygments-2.21.0-py3-none-any.whl.metadata (2.5 kB) +2026-10-08T16:51:25.3804181Z Collecting coverage>=7.10.6 (from coverage[toml]>=7.10.6->pytest-cov>=5->-r requirements-ci.txt (line 11)) +2026-10-08T16:51:25.3929090Z Downloading coverage-7.16.2-cp312-cp312-win_amd64.whl.metadata (8.4 kB) +2026-10-08T16:51:25.4407924Z Collecting typing-extensions~=4.12 (from grpcio>=1.62.3->grpcio-tools<1.63,>=1.62->-r requirements-ci.txt (line 8)) +2026-10-08T16:51:25.4527706Z Downloading typing_extensions-4.16.0-py3-none-any.whl.metadata (3.3 kB) +2026-10-08T16:51:25.5025726Z Collecting attrs>=22.2.0 (from jsonschema>=4.21->capture-session==0.1.0->-r requirements-ci.txt (line 4)) +2026-10-08T16:51:25.5154041Z Downloading attrs-26.1.0-py3-none-any.whl.metadata (8.8 kB) +2026-10-08T16:51:25.5541607Z Collecting jsonschema-specifications>=2023.03.6 (from jsonschema>=4.21->capture-session==0.1.0->-r requirements-ci.txt (line 4)) +2026-10-08T16:51:25.5657900Z Downloading jsonschema_specifications-2025.9.1-py3-none-any.whl.metadata (2.9 kB) +2026-10-08T16:51:25.6073574Z Collecting referencing>=0.28.4 (from jsonschema>=4.21->capture-session==0.1.0->-r requirements-ci.txt (line 4)) +2026-10-08T16:51:25.6189884Z Downloading referencing-0.37.0-py3-none-any.whl.metadata (2.8 kB) +2026-10-08T16:51:25.8852887Z Collecting rpds-py>=0.25.0 (from jsonschema>=4.21->capture-session==0.1.0->-r requirements-ci.txt (line 4)) +2026-10-08T16:51:25.8978468Z Downloading rpds_py-2026.9.1-cp312-cp312-win_amd64.whl.metadata (4.2 kB) +2026-10-08T16:51:25.9861700Z Collecting contourpy>=1.0.1 (from matplotlib>=3.8->capture-analysis==0.1.0) +2026-10-08T16:51:25.9986353Z Downloading contourpy-1.4.0-cp312-cp312-win_amd64.whl.metadata (3.8 kB) +2026-10-08T16:51:26.0340343Z Collecting cycler>=0.10 (from matplotlib>=3.8->capture-analysis==0.1.0) +2026-10-08T16:51:26.0455973Z Downloading cycler-0.12.1-py3-none-any.whl.metadata (3.8 kB) +2026-10-08T16:51:26.2135635Z Collecting fonttools>=4.28.2 (from matplotlib>=3.8->capture-analysis==0.1.0) +2026-10-08T16:51:26.2275515Z Downloading fonttools-4.66.1-cp312-cp312-win_amd64.whl.metadata (132 kB) +2026-10-08T16:51:26.3310203Z Collecting kiwisolver>=1.3.1 (from matplotlib>=3.8->capture-analysis==0.1.0) +2026-10-08T16:51:26.3434832Z Downloading kiwisolver-1.5.1-cp312-cp312-win_amd64.whl.metadata (5.2 kB) +2026-10-08T16:51:26.5872104Z Collecting pillow>=9 (from matplotlib>=3.8->capture-analysis==0.1.0) +2026-10-08T16:51:26.5993637Z Downloading pillow-12.3.0-cp312-cp312-win_amd64.whl.metadata (9.3 kB) +2026-10-08T16:51:26.6514750Z Collecting pyparsing>=3 (from matplotlib>=3.8->capture-analysis==0.1.0) +2026-10-08T16:51:26.6681488Z Downloading pyparsing-3.3.3-py3-none-any.whl.metadata (5.9 kB) +2026-10-08T16:51:26.7051576Z Collecting python-dateutil>=2.7 (from matplotlib>=3.8->capture-analysis==0.1.0) +2026-10-08T16:51:26.7172438Z Downloading python_dateutil-2.9.0.post0-py2.py3-none-any.whl.metadata (8.4 kB) +2026-10-08T16:51:26.7647437Z Collecting tzdata (from pandas>=2.1->capture-analysis==0.1.0) +2026-10-08T16:51:26.7764751Z Downloading tzdata-2026.5-py2.py3-none-any.whl.metadata (1.4 kB) +2026-10-08T16:51:26.8258537Z Collecting six>=1.5 (from python-dateutil>=2.7->matplotlib>=3.8->capture-analysis==0.1.0) +2026-10-08T16:51:26.8372725Z Downloading six-1.17.0-py2.py3-none-any.whl.metadata (1.7 kB) +2026-10-08T16:51:26.8748841Z Downloading grpcio_tools-1.62.3-cp312-cp312-win_amd64.whl (1.1 MB) +2026-10-08T16:51:26.9167792Z ---------------------------------------- 1.1/1.1 MB 16.8 MB/s 0:00:00 +2026-10-08T16:51:26.9284310Z Downloading mcap-1.5.0-py3-none-any.whl (21 kB) +2026-10-08T16:51:26.9562615Z Downloading ruff-0.16.10-py3-none-win_amd64.whl (10.6 MB) +2026-10-08T16:51:27.0549875Z ---------------------------------------- 10.6/10.6 MB 109.8 MB/s 0:00:00 +2026-10-08T16:51:27.0670344Z Downloading protobuf-4.25.9-cp310-abi3-win_amd64.whl (413 kB) +2026-10-08T16:51:27.0989149Z Downloading pyside6-6.12.0-cp310-abi3-win_amd64.whl (578 kB) +2026-10-08T16:51:27.1208106Z ---------------------------------------- 579.0/579.0 kB 10.2 MB/s 0:00:00 +2026-10-08T16:51:27.1333297Z Downloading pyside6_addons-6.12.0-cp310-abi3-win_amd64.whl (40.5 MB) +2026-10-08T16:51:27.5991511Z ---------------------------------------- 40.5/40.5 MB 88.9 MB/s 0:00:00 +2026-10-08T16:51:27.6120065Z Downloading pyside6_essentials-6.12.0-cp310-abi3-win_amd64.whl (82.2 MB) +2026-10-08T16:51:29.0049725Z ---------------------------------------- 82.2/82.2 MB 58.9 MB/s 0:00:01 +2026-10-08T16:51:29.0178617Z Downloading pyside6_pdf-6.12.0.140-cp310-abi3-win_amd64.whl (3.0 MB) +2026-10-08T16:51:29.0575481Z ---------------------------------------- 3.0/3.0 MB 57.9 MB/s 0:00:00 +2026-10-08T16:51:29.0701377Z Downloading pyside6_webengine-6.12.0.140-cp310-abi3-win_amd64.whl (131.7 MB) +2026-10-08T16:51:30.9886666Z ---------------------------------------- 131.7/131.7 MB 68.9 MB/s 0:00:01 +2026-10-08T16:51:31.0008561Z Downloading shiboken6-6.12.0-cp310-abi3-win_amd64.whl (1.3 MB) +2026-10-08T16:51:31.0264678Z ---------------------------------------- 1.3/1.3 MB 62.7 MB/s 0:00:00 +2026-10-08T16:51:31.0383065Z Downloading pytest-9.1.1-py3-none-any.whl (386 kB) +2026-10-08T16:51:31.0681171Z Downloading pluggy-1.6.0-py3-none-any.whl (20 kB) +2026-10-08T16:51:31.0929234Z Downloading pytest_cov-7.1.0-py3-none-any.whl (22 kB) +2026-10-08T16:51:31.1223989Z Downloading coverage-7.16.2-cp312-cp312-win_amd64.whl (226 kB) +2026-10-08T16:51:31.1515779Z Downloading grpcio-1.84.0-cp312-cp312-win_amd64.whl (5.3 MB) +2026-10-08T16:51:31.2012189Z ---------------------------------------- 5.3/5.3 MB 108.5 MB/s 0:00:00 +2026-10-08T16:51:31.2129905Z Downloading typing_extensions-4.16.0-py3-none-any.whl (45 kB) +2026-10-08T16:51:31.2363197Z Downloading iniconfig-2.3.1-py3-none-any.whl (7.6 kB) +2026-10-08T16:51:31.2628390Z Downloading jsonschema-4.26.0-py3-none-any.whl (90 kB) +2026-10-08T16:51:31.2891005Z Downloading attrs-26.1.0-py3-none-any.whl (67 kB) +2026-10-08T16:51:31.3172588Z Downloading jsonschema_specifications-2025.9.1-py3-none-any.whl (18 kB) +2026-10-08T16:51:31.3437370Z Downloading matplotlib-3.11.2-cp312-cp312-win_amd64.whl (9.3 MB) +2026-10-08T16:51:31.4219448Z ---------------------------------------- 9.3/9.3 MB 116.5 MB/s 0:00:00 +2026-10-08T16:51:31.4340992Z Downloading contourpy-1.4.0-cp312-cp312-win_amd64.whl (234 kB) +2026-10-08T16:51:31.4632119Z Downloading cycler-0.12.1-py3-none-any.whl (8.3 kB) +2026-10-08T16:51:31.4904053Z Downloading fonttools-4.66.1-cp312-cp312-win_amd64.whl (2.5 MB) +2026-10-08T16:51:31.5357126Z ---------------------------------------- 2.5/2.5 MB 69.5 MB/s 0:00:00 +2026-10-08T16:51:31.5479268Z Downloading kiwisolver-1.5.1-cp312-cp312-win_amd64.whl (70 kB) +2026-10-08T16:51:31.5790967Z Downloading numpy-2.5.3-cp312-cp312-win_amd64.whl (12.6 MB) +2026-10-08T16:51:31.6817146Z ---------------------------------------- 12.6/12.6 MB 111.9 MB/s 0:00:00 +2026-10-08T16:51:31.6939421Z Downloading pandas-3.0.6-cp312-cp312-win_amd64.whl (9.7 MB) +2026-10-08T16:51:31.7607179Z ---------------------------------------- 9.7/9.7 MB 149.2 MB/s 0:00:00 +2026-10-08T16:51:31.7732072Z Downloading pillow-12.3.0-cp312-cp312-win_amd64.whl (7.2 MB) +2026-10-08T16:51:31.8274667Z ---------------------------------------- 7.2/7.2 MB 151.4 MB/s 0:00:00 +2026-10-08T16:51:31.8409263Z Downloading pyarrow-25.0.1-cp312-cp312-win_amd64.whl (28.0 MB) +2026-10-08T16:51:32.2777783Z ---------------------------------------- 28.0/28.0 MB 63.2 MB/s 0:00:00 +2026-10-08T16:51:32.2897793Z Downloading pygments-2.21.0-py3-none-any.whl (1.3 MB) +2026-10-08T16:51:32.3158487Z ---------------------------------------- 1.3/1.3 MB 61.8 MB/s 0:00:00 +2026-10-08T16:51:32.3274457Z Downloading pyparsing-3.3.3-py3-none-any.whl (126 kB) +2026-10-08T16:51:32.3551552Z Downloading pyqtgraph-0.14.0-py3-none-any.whl (1.9 MB) +2026-10-08T16:51:32.3877193Z ---------------------------------------- 1.9/1.9 MB 53.6 MB/s 0:00:00 +2026-10-08T16:51:32.3997012Z Downloading python_dateutil-2.9.0.post0-py2.py3-none-any.whl (229 kB) +2026-10-08T16:51:32.4252537Z Downloading pyyaml-6.0.3-cp312-cp312-win_amd64.whl (154 kB) +2026-10-08T16:51:32.4564743Z Downloading referencing-0.37.0-py3-none-any.whl (26 kB) +2026-10-08T16:51:32.4800948Z Downloading rpds_py-2026.9.1-cp312-cp312-win_amd64.whl (222 kB) +2026-10-08T16:51:32.5131821Z Downloading scipy-1.18.1-cp312-cp312-win_amd64.whl (36.7 MB) +2026-10-08T16:51:33.7326562Z ---------------------------------------- 36.7/36.7 MB 29.9 MB/s 0:00:01 +2026-10-08T16:51:33.7442041Z Downloading six-1.17.0-py2.py3-none-any.whl (11 kB) +2026-10-08T16:51:33.7742839Z Downloading lz4-4.4.5-cp312-cp312-win_amd64.whl (99 kB) +2026-10-08T16:51:33.7918994Z Using cached setuptools-84.0.0-py3-none-any.whl (818 kB) +2026-10-08T16:51:33.8053697Z Downloading tzdata-2026.5-py2.py3-none-any.whl (347 kB) +2026-10-08T16:51:33.8327219Z Downloading zstandard-0.25.0-cp312-cp312-win_amd64.whl (506 kB) +2026-10-08T16:51:34.5914778Z Building wheels for collected packages: capture-protocol, capture-session, capture-analysis, capture-worker, capture-desktop +2026-10-08T16:51:34.6063343Z Building editable for capture-protocol (pyproject.toml): started +2026-10-08T16:51:34.9856995Z Building editable for capture-protocol (pyproject.toml): finished with status 'done' +2026-10-08T16:51:34.9894284Z Created wheel for capture-protocol: filename=capture_protocol-0.1.0-0.editable-py3-none-any.whl size=7398 sha256=e368858667717cc180090825f7f3ab1fa1e23e25e5756a891601dcdc67f5d7ee +2026-10-08T16:51:34.9896196Z Stored in directory: C:\Users\runneradmin\AppData\Local\Temp\pip-ephem-wheel-cache-fvasdsq4\wheels\be\38\74\adf0f9a8f0ba8d26599b299cff33b892a58ed35959c9e09acd +2026-10-08T16:51:34.9936777Z Building editable for capture-session (pyproject.toml): started +2026-10-08T16:51:35.3098376Z Building editable for capture-session (pyproject.toml): finished with status 'done' +2026-10-08T16:51:35.3132901Z Created wheel for capture-session: filename=capture_session-0.1.0-0.editable-py3-none-any.whl size=2863 sha256=9e88e25ab3d85c76e38f3d731bb21f9cb9b211a47c8f980927dd8a307ed589b3 +2026-10-08T16:51:35.3134298Z Stored in directory: C:\Users\runneradmin\AppData\Local\Temp\pip-ephem-wheel-cache-fvasdsq4\wheels\49\8f\6e\163bd066522d89fdd0906cf22a1687ebc628821c7980903be9 +2026-10-08T16:51:35.3174025Z Building editable for capture-analysis (pyproject.toml): started +2026-10-08T16:51:35.6657221Z Building editable for capture-analysis (pyproject.toml): finished with status 'done' +2026-10-08T16:51:35.6690723Z Created wheel for capture-analysis: filename=capture_analysis-0.1.0-0.editable-py3-none-any.whl size=3050 sha256=fa5f2e8ac509a025fb23323052b2c24f0d04d3b6cc5e423370f967abd2768ea8 +2026-10-08T16:51:35.6692838Z Stored in directory: C:\Users\runneradmin\AppData\Local\Temp\pip-ephem-wheel-cache-fvasdsq4\wheels\f4\d1\58\14e4976a0c15c2c470fc12f9a2873cc8c4bc7bd989766b97b4 +2026-10-08T16:51:35.6732539Z Building editable for capture-worker (pyproject.toml): started +2026-10-08T16:51:36.0254279Z Building editable for capture-worker (pyproject.toml): finished with status 'done' +2026-10-08T16:51:36.0300549Z Created wheel for capture-worker: filename=capture_worker-0.1.0-0.editable-py3-none-any.whl size=7659 sha256=ca8ac44cab11d18ad97b9171e0323568bdb5a3b5a8f5bb5d79066270550b89a4 +2026-10-08T16:51:36.0303136Z Stored in directory: C:\Users\runneradmin\AppData\Local\Temp\pip-ephem-wheel-cache-fvasdsq4\wheels\91\10\bd\b56fd1c22822b4cd753ca217f259119db33a4fa54b26c297ee +2026-10-08T16:51:36.0344057Z Building editable for capture-desktop (pyproject.toml): started +2026-10-08T16:51:36.3640418Z Building editable for capture-desktop (pyproject.toml): finished with status 'done' +2026-10-08T16:51:36.3673458Z Created wheel for capture-desktop: filename=capture_desktop-0.1.0-0.editable-py3-none-any.whl size=3184 sha256=8b53cfefe44d9af141c6a24c8f15da59501c54ffa2d59c9c3afe6e750cc4c744 +2026-10-08T16:51:36.3674825Z Stored in directory: C:\Users\runneradmin\AppData\Local\Temp\pip-ephem-wheel-cache-fvasdsq4\wheels\04\f4\80\083223dba330947d948f2d768e3de9f1e54ae638d0a391d614 +2026-10-08T16:51:36.3696959Z Successfully built capture-protocol capture-session capture-analysis capture-worker capture-desktop +2026-10-08T16:51:36.5258190Z Installing collected packages: zstandard, tzdata, typing-extensions, six, shiboken6, setuptools, ruff, rpds-py, pyyaml, pyparsing, pygments, pyarrow, protobuf, pluggy, pillow, numpy, lz4, kiwisolver, iniconfig, fonttools, cycler, coverage, attrs, scipy, referencing, python-dateutil, pytest, PySide6_Essentials, pyqtgraph, mcap, grpcio, contourpy, capture-protocol, pytest-cov, PySide6_Pdf, PySide6_Addons, pandas, matplotlib, jsonschema-specifications, grpcio-tools, capture-worker, PySide6_WebEngine, jsonschema, PySide6, capture-session, capture-desktop, capture-analysis +2026-10-08T16:52:29.0810050Z +2026-10-08T16:52:29.0857484Z Successfully installed PySide6-6.12.0 PySide6_Addons-6.12.0 PySide6_Essentials-6.12.0 PySide6_Pdf-6.12.0.140 PySide6_WebEngine-6.12.0.140 attrs-26.1.0 capture-analysis-0.1.0 capture-desktop-0.1.0 capture-protocol-0.1.0 capture-session-0.1.0 capture-worker-0.1.0 contourpy-1.4.0 coverage-7.16.2 cycler-0.12.1 fonttools-4.66.1 grpcio-1.84.0 grpcio-tools-1.62.3 iniconfig-2.3.1 jsonschema-4.26.0 jsonschema-specifications-2025.9.1 kiwisolver-1.5.1 lz4-4.4.5 matplotlib-3.11.2 mcap-1.5.0 numpy-2.5.3 pandas-3.0.6 pillow-12.3.0 pluggy-1.6.0 protobuf-4.25.9 pyarrow-25.0.1 pygments-2.21.0 pyparsing-3.3.3 pyqtgraph-0.14.0 pytest-9.1.1 pytest-cov-7.1.0 python-dateutil-2.9.0.post0 pyyaml-6.0.3 referencing-0.37.0 rpds-py-2026.9.1 ruff-0.16.10 scipy-1.18.1 setuptools-84.0.0 shiboken6-6.12.0 six-1.17.0 typing-extensions-4.16.0 tzdata-2026.5 zstandard-0.25.0 +2026-10-08T16:52:30.0781156Z ##[group]Run python -m pip check +2026-10-08T16:52:30.0781564Z python -m pip check +2026-10-08T16:52:30.0827396Z shell: C:\Program Files\PowerShell\7\pwsh.EXE -command ". '{0}'" +2026-10-08T16:52:30.0827747Z env: +2026-10-08T16:52:30.0828036Z pythonLocation: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:52:30.0828470Z PKG_CONFIG_PATH: C:\hostedtoolcache\windows\Python\3.12.10\x64/lib/pkgconfig +2026-10-08T16:52:30.0828920Z Python_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:52:30.0829310Z Python2_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:52:30.0829700Z Python3_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:52:30.0830013Z ##[endgroup] +2026-10-08T16:52:30.7411991Z No broken requirements found. +2026-10-08T16:52:30.8959645Z ##[group]Run python tools/check_ci_contract.py --check-environment +2026-10-08T16:52:30.8960165Z python tools/check_ci_contract.py --check-environment +2026-10-08T16:52:30.8997547Z shell: C:\Program Files\PowerShell\7\pwsh.EXE -command ". '{0}'" +2026-10-08T16:52:30.8997890Z env: +2026-10-08T16:52:30.8998157Z pythonLocation: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:52:30.8998600Z PKG_CONFIG_PATH: C:\hostedtoolcache\windows\Python\3.12.10\x64/lib/pkgconfig +2026-10-08T16:52:30.8999029Z Python_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:52:30.8999433Z Python2_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:52:30.8999811Z Python3_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:52:30.9000113Z ##[endgroup] +2026-10-08T16:52:37.4814647Z Matplotlib is building the font cache; this may take a moment. +2026-10-08T16:52:48.5529827Z { +2026-10-08T16:52:48.5530630Z "accepted": true, +2026-10-08T16:52:48.5530964Z "errors": [] +2026-10-08T16:52:48.5531251Z } +2026-10-08T16:52:48.8316375Z ##[group]Run python tools/gen_protos.py +2026-10-08T16:52:48.8316738Z python tools/gen_protos.py +2026-10-08T16:52:48.8354027Z shell: C:\Program Files\PowerShell\7\pwsh.EXE -command ". '{0}'" +2026-10-08T16:52:48.8354370Z env: +2026-10-08T16:52:48.8354631Z pythonLocation: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:52:48.8355073Z PKG_CONFIG_PATH: C:\hostedtoolcache\windows\Python\3.12.10\x64/lib/pkgconfig +2026-10-08T16:52:48.8355485Z Python_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:52:48.8356531Z Python2_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:52:48.8356918Z Python3_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:52:48.8357231Z ##[endgroup] +2026-10-08T16:52:49.2497027Z Running: C:\hostedtoolcache\windows\Python\3.12.10\x64\python.exe -m grpc_tools.protoc --proto_path=D:\a\CaptureSuite\CaptureSuite\schemas\proto --python_out=D:\a\CaptureSuite\CaptureSuite\libs\python\capture_protocol\capture_protocol\generated --descriptor_set_out=D:\a\CaptureSuite\CaptureSuite\build\generated\capture_v1.desc --include_imports --proto_path=C:\hostedtoolcache\windows\Python\3.12.10\x64\Lib\site-packages\grpc_tools\_proto capture/v1/arrays.proto capture/v1/common.proto capture/v1/control.proto capture/v1/data/emg_batch.proto capture/v1/data/imu_frame.proto capture/v1/data/numeric_batch.proto capture/v1/data/radar_doppler.proto capture/v1/data/radar_frame.proto capture/v1/data/video_timing.proto capture/v1/events.proto capture/v1/health.proto capture/v1/presets.proto capture/v1/preview.proto capture/v1/project.proto capture/v1/source.proto capture/v1/storage.proto capture/v1/worker.proto +2026-10-08T16:52:49.2500265Z Wrote Python bindings under D:\a\CaptureSuite\CaptureSuite\libs\python\capture_protocol\capture_protocol\generated +2026-10-08T16:52:49.2500882Z Wrote descriptor set D:\a\CaptureSuite\CaptureSuite\build\generated\capture_v1.desc +2026-10-08T16:52:49.3866842Z ##[group]Run git diff --exit-code -- libs/python/capture_protocol/capture_protocol/generated +2026-10-08T16:52:49.3867581Z git diff --exit-code -- libs/python/capture_protocol/capture_protocol/generated +2026-10-08T16:52:49.3906065Z shell: C:\Program Files\PowerShell\7\pwsh.EXE -command ". '{0}'" +2026-10-08T16:52:49.3906392Z env: +2026-10-08T16:52:49.3906651Z pythonLocation: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:52:49.3907096Z PKG_CONFIG_PATH: C:\hostedtoolcache\windows\Python\3.12.10\x64/lib/pkgconfig +2026-10-08T16:52:49.3907525Z Python_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:52:49.3907900Z Python2_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:52:49.3908275Z Python3_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:52:49.3908572Z ##[endgroup] +2026-10-08T16:52:49.8536960Z ##[group]Run python tools/gen_session_schemas.py +2026-10-08T16:52:49.8537404Z python tools/gen_session_schemas.py +2026-10-08T16:52:49.8573794Z shell: C:\Program Files\PowerShell\7\pwsh.EXE -command ". '{0}'" +2026-10-08T16:52:49.8574125Z env: +2026-10-08T16:52:49.8574394Z pythonLocation: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:52:49.8574840Z PKG_CONFIG_PATH: C:\hostedtoolcache\windows\Python\3.12.10\x64/lib/pkgconfig +2026-10-08T16:52:49.8575254Z Python_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:52:49.8575627Z Python2_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:52:49.8576018Z Python3_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:52:49.8576313Z ##[endgroup] +2026-10-08T16:52:50.1655942Z Wrote 19 schemas to D:\a\CaptureSuite\CaptureSuite\schemas\session\jsonschema +2026-10-08T16:52:50.2705441Z ##[group]Run git diff --exit-code -- schemas/session/jsonschema +2026-10-08T16:52:50.2705945Z git diff --exit-code -- schemas/session/jsonschema +2026-10-08T16:52:50.2744480Z shell: C:\Program Files\PowerShell\7\pwsh.EXE -command ". '{0}'" +2026-10-08T16:52:50.2744804Z env: +2026-10-08T16:52:50.2745066Z pythonLocation: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:52:50.2745507Z PKG_CONFIG_PATH: C:\hostedtoolcache\windows\Python\3.12.10\x64/lib/pkgconfig +2026-10-08T16:52:50.2745933Z Python_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:52:50.2746323Z Python2_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:52:50.2746690Z Python3_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:52:50.2747144Z ##[endgroup] +2026-10-08T16:52:50.6124294Z ##[group]Run ruff check libs/python/capture_protocol libs/python/capture_session libs/python/capture_analysis libs/python/capture_worker workers/python_host desktop/capture_desktop tools tests plugins/example_sine_py plugins/lsl_bridge +2026-10-08T16:52:50.6127128Z ruff check libs/python/capture_protocol libs/python/capture_session libs/python/capture_analysis libs/python/capture_worker workers/python_host desktop/capture_desktop tools tests plugins/example_sine_py plugins/lsl_bridge +2026-10-08T16:52:50.6165969Z shell: C:\Program Files\PowerShell\7\pwsh.EXE -command ". '{0}'" +2026-10-08T16:52:50.6166304Z env: +2026-10-08T16:52:50.6166577Z pythonLocation: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:52:50.6167022Z PKG_CONFIG_PATH: C:\hostedtoolcache\windows\Python\3.12.10\x64/lib/pkgconfig +2026-10-08T16:52:50.6167450Z Python_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:52:50.6167897Z Python2_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:52:50.6168275Z Python3_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:52:50.6168576Z ##[endgroup] +2026-10-08T16:52:50.9507474Z All checks passed! +2026-10-08T16:52:51.0467145Z ##[group]Run python tools/check_licenses.py --enforce-spdx +2026-10-08T16:52:51.0467642Z python tools/check_licenses.py --enforce-spdx +2026-10-08T16:52:51.0505180Z shell: C:\Program Files\PowerShell\7\pwsh.EXE -command ". '{0}'" +2026-10-08T16:52:51.0505524Z env: +2026-10-08T16:52:51.0505805Z pythonLocation: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:52:51.0506257Z PKG_CONFIG_PATH: C:\hostedtoolcache\windows\Python\3.12.10\x64/lib/pkgconfig +2026-10-08T16:52:51.0506691Z Python_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:52:51.0507082Z Python2_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:52:51.0507466Z Python3_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:52:51.0507790Z ##[endgroup] +2026-10-08T16:52:51.6388610Z license check OK +2026-10-08T16:52:51.7422932Z ##[group]Run python tools/run_ci_tests.py +2026-10-08T16:52:51.7423311Z python tools/run_ci_tests.py +2026-10-08T16:52:51.7460266Z shell: C:\Program Files\PowerShell\7\pwsh.EXE -command ". '{0}'" +2026-10-08T16:52:51.7460604Z env: +2026-10-08T16:52:51.7460875Z pythonLocation: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:52:51.7461329Z PKG_CONFIG_PATH: C:\hostedtoolcache\windows\Python\3.12.10\x64/lib/pkgconfig +2026-10-08T16:52:51.7461760Z Python_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:52:51.7462153Z Python2_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:52:51.7462535Z Python3_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:52:51.7462862Z QT_QPA_PLATFORM: offscreen +2026-10-08T16:52:51.7463086Z ##[endgroup] +2026-10-08T16:57:06.8819185Z ........................................................................ [ 13%] +2026-10-08T16:57:06.8820214Z ........................................................................ [ 26%] +2026-10-08T16:57:06.8820823Z ........................................................................ [ 39%] +2026-10-08T16:57:06.8821418Z ........................................................................ [ 52%] +2026-10-08T16:57:06.8822019Z ..........................................................ssssss........ [ 65%] +2026-10-08T16:57:06.8822618Z ........................................................................ [ 78%] +2026-10-08T16:57:06.8823216Z ........................................................................ [ 91%] +2026-10-08T16:57:06.8823848Z ..............F................................. [100%] +2026-10-08T16:57:06.8824442Z ================================== FAILURES =================================== +2026-10-08T16:57:06.8825129Z _______ test_png_discovery_refuses_external_file_links_and_directories ________ +2026-10-08T16:57:06.8826081Z +2026-10-08T16:57:06.8826482Z qapp = +2026-10-08T16:57:06.8827572Z tmp_path = WindowsPath('C:/Users/runneradmin/AppData/Local/Temp/pytest-of-runneradmin/pytest-0/test_png_discovery_refuses_ext0') +2026-10-08T16:57:06.8828428Z +2026-10-08T16:57:06.8828819Z def test_png_discovery_refuses_external_file_links_and_directories(qapp, tmp_path): +2026-10-08T16:57:06.8829690Z from capture_desktop.widgets_analysis_plots import FigureGallery +2026-10-08T16:57:06.8830321Z +2026-10-08T16:57:06.8830658Z job = tmp_path / "job" +2026-10-08T16:57:06.8831098Z outside = tmp_path / "external.png" +2026-10-08T16:57:06.8831591Z _png(outside, "#aa1122") +2026-10-08T16:57:06.8832101Z _png(job / "figures/nested/good.png", "#22aa55") +2026-10-08T16:57:06.8832687Z foreign = job / "figures/foreign.png" +2026-10-08T16:57:06.8833207Z try: +2026-10-08T16:57:06.8833618Z foreign.symlink_to(outside) +2026-10-08T16:57:06.8834311Z except OSError as exc: +2026-10-08T16:57:06.8835145Z pytest.skip(f"This filesystem cannot create the symlink fixture: {exc}") +2026-10-08T16:57:06.8836246Z (job / "figures/not_a_file.png").mkdir() +2026-10-08T16:57:06.8836988Z before = _hashes(tmp_path) +2026-10-08T16:57:06.8837462Z gallery = FigureGallery() +2026-10-08T16:57:06.8837914Z gallery.load_job_dir(job) +2026-10-08T16:57:06.8838515Z assert _titles(gallery) == ["Sync", "nested / good"] +2026-10-08T16:57:06.8839311Z assert _color(gallery, 1) == "#22aa55" +2026-10-08T16:57:06.8840245Z assert gallery._tabs.tabToolTip(1) == "nested/good.png" +2026-10-08T16:57:06.8840888Z > assert foreign.readlink() == outside +2026-10-08T16:57:06.8846486Z E AssertionError: assert WindowsPath('//?/C:/Users/runneradmin/AppData/Local/Temp/pytest-of-runneradmin/pytest-0/test_png_discovery_refuses_ext0/external.png') == WindowsPath('C:/Users/runneradmin/AppData/Local/Temp/pytest-of-runneradmin/pytest-0/test_png_discovery_refuses_ext0/external.png') +2026-10-08T16:57:06.8849960Z E + where WindowsPath('//?/C:/Users/runneradmin/AppData/Local/Temp/pytest-of-runneradmin/pytest-0/test_png_discovery_refuses_ext0/external.png') = readlink() +2026-10-08T16:57:06.8852238Z E + where readlink = WindowsPath('C:/Users/runneradmin/AppData/Local/Temp/pytest-of-runneradmin/pytest-0/test_png_discovery_refuses_ext0/job/figures/foreign.png').readlink +2026-10-08T16:57:06.8853361Z +2026-10-08T16:57:06.8853673Z tests\ui\test_analysis_nested_gallery.py:176: AssertionError +2026-10-08T16:57:06.8854389Z ============================== warnings summary =============================== +2026-10-08T16:57:06.8855004Z :488 +2026-10-08T16:57:06.8856564Z :488: DeprecationWarning: Type google._upb._message.MessageMapContainer uses PyType_Spec with a metaclass that has custom tp_new. This is deprecated and will no longer be allowed in Python 3.14. +2026-10-08T16:57:06.8857903Z +2026-10-08T16:57:06.8858082Z :488 +2026-10-08T16:57:06.8859635Z :488: DeprecationWarning: Type google._upb._message.ScalarMapContainer uses PyType_Spec with a metaclass that has custom tp_new. This is deprecated and will no longer be allowed in Python 3.14. +2026-10-08T16:57:06.8861035Z +2026-10-08T16:57:06.8861457Z -- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html +2026-10-08T16:57:06.8862237Z =========================== short test summary info =========================== +2026-10-08T16:57:06.8863082Z SKIPPED [1] tests\protocol\test_daemon_e2e.py:74: capture_daemon.exe not built (run cmake --build) +2026-10-08T16:57:06.8864187Z SKIPPED [1] tests\protocol\test_daemon_e2e.py:148: capture_daemon.exe not built (run cmake --build) +2026-10-08T16:57:06.8865313Z SKIPPED [1] tests\protocol\test_daemon_e2e.py:161: capture_daemon.exe not built (run cmake --build) +2026-10-08T16:57:06.8866650Z SKIPPED [1] tests\protocol\test_daemon_e2e.py:196: capture_daemon.exe not built (run cmake --build) +2026-10-08T16:57:06.8867745Z SKIPPED [1] tests\protocol\test_daemon_e2e.py:238: capture_daemon.exe not built (run cmake --build) +2026-10-08T16:57:06.8868829Z SKIPPED [1] tests\protocol\test_daemon_e2e.py:262: capture_daemon.exe not built (run cmake --build) +2026-10-08T16:57:06.8872055Z FAILED tests/ui/test_analysis_nested_gallery.py::test_png_discovery_refuses_external_file_links_and_directories - AssertionError: assert WindowsPath('//?/C:/Users/runneradmin/AppData/Local/Temp/pytest-of-runneradmin/pytest-0/test_png_discovery_refuses_ext0/external.png') == WindowsPath('C:/Users/runneradmin/AppData/Local/Temp/pytest-of-runneradmin/pytest-0/test_png_discovery_refuses_ext0/external.png') +2026-10-08T16:57:06.8875727Z + where WindowsPath('//?/C:/Users/runneradmin/AppData/Local/Temp/pytest-of-runneradmin/pytest-0/test_png_discovery_refuses_ext0/external.png') = readlink() +2026-10-08T16:57:06.8877750Z + where readlink = WindowsPath('C:/Users/runneradmin/AppData/Local/Temp/pytest-of-runneradmin/pytest-0/test_png_discovery_refuses_ext0/job/figures/foreign.png').readlink +2026-10-08T16:57:06.8879242Z 1 failed, 545 passed, 6 skipped, 2 warnings in 252.87s (0:04:12) +2026-10-08T16:57:06.8879693Z +2026-10-08T16:57:06.8879877Z { +2026-10-08T16:57:06.8880315Z "schema": "capturesuite.test-receipt.v1", +2026-10-08T16:57:06.8880851Z "accepted": false, +2026-10-08T16:57:06.8881281Z "process_exit": 1, +2026-10-08T16:57:06.8881680Z "counts": { +2026-10-08T16:57:06.8882043Z "tests": 552, +2026-10-08T16:57:06.8882431Z "passed": 545, +2026-10-08T16:57:06.8882819Z "failures": 1, +2026-10-08T16:57:06.8883235Z "errors": 0, +2026-10-08T16:57:06.8883611Z "skipped": 6 +2026-10-08T16:57:06.8883937Z }, +2026-10-08T16:57:06.8884526Z "junit_sha256": "fd1f28dde83c47406527a10c298ff5bf1e704ab1a3ca40a3d33fb0241a2fffdc", +2026-10-08T16:57:06.8885237Z "problems": [ +2026-10-08T16:57:06.8885640Z "Test process did not exit successfully", +2026-10-08T16:57:06.8887198Z "JUnit contains failing or errored cases" +2026-10-08T16:57:06.8887765Z ], +2026-10-08T16:57:06.8888254Z "scope": "Process and test-evidence consistency, not clinical validation", +2026-10-08T16:57:06.8888833Z "seconds": 253.92585270000006, +2026-10-08T16:57:06.8889252Z "created_at": "2026-10-08T16:57:06.415339+00:00", +2026-10-08T16:57:06.8890002Z "run_directory": "build/evidence/python-20261008T165252Z-6c42a44d", +2026-10-08T16:57:06.8890850Z "log_sha256": "a601ba62345c015d526826c931beca8abfc843473918ae5d1aa2aa0f433026cb", +2026-10-08T16:57:06.8891667Z "source_commit": "e0a45debe5e2a331ba5aee242ac985c9f604b31b", +2026-10-08T16:57:06.8892332Z "source_worktree_dirty": false, +2026-10-08T16:57:06.8893052Z "source_tree_sha256": "8c6145c31f582402cceb023450a81f949dee5318c6fc2a5675cc30662dc576ff", +2026-10-08T16:57:06.8893797Z "source_file_count": 1078, +2026-10-08T16:57:06.8894182Z "github": { +2026-10-08T16:57:06.8894515Z "GITHUB_ACTIONS": "true", +2026-10-08T16:57:06.8894923Z "GITHUB_EVENT_NAME": "pull_request", +2026-10-08T16:57:06.8895447Z "GITHUB_SHA": "e0a45debe5e2a331ba5aee242ac985c9f604b31b", +2026-10-08T16:57:06.8895982Z "GITHUB_REF": "refs/pull/80/merge", +2026-10-08T16:57:06.8896497Z "GITHUB_HEAD_REF": "fix/nested-figure-gallery-401c5d17da79", +2026-10-08T16:57:06.8897008Z "GITHUB_BASE_REF": "main", +2026-10-08T16:57:06.8897391Z "GITHUB_RUN_ID": "37811945519", +2026-10-08T16:57:06.8898100Z "GITHUB_WORKFLOW_REF": "Jacob-Met/CaptureSuite/.github/workflows/ci.yml@refs/pull/80/merge" +2026-10-08T16:57:06.8898759Z }, +2026-10-08T16:57:06.8899075Z "source_unchanged_during_test": true +2026-10-08T16:57:06.8899498Z } +2026-10-08T16:57:06.9848395Z ##[error]Process completed with exit code 1. +2026-10-08T16:57:07.0036104Z ##[group]Run actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a +2026-10-08T16:57:07.0036904Z with: +2026-10-08T16:57:07.0037158Z name: python-test-evidence +2026-10-08T16:57:07.0037447Z path: build/evidence/ +2026-10-08T16:57:07.0037719Z if-no-files-found: warn +2026-10-08T16:57:07.0037979Z retention-days: 7 +2026-10-08T16:57:07.0038224Z compression-level: 6 +2026-10-08T16:57:07.0038466Z overwrite: false +2026-10-08T16:57:07.0038715Z include-hidden-files: false +2026-10-08T16:57:07.0039005Z archive: true +2026-10-08T16:57:07.0039227Z env: +2026-10-08T16:57:07.0039529Z pythonLocation: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:57:07.0040014Z PKG_CONFIG_PATH: C:\hostedtoolcache\windows\Python\3.12.10\x64/lib/pkgconfig +2026-10-08T16:57:07.0040483Z Python_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:57:07.0040918Z Python2_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:57:07.0041444Z Python3_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.12.10\x64 +2026-10-08T16:57:07.0041797Z ##[endgroup] +2026-10-08T16:57:07.3032101Z With the provided path, there will be 281 files uploaded +2026-10-08T16:57:07.3037874Z Artifact name is valid! +2026-10-08T16:57:07.3039356Z Root directory input is valid! +2026-10-08T16:57:07.6773011Z Uploading artifact: python-test-evidence.zip +2026-10-08T16:57:07.6813636Z Beginning upload of artifact content to blob storage +2026-10-08T16:57:08.7447249Z Uploaded bytes 1611429 +2026-10-08T16:57:08.7998008Z Finished uploading artifact content to blob storage! +2026-10-08T16:57:08.7998831Z SHA256 digest of uploaded artifact is c3fd2500eb66af941ef46da3122874708f4e7e63f57e8f84b6f574e41d024803 +2026-10-08T16:57:08.7999596Z Finalizing artifact upload +2026-10-08T16:57:09.2066199Z Artifact python-test-evidence successfully finalized. Artifact ID 11565362992 +2026-10-08T16:57:09.2067745Z Artifact python-test-evidence has been successfully uploaded! Final size is 1611429 bytes. Artifact ID is 11565362992 +2026-10-08T16:57:09.2074217Z Artifact download URL: https://github.com/Jacob-Met/CaptureSuite/actions/runs/37811945519/artifacts/11565362992 +2026-10-08T16:57:09.2437949Z Post job cleanup. +2026-10-08T16:57:09.4240855Z [command]"C:\Program Files\Git\bin\git.exe" version +2026-10-08T16:57:09.4526401Z git version 2.56.0.windows.1 +2026-10-08T16:57:09.4593752Z Temporarily overriding HOME='D:\a\_temp\11603373-95fe-4eee-b492-c96a5fd1a03e' before making global git config changes +2026-10-08T16:57:09.4595041Z Adding repository directory to the temporary git global config as a safe directory +2026-10-08T16:57:09.4606417Z [command]"C:\Program Files\Git\bin\git.exe" config --global --add safe.directory D:\a\CaptureSuite\CaptureSuite +2026-10-08T16:57:09.4961465Z [command]"C:\Program Files\Git\bin\git.exe" config --local --name-only --get-regexp core\.sshCommand +2026-10-08T16:57:09.5294071Z [command]"C:\Program Files\Git\bin\git.exe" submodule foreach --recursive "sh -c \"git config --local --name-only --get-regexp 'core\.sshCommand' && git config --local --unset-all 'core.sshCommand' || :\"" +2026-10-08T16:57:10.0194822Z [command]"C:\Program Files\Git\bin\git.exe" config --local --name-only --get-regexp http\.https\:\/\/github\.com\/\.extraheader +2026-10-08T16:57:10.0466446Z http.https://github.com/.extraheader +2026-10-08T16:57:10.0515565Z [command]"C:\Program Files\Git\bin\git.exe" config --local --unset-all http.https://github.com/.extraheader +2026-10-08T16:57:10.0851234Z [command]"C:\Program Files\Git\bin\git.exe" submodule foreach --recursive "sh -c \"git config --local --name-only --get-regexp 'http\.https\:\/\/github\.com\/\.extraheader' && git config --local --unset-all 'http.https://github.com/.extraheader' || :\"" +2026-10-08T16:57:10.5998072Z [command]"C:\Program Files\Git\bin\git.exe" config --local --name-only --get-regexp ^includeIf\.gitdir: +2026-10-08T16:57:10.6333783Z [command]"C:\Program Files\Git\bin\git.exe" submodule foreach --recursive "git config --local --show-origin --name-only --get-regexp remote.origin.url" +2026-10-08T16:57:11.1760191Z Cleaning up orphan processes +2026-10-08T16:57:11.2116929Z Terminate orphan process: pid (7996) (vctip) +2026-10-08T16:57:11.2240138Z Terminate orphan process: pid (6124) (MSBuild) +2026-10-08T16:57:11.2496129Z Terminate orphan process: pid (5492) (conhost) +2026-10-08T16:57:11.2621801Z ##[warning]Node.js 20 is deprecated. The following actions target Node.js 20 but are being forced to run on Node.js 24: actions/checkout@v4, actions/setup-python@v5. For more information see: https://github.blog/changelog/2025-09-19-deprecation-of-node-20-on-github-actions-runners/ diff --git a/docs/receiving/windows-nested-gallery-e46e74cdc4f4/manifest.json b/docs/receiving/windows-nested-gallery-e46e74cdc4f4/manifest.json new file mode 100644 index 00000000..900cf184 --- /dev/null +++ b/docs/receiving/windows-nested-gallery-e46e74cdc4f4/manifest.json @@ -0,0 +1,51 @@ +{ + "schema": "capturesuite.pr80.receiving-manifest.v1", + "parent": "bd390a9d497e567cd868ba4029b74bbd509b4a78", + "candidate_test": { + "path": "tests/ui/test_analysis_nested_gallery.py", + "bytes": 7291, + "sha256": "566ff56a05014d47ffd887976751c06f259957a908ec34528725a039269b434f" + }, + "files": [ + { + "path": "INDEPENDENT_RECEIVING.md", + "bytes": 6052, + "sha256": "af5efd32ff6d8b8b972ba6402d7a577352ce526e06238ee3d80dda2f68342aaf" + }, + { + "path": "github-job-113430762650.log", + "bytes": 57921, + "sha256": "e9bbc99cb596b4016de2cfa7ab0729d8daff846e6e97459a8f2dec11af93a074" + }, + { + "path": "native/receipt.json", + "bytes": 2981, + "sha256": "a47567302f0e0b5b3cf2b205527856aaa1d1a5d48e87ba4d2c22d20027afab48" + }, + { + "path": "native/receive_windows_links.py", + "bytes": 6850, + "sha256": "314a5b53ec2ac56a05a57f0ff6ba7e29a7f49a048ec5ab65adf1c160e5cfba9b" + }, + { + "path": "native/process-start.json", + "bytes": 3884, + "sha256": "cc83122ed2544831ffb0dea3910912fd3c202eb32517e264bd68156dcd1fc781" + }, + { + "path": "native/process-completion.json", + "bytes": 575, + "sha256": "dac63725d0a8d3b95f778d6e2caed853c4a855389ba766b3343924c5b38683fe" + }, + { + "path": "test_analysis_nested_gallery.original.py", + "bytes": 7142, + "sha256": "727340556a0d8e4178b62157ba9680a59d1c43158abb1bf979b21be8c98c591f" + }, + { + "path": "native/source-payload.json", + "bytes": 15282, + "sha256": "21da53dd248c0b45863ccccc0b3fb4fc88a995a4cc774f805adab7ec6baabd69" + } + ] +} diff --git a/docs/receiving/windows-nested-gallery-e46e74cdc4f4/native/process-completion.json b/docs/receiving/windows-nested-gallery-e46e74cdc4f4/native/process-completion.json new file mode 100644 index 00000000..8f0cfe28 --- /dev/null +++ b/docs/receiving/windows-nested-gallery-e46e74cdc4f4/native/process-completion.json @@ -0,0 +1,13 @@ +{ + "content": [ + { + "type": "text", + "text": "[Reading last 5 lines (total: 85 lines)]\n\n \"receipt_directory\": \"C:\\\\Users\\\\minec\\\\hamon-cs80-receiving-e46e74cdc4f4\\\\native-20261008T171644Z\",\r\n \"time_utc\": \"2026-10-08T17:16:44Z\"\r\n}\r\nRECEIPT_SHA256=a47567302f0e0b5b3cf2b205527856aaa1d1a5d48e87ba4d2c22d20027afab48\r\n\n✅ Process completed with exit code 0 (runtime: 0.32s)" + }, + { + "type": "text", + "text": "\n[executed on device: DESKTOP-LA7CMTA (42ad330c-bb9a-4d2f-bcb4-6efeb4c6583e)]" + } + ], + "isError": false +} diff --git a/docs/receiving/windows-nested-gallery-e46e74cdc4f4/native/process-start.json b/docs/receiving/windows-nested-gallery-e46e74cdc4f4/native/process-start.json new file mode 100644 index 00000000..fde78367 --- /dev/null +++ b/docs/receiving/windows-nested-gallery-e46e74cdc4f4/native/process-start.json @@ -0,0 +1,13 @@ +{ + "content": [ + { + "type": "text", + "text": "Process started with PID 50068 (shell: powershell.exe)\nInitial output:\n{\r\n \"schema\": \"capturesuite.pr80.windows-link-assertion-receiving.v1\",\r\n \"accepted\": true,\r\n \"scope\": \"Actual Windows filesystem and exact original/candidate assertion statements; no Qt/gallery invocation\",\r\n \"gallery_invoked\": false,\r\n \"source_ref\": \"bd390a9d497e567cd868ba4029b74bbd509b4a78\",\r\n \"source\": {\r\n \"original\": {\r\n \"git_blob\": \"0874d6b51b22cbbeaa8b1e309ed92418efcec2c6\",\r\n \"sha256\": \"727340556a0d8e4178b62157ba9680a59d1c43158abb1bf979b21be8c98c591f\",\r\n \"bytes\": 7142\r\n },\r\n \"candidate\": {\r\n \"git_blob\": \"746084780e126b103489902f119b8e46c2fd8c98\",\r\n \"sha256\": \"566ff56a05014d47ffd887976751c06f259957a908ec34528725a039269b434f\",\r\n \"bytes\": 7291\r\n }\r\n },\r\n \"preservation\": {\r\n \"all_other_function_ast_nodes_identical\": true,\r\n \"source_bytes_unchanged\": true,\r\n \"healthy_fixture_target_bytes_unchanged\": true\r\n },\r\n \"checks\": [\r\n {\r\n \"name\": \"original_assertion_on_actual_absolute_windows_link\",\r\n \"status\": \"rejected\",\r\n \"exception\": \"AssertionError\",\r\n \"message\": \"\",\r\n \"raw_readlink\": \"\\\\\\\\?\\\\C:\\\\Users\\\\minec\\\\hamon-cs80-receiving-e46e74cdc4f4\\\\native-20261008T171644Z\\\\absolute\\\\external.png\",\r\n \"authored_target\": \"C:\\\\Users\\\\minec\\\\hamon-cs80-receiving-e46e74cdc4f4\\\\native-20261008T171644Z\\\\absolute\\\\external.png\",\r\n \"samefile\": true\r\n },\r\n {\r\n \"name\": \"candidate_exact_assertions_unchanged_absolute_link\",\r\n \"guard\": {\r\n \"status\": \"passed\"\r\n },\r\n \"after\": {\r\n \"status\": \"passed\"\r\n },\r\n \"raw_target_unchanged\": true\r\n },\r\n {\r\n \"name\": \"candidate_exact_assertions_unchanged_relative_link\",\r\n \"guard\": {\r\n \"status\": \"passed\"\r\n },\r\n \"after\": {\r\n \"status\": \"passed\"\r\n },\r\n \"raw_readlink\": \"..\\\\..\\\\external.png\",\r\n \"samefile\": true\r\n },\r\n {\r\n \"name\": \"negative_same_bytes_different_target\",\r\n \"status\": \"rejected\",\r\n \"exception\": \"AssertionError\",\r\n \"message\": \"\",\r\n \"targets_have_equal_bytes\": true\r\n },\r\n {\r\n \"name\": \"negative_link_replaced_by_regular_file\",\r\n \"status\": \"rejected\",\r\n \"exception\": \"OSError\",\r\n \"message\": \"[WinError 4390] The file or directory is not a reparse point: 'C:\\\\\\\\Users\\\\\\\\minec\\\\\\\\hamon-cs80-receiving-e46e74cdc4f4\\\\\\\\native-20261008T171644Z\\\\\\\\replaced_regular\\\\\\\\job\\\\\\\\figures\\\\\\\\foreign.png'\"\r\n },\r\n {\r\n \"name\": \"negative_initial_wrong_identity_same_bytes\",\r\n \"status\": \"rejected\",\r\n \"exception\": \"AssertionError\",\r\n \"message\": \"\",\r\n \"targets_have_equal_bytes\": true\r\n }\r\n ],\r\n \"python\": {\r\n \"executable\": \"C:\\\\Program Files\\\\WindowsApps\\\\PythonSoftwareFoundation.Python.3.11_3.11.2544.0_x64__qbz5n2kfra8p0\\\\python.exe\",\r\n \"version\": \"3.11.9 (tags/v3.11.9:de54cf5, Apr 2 2024, 10:12:12) [MSC v.1938 64 bit (AMD64)]\"\r\n },\r\n \"platform\": \"Windows-10-10.0.19045-SP0\",\r\n \"receipt_directory\": \"C:\\\\Users\\\\minec\\\\hamon-cs80-receiving-e46e74cdc4f4\\\\native-20261008T171644Z\",\r\n \"time_utc\": \"2026-10-08T17:16:44Z\"\r\n}\r\nRECEIPT_SHA256=a47567302f0e0b5b3cf2b205527856aaa1d1a5d48e87ba4d2c22d20027afab48\r\n" + }, + { + "type": "text", + "text": "\n[executed on device: DESKTOP-LA7CMTA (42ad330c-bb9a-4d2f-bcb4-6efeb4c6583e)]" + } + ], + "isError": false +} diff --git a/docs/receiving/windows-nested-gallery-e46e74cdc4f4/native/receipt.json b/docs/receiving/windows-nested-gallery-e46e74cdc4f4/native/receipt.json new file mode 100644 index 00000000..fc76063e --- /dev/null +++ b/docs/receiving/windows-nested-gallery-e46e74cdc4f4/native/receipt.json @@ -0,0 +1,83 @@ +{ + "schema": "capturesuite.pr80.windows-link-assertion-receiving.v1", + "accepted": true, + "scope": "Actual Windows filesystem and exact original/candidate assertion statements; no Qt/gallery invocation", + "gallery_invoked": false, + "source_ref": "bd390a9d497e567cd868ba4029b74bbd509b4a78", + "source": { + "original": { + "git_blob": "0874d6b51b22cbbeaa8b1e309ed92418efcec2c6", + "sha256": "727340556a0d8e4178b62157ba9680a59d1c43158abb1bf979b21be8c98c591f", + "bytes": 7142 + }, + "candidate": { + "git_blob": "746084780e126b103489902f119b8e46c2fd8c98", + "sha256": "566ff56a05014d47ffd887976751c06f259957a908ec34528725a039269b434f", + "bytes": 7291 + } + }, + "preservation": { + "all_other_function_ast_nodes_identical": true, + "source_bytes_unchanged": true, + "healthy_fixture_target_bytes_unchanged": true + }, + "checks": [ + { + "name": "original_assertion_on_actual_absolute_windows_link", + "status": "rejected", + "exception": "AssertionError", + "message": "", + "raw_readlink": "\\\\?\\C:\\Users\\minec\\hamon-cs80-receiving-e46e74cdc4f4\\native-20261008T171644Z\\absolute\\external.png", + "authored_target": "C:\\Users\\minec\\hamon-cs80-receiving-e46e74cdc4f4\\native-20261008T171644Z\\absolute\\external.png", + "samefile": true + }, + { + "name": "candidate_exact_assertions_unchanged_absolute_link", + "guard": { + "status": "passed" + }, + "after": { + "status": "passed" + }, + "raw_target_unchanged": true + }, + { + "name": "candidate_exact_assertions_unchanged_relative_link", + "guard": { + "status": "passed" + }, + "after": { + "status": "passed" + }, + "raw_readlink": "..\\..\\external.png", + "samefile": true + }, + { + "name": "negative_same_bytes_different_target", + "status": "rejected", + "exception": "AssertionError", + "message": "", + "targets_have_equal_bytes": true + }, + { + "name": "negative_link_replaced_by_regular_file", + "status": "rejected", + "exception": "OSError", + "message": "[WinError 4390] The file or directory is not a reparse point: 'C:\\\\Users\\\\minec\\\\hamon-cs80-receiving-e46e74cdc4f4\\\\native-20261008T171644Z\\\\replaced_regular\\\\job\\\\figures\\\\foreign.png'" + }, + { + "name": "negative_initial_wrong_identity_same_bytes", + "status": "rejected", + "exception": "AssertionError", + "message": "", + "targets_have_equal_bytes": true + } + ], + "python": { + "executable": "C:\\Program Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.11_3.11.2544.0_x64__qbz5n2kfra8p0\\python.exe", + "version": "3.11.9 (tags/v3.11.9:de54cf5, Apr 2 2024, 10:12:12) [MSC v.1938 64 bit (AMD64)]" + }, + "platform": "Windows-10-10.0.19045-SP0", + "receipt_directory": "C:\\Users\\minec\\hamon-cs80-receiving-e46e74cdc4f4\\native-20261008T171644Z", + "time_utc": "2026-10-08T17:16:44Z" +} diff --git a/docs/receiving/windows-nested-gallery-e46e74cdc4f4/native/receive_windows_links.py b/docs/receiving/windows-nested-gallery-e46e74cdc4f4/native/receive_windows_links.py new file mode 100644 index 00000000..1ca3a2b7 --- /dev/null +++ b/docs/receiving/windows-nested-gallery-e46e74cdc4f4/native/receive_windows_links.py @@ -0,0 +1,145 @@ +# SPDX-License-Identifier: GPL-3.0-only +"""Independent Windows filesystem receiving of PR80's exact assertion correction. +No Qt/gallery code is invoked; hosted run 37811945519 supplies the full-suite baseline. +""" +from __future__ import annotations +import ast +import hashlib +import json +import os +from pathlib import Path +import platform +import sys +import time + +ROOT = Path(__file__).resolve().parent +OUT = ROOT / ("native-" + time.strftime("%Y%m%dT%H%M%SZ", time.gmtime())) +OUT.mkdir() +payload = json.loads((ROOT / "source-payload.json").read_text(encoding="utf-8")) +expected = { + "original": ("0874d6b51b22cbbeaa8b1e309ed92418efcec2c6", "727340556a0d8e4178b62157ba9680a59d1c43158abb1bf979b21be8c98c591f"), + "candidate": ("746084780e126b103489902f119b8e46c2fd8c98", "566ff56a05014d47ffd887976751c06f259957a908ec34528725a039269b434f"), +} +source = {} +for name, (git, sha) in expected.items(): + data = payload[name].encode("utf-8") + assert hashlib.sha256(data).hexdigest() == sha + assert hashlib.sha1(b"blob " + str(len(data)).encode() + b"\0" + data).hexdigest() == git + (OUT / (name + ".py")).write_bytes(data) + source[name] = {"git_blob": git, "sha256": sha, "bytes": len(data)} + +def function(text): + return next(n for n in ast.parse(text).body if isinstance(n, ast.FunctionDef) + and n.name == "test_png_discovery_refuses_external_file_links_and_directories") + +def has_call(node, name): + return any(isinstance(n, ast.Call) and isinstance(n.func, ast.Attribute) and n.func.attr == name + for n in ast.walk(node)) + +old = function(payload["original"]) +new = function(payload["candidate"]) +old_after = next(n for n in old.body if isinstance(n, ast.Assert) and has_call(n, "readlink")) +new_before = [n for n in new.body if + (isinstance(n, ast.Assign) and has_call(n, "readlink")) + or (isinstance(n, ast.Assert) and has_call(n, "samefile"))] +new_after = next(n for n in new.body if isinstance(n, ast.Assert) and has_call(n, "readlink")) +assert len(new_before) == 2 +old_rest = [n for n in old.body if n is not old_after] +new_rest = [n for n in new.body if n not in new_before and n is not new_after] +assert ast.dump(ast.Module(body=old_rest, type_ignores=[])) == ast.dump(ast.Module(body=new_rest, type_ignores=[])) + +def statements(nodes, scope): + try: + exec(compile(ast.Module(body=nodes, type_ignores=[]), "", "exec"), scope) + except Exception as exc: + return {"status": "rejected", "exception": type(exc).__name__, "message": str(exc)} + return {"status": "passed"} + +def fixture(name, *, relative=False, wrong=False): + root = OUT / name + folder = root / "job" / "figures" + folder.mkdir(parents=True) + outside = root / "external.png" + other = root / "other.png" + outside.write_bytes(b"filesystem identity fixture; not a Qt image\n") + other.write_bytes(outside.read_bytes()) + foreign = folder / "foreign.png" + target = other if wrong else outside + if relative: + target = Path(os.path.relpath(target, foreign.parent)) + foreign.symlink_to(target) + return {"foreign": foreign, "outside": outside, "other": other}, root + +checks = [] +def record(name, result): + checks.append({"name": name, **result}) + +scope, root = fixture("absolute") +foreign, outside = scope["foreign"], scope["outside"] +raw_before = foreign.readlink() +before = {p.name: hashlib.sha256(p.read_bytes()).hexdigest() for p in (outside, scope["other"])} +baseline = statements([old_after], dict(scope)) +record("original_assertion_on_actual_absolute_windows_link", { + **baseline, "raw_readlink": str(raw_before), "authored_target": str(outside), + "samefile": foreign.samefile(outside), +}) +assert baseline["status"] == "rejected" and baseline["exception"] == "AssertionError" +assert foreign.samefile(outside) +guard = statements(new_before, scope) +after = statements([new_after], scope) +record("candidate_exact_assertions_unchanged_absolute_link", {"guard": guard, "after": after, + "raw_target_unchanged": foreign.readlink() == raw_before}) +assert guard["status"] == after["status"] == "passed" + +scope, _ = fixture("relative", relative=True) +raw = scope["foreign"].readlink() +guard = statements(new_before, scope) +after = statements([new_after], scope) +record("candidate_exact_assertions_unchanged_relative_link", { + "guard": guard, "after": after, "raw_readlink": str(raw), "samefile": scope["foreign"].samefile(scope["outside"])}) +assert guard["status"] == after["status"] == "passed" + +scope, _ = fixture("changed_target") +assert statements(new_before, scope)["status"] == "passed" +scope["foreign"].unlink() +scope["foreign"].symlink_to(scope["other"]) +changed = statements([new_after], scope) +record("negative_same_bytes_different_target", {**changed, "targets_have_equal_bytes": scope["outside"].read_bytes() == scope["other"].read_bytes()}) +assert changed["status"] == "rejected" and changed["exception"] == "AssertionError" + +scope, _ = fixture("replaced_regular") +assert statements(new_before, scope)["status"] == "passed" +scope["foreign"].unlink() +scope["foreign"].write_bytes(scope["outside"].read_bytes()) +replaced = statements([new_after], scope) +record("negative_link_replaced_by_regular_file", replaced) +assert replaced["status"] == "rejected" and replaced["exception"] in ("OSError", "ValueError") + +scope, _ = fixture("wrong_initial_target", wrong=True) +wrong = statements(new_before, scope) +record("negative_initial_wrong_identity_same_bytes", {**wrong, "targets_have_equal_bytes": scope["outside"].read_bytes() == scope["other"].read_bytes()}) +assert wrong["status"] == "rejected" and wrong["exception"] == "AssertionError" + +assert before == {p.name: hashlib.sha256(p.read_bytes()).hexdigest() for p in (outside, root / "other.png")} +for name, (_, sha) in expected.items(): + assert hashlib.sha256((OUT / (name + ".py")).read_bytes()).hexdigest() == sha + +receipt = { + "schema": "capturesuite.pr80.windows-link-assertion-receiving.v1", + "accepted": True, + "scope": "Actual Windows filesystem and exact original/candidate assertion statements; no Qt/gallery invocation", + "gallery_invoked": False, + "source_ref": payload["source_ref"], + "source": source, + "preservation": {"all_other_function_ast_nodes_identical": True, "source_bytes_unchanged": True, + "healthy_fixture_target_bytes_unchanged": True}, + "checks": checks, + "python": {"executable": sys.executable, "version": sys.version}, + "platform": platform.platform(), + "receipt_directory": str(OUT), + "time_utc": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()), +} +data = json.dumps(receipt, ensure_ascii=False, indent=2).encode("utf-8") + b"\n" +(OUT / "receipt.json").write_bytes(data) +print(data.decode("utf-8"), end="") +print("RECEIPT_SHA256=" + hashlib.sha256(data).hexdigest()) diff --git a/docs/receiving/windows-nested-gallery-e46e74cdc4f4/native/source-payload.json b/docs/receiving/windows-nested-gallery-e46e74cdc4f4/native/source-payload.json new file mode 100644 index 00000000..66e73ad6 --- /dev/null +++ b/docs/receiving/windows-nested-gallery-e46e74cdc4f4/native/source-payload.json @@ -0,0 +1 @@ +{"source_ref":"bd390a9d497e567cd868ba4029b74bbd509b4a78","original":"# SPDX-License-Identifier: GPL-3.0-only\n\"\"\"Native saved PNG discovery across current nested and legacy flat layouts.\"\"\"\n\nfrom __future__ import annotations\n\nimport hashlib\nimport json\nfrom pathlib import Path\n\nimport pytest\n\npytest.importorskip(\"PySide6\")\n\n\ndef _png(path: Path, color: str) -> None:\n from PySide6.QtGui import QColor, QImage\n\n path.parent.mkdir(parents=True, exist_ok=True)\n image = QImage(16, 12, QImage.Format.Format_RGB32)\n image.fill(QColor(color))\n assert image.save(str(path), \"PNG\")\n\n\ndef _hashes(path: Path) -> dict[str, str]:\n return {str(p.relative_to(path)): hashlib.sha256(p.read_bytes()).hexdigest()\n for p in path.rglob(\"*\") if p.is_file()}\n\n\ndef _numeric_path(job: Path, source: str, stream: str, channel: int = 0) -> Path:\n return (job / \"figures/numeric\" / f\"source-{source.encode().hex()}\"\n / f\"stream-{stream.encode().hex()}\" / f\"channel_{channel}.png\")\n\n\ndef _titles(gallery) -> list[str]:\n return [gallery._tabs.tabText(i) for i in range(gallery._tabs.count())]\n\n\ndef _color(gallery, index: int) -> str:\n label = gallery._tabs.widget(index).widget()\n return label.pixmap().toImage().pixelColor(0, 0).name()\n\n\ndef test_flat_figures_and_sync_dashboard_keep_their_existing_behavior(qapp, tmp_path):\n from capture_desktop.widgets_analysis_plots import FigureGallery\n\n _png(tmp_path / \"figures/legacy_signal.png\", \"#2855cc\")\n _png(tmp_path / \"figures/sync_dashboard.png\", \"#000000\")\n before = _hashes(tmp_path)\n gallery = FigureGallery()\n gallery.load_job_dir(tmp_path)\n assert _titles(gallery) == [\"Sync\", \"legacy signal\"]\n assert _color(gallery, 1) == \"#2855cc\"\n assert gallery._tabs.tabToolTip(1) == \"legacy_signal.png\"\n assert _hashes(tmp_path) == before\n gallery.close()\n\n\ndef test_nested_numeric_figures_preserve_channels_and_linked_series(qapp, tmp_path):\n from capture_desktop.widgets_analysis_plots import FigureGallery\n\n for channel, color in enumerate((\"#cc3322\", \"#22aa55\")):\n _png(_numeric_path(tmp_path, \"lsl\", \"numeric.stream\", channel), color)\n doc = {\n \"schemaId\": \"capture.sync_dashboard_series/1\", \"title\": \"retained numeric\",\n \"window\": {\"startSessionNs\": 0, \"endSessionNs\": 1_000_000_000}, \"gaps\": [],\n \"series\": [{\"label\": f\"channel {i}\", \"t_ns\": [0, 500_000_000, 1_000_000_000],\n \"y\": [i, i + 1, i + 2]} for i in range(2)],\n }\n (tmp_path / \"figures/sync_dashboard_series.json\").write_text(json.dumps(doc))\n before = _hashes(tmp_path)\n gallery = FigureGallery()\n gallery.load_job_dir(tmp_path)\n assert _titles(gallery) == [\"Sync\", \"lsl / numeric.stream / channel 0\",\n \"lsl / numeric.stream / channel 1\"]\n assert [_color(gallery, i) for i in (1, 2)] == [\"#cc3322\", \"#22aa55\"]\n assert len(gallery._sync._linked) == 2\n assert gallery._sync._title.text() == \"retained numeric\"\n for i in (1, 2):\n expected = _numeric_path(tmp_path, \"lsl\", \"numeric.stream\", i - 1)\n assert gallery._tabs.tabToolTip(i) == expected.relative_to(tmp_path / \"figures\").as_posix()\n assert _hashes(tmp_path) == before\n gallery.close()\n\n\ndef test_same_filename_retains_case_unicode_and_stream_identity(qapp, tmp_path):\n from capture_desktop.widgets_analysis_plots import FigureGallery\n\n identities = [(\"Arm\", \"force\", \"#aabbcc\"), (\"arm\", \"force\", \"#bbccdd\"),\n (\"café\", \"force / left\", \"#ccddee\")]\n for source, stream, color in identities:\n _png(_numeric_path(tmp_path, source, stream), color)\n before = _hashes(tmp_path)\n gallery = FigureGallery()\n gallery.load_job_dir(tmp_path)\n by_title = {gallery._tabs.tabText(i): _color(gallery, i)\n for i in range(1, gallery._tabs.count())}\n assert by_title == {f\"{source} / {stream} / channel 0\": color\n for source, stream, color in identities}\n tips = [gallery._tabs.tabToolTip(i) for i in range(1, gallery._tabs.count())]\n assert len(set(tips)) == 3\n assert _hashes(tmp_path) == before\n gallery.close()\n\n\ndef test_unknown_nested_paths_and_nested_dashboard_png_remain_inspectable(qapp, tmp_path):\n from capture_desktop.widgets_analysis_plots import FigureGallery\n\n _png(tmp_path / \"figures/custom/sync_dashboard.png\", \"#ddeeff\")\n _png(tmp_path / \"figures/numeric/source-zz/stream-e9/channel_0.png\", \"#eeff11\")\n _png(tmp_path / \"figures/sync_dashboard.png\", \"#000000\")\n gallery = FigureGallery()\n gallery.load_job_dir(tmp_path)\n assert _titles(gallery) == [\"Sync\", \"custom / sync dashboard\",\n \"numeric / source-zz / stream-e9 / channel 0\"]\n assert [_color(gallery, i) for i in (1, 2)] == [\"#ddeeff\", \"#eeff11\"]\n gallery.close()\n\n\ndef test_reloading_a_job_replaces_nested_and_flat_tabs(qapp, tmp_path):\n from capture_desktop.widgets_analysis_plots import FigureGallery\n\n first, second, empty = (tmp_path / name for name in (\"first\", \"second\", \"empty\"))\n _png(_numeric_path(first, \"a\", \"b\"), \"#112233\")\n _png(first / \"figures/flat.png\", \"#223344\")\n _png(second / \"figures/new_signal.png\", \"#334455\")\n empty.mkdir()\n before = _hashes(tmp_path)\n gallery = FigureGallery()\n gallery.load_job_dir(first)\n assert gallery._tabs.count() == 3\n gallery.load_job_dir(second)\n assert _titles(gallery) == [\"Sync\", \"new signal\"]\n assert _color(gallery, 1) == \"#334455\"\n gallery.load_job_dir(empty)\n assert _titles(gallery) == [\"Sync\"]\n assert not gallery._sync._linked\n assert _hashes(tmp_path) == before\n gallery.close()\n\n\ndef test_one_unreadable_png_does_not_hide_other_saved_figures(qapp, tmp_path):\n from capture_desktop.widgets_analysis_plots import FigureGallery\n\n _png(tmp_path / \"figures/nested/good.png\", \"#445566\")\n bad = tmp_path / \"figures/nested/bad.png\"\n bad.write_bytes(b\"not an image\")\n before = _hashes(tmp_path)\n gallery = FigureGallery()\n gallery.load_job_dir(tmp_path)\n assert _titles(gallery) == [\"Sync\", \"nested / bad\", \"nested / good\"]\n assert gallery._tabs.widget(1).widget().text() == \"Could not load bad.png\"\n assert _color(gallery, 2) == \"#445566\"\n assert _hashes(tmp_path) == before\n gallery.close()\n\n\ndef test_png_discovery_refuses_external_file_links_and_directories(qapp, tmp_path):\n from capture_desktop.widgets_analysis_plots import FigureGallery\n\n job = tmp_path / \"job\"\n outside = tmp_path / \"external.png\"\n _png(outside, \"#aa1122\")\n _png(job / \"figures/nested/good.png\", \"#22aa55\")\n foreign = job / \"figures/foreign.png\"\n try:\n foreign.symlink_to(outside)\n except OSError as exc:\n pytest.skip(f\"This filesystem cannot create the symlink fixture: {exc}\")\n (job / \"figures/not_a_file.png\").mkdir()\n before = _hashes(tmp_path)\n gallery = FigureGallery()\n gallery.load_job_dir(job)\n assert _titles(gallery) == [\"Sync\", \"nested / good\"]\n assert _color(gallery, 1) == \"#22aa55\"\n assert gallery._tabs.tabToolTip(1) == \"nested/good.png\"\n assert foreign.readlink() == outside\n assert _hashes(tmp_path) == before\n gallery.close()\n","candidate":"# SPDX-License-Identifier: GPL-3.0-only\n\"\"\"Native saved PNG discovery across current nested and legacy flat layouts.\"\"\"\n\nfrom __future__ import annotations\n\nimport hashlib\nimport json\nfrom pathlib import Path\n\nimport pytest\n\npytest.importorskip(\"PySide6\")\n\n\ndef _png(path: Path, color: str) -> None:\n from PySide6.QtGui import QColor, QImage\n\n path.parent.mkdir(parents=True, exist_ok=True)\n image = QImage(16, 12, QImage.Format.Format_RGB32)\n image.fill(QColor(color))\n assert image.save(str(path), \"PNG\")\n\n\ndef _hashes(path: Path) -> dict[str, str]:\n return {str(p.relative_to(path)): hashlib.sha256(p.read_bytes()).hexdigest()\n for p in path.rglob(\"*\") if p.is_file()}\n\n\ndef _numeric_path(job: Path, source: str, stream: str, channel: int = 0) -> Path:\n return (job / \"figures/numeric\" / f\"source-{source.encode().hex()}\"\n / f\"stream-{stream.encode().hex()}\" / f\"channel_{channel}.png\")\n\n\ndef _titles(gallery) -> list[str]:\n return [gallery._tabs.tabText(i) for i in range(gallery._tabs.count())]\n\n\ndef _color(gallery, index: int) -> str:\n label = gallery._tabs.widget(index).widget()\n return label.pixmap().toImage().pixelColor(0, 0).name()\n\n\ndef test_flat_figures_and_sync_dashboard_keep_their_existing_behavior(qapp, tmp_path):\n from capture_desktop.widgets_analysis_plots import FigureGallery\n\n _png(tmp_path / \"figures/legacy_signal.png\", \"#2855cc\")\n _png(tmp_path / \"figures/sync_dashboard.png\", \"#000000\")\n before = _hashes(tmp_path)\n gallery = FigureGallery()\n gallery.load_job_dir(tmp_path)\n assert _titles(gallery) == [\"Sync\", \"legacy signal\"]\n assert _color(gallery, 1) == \"#2855cc\"\n assert gallery._tabs.tabToolTip(1) == \"legacy_signal.png\"\n assert _hashes(tmp_path) == before\n gallery.close()\n\n\ndef test_nested_numeric_figures_preserve_channels_and_linked_series(qapp, tmp_path):\n from capture_desktop.widgets_analysis_plots import FigureGallery\n\n for channel, color in enumerate((\"#cc3322\", \"#22aa55\")):\n _png(_numeric_path(tmp_path, \"lsl\", \"numeric.stream\", channel), color)\n doc = {\n \"schemaId\": \"capture.sync_dashboard_series/1\", \"title\": \"retained numeric\",\n \"window\": {\"startSessionNs\": 0, \"endSessionNs\": 1_000_000_000}, \"gaps\": [],\n \"series\": [{\"label\": f\"channel {i}\", \"t_ns\": [0, 500_000_000, 1_000_000_000],\n \"y\": [i, i + 1, i + 2]} for i in range(2)],\n }\n (tmp_path / \"figures/sync_dashboard_series.json\").write_text(json.dumps(doc))\n before = _hashes(tmp_path)\n gallery = FigureGallery()\n gallery.load_job_dir(tmp_path)\n assert _titles(gallery) == [\"Sync\", \"lsl / numeric.stream / channel 0\",\n \"lsl / numeric.stream / channel 1\"]\n assert [_color(gallery, i) for i in (1, 2)] == [\"#cc3322\", \"#22aa55\"]\n assert len(gallery._sync._linked) == 2\n assert gallery._sync._title.text() == \"retained numeric\"\n for i in (1, 2):\n expected = _numeric_path(tmp_path, \"lsl\", \"numeric.stream\", i - 1)\n assert gallery._tabs.tabToolTip(i) == expected.relative_to(tmp_path / \"figures\").as_posix()\n assert _hashes(tmp_path) == before\n gallery.close()\n\n\ndef test_same_filename_retains_case_unicode_and_stream_identity(qapp, tmp_path):\n from capture_desktop.widgets_analysis_plots import FigureGallery\n\n identities = [(\"Arm\", \"force\", \"#aabbcc\"), (\"arm\", \"force\", \"#bbccdd\"),\n (\"café\", \"force / left\", \"#ccddee\")]\n for source, stream, color in identities:\n _png(_numeric_path(tmp_path, source, stream), color)\n before = _hashes(tmp_path)\n gallery = FigureGallery()\n gallery.load_job_dir(tmp_path)\n by_title = {gallery._tabs.tabText(i): _color(gallery, i)\n for i in range(1, gallery._tabs.count())}\n assert by_title == {f\"{source} / {stream} / channel 0\": color\n for source, stream, color in identities}\n tips = [gallery._tabs.tabToolTip(i) for i in range(1, gallery._tabs.count())]\n assert len(set(tips)) == 3\n assert _hashes(tmp_path) == before\n gallery.close()\n\n\ndef test_unknown_nested_paths_and_nested_dashboard_png_remain_inspectable(qapp, tmp_path):\n from capture_desktop.widgets_analysis_plots import FigureGallery\n\n _png(tmp_path / \"figures/custom/sync_dashboard.png\", \"#ddeeff\")\n _png(tmp_path / \"figures/numeric/source-zz/stream-e9/channel_0.png\", \"#eeff11\")\n _png(tmp_path / \"figures/sync_dashboard.png\", \"#000000\")\n gallery = FigureGallery()\n gallery.load_job_dir(tmp_path)\n assert _titles(gallery) == [\"Sync\", \"custom / sync dashboard\",\n \"numeric / source-zz / stream-e9 / channel 0\"]\n assert [_color(gallery, i) for i in (1, 2)] == [\"#ddeeff\", \"#eeff11\"]\n gallery.close()\n\n\ndef test_reloading_a_job_replaces_nested_and_flat_tabs(qapp, tmp_path):\n from capture_desktop.widgets_analysis_plots import FigureGallery\n\n first, second, empty = (tmp_path / name for name in (\"first\", \"second\", \"empty\"))\n _png(_numeric_path(first, \"a\", \"b\"), \"#112233\")\n _png(first / \"figures/flat.png\", \"#223344\")\n _png(second / \"figures/new_signal.png\", \"#334455\")\n empty.mkdir()\n before = _hashes(tmp_path)\n gallery = FigureGallery()\n gallery.load_job_dir(first)\n assert gallery._tabs.count() == 3\n gallery.load_job_dir(second)\n assert _titles(gallery) == [\"Sync\", \"new signal\"]\n assert _color(gallery, 1) == \"#334455\"\n gallery.load_job_dir(empty)\n assert _titles(gallery) == [\"Sync\"]\n assert not gallery._sync._linked\n assert _hashes(tmp_path) == before\n gallery.close()\n\n\ndef test_one_unreadable_png_does_not_hide_other_saved_figures(qapp, tmp_path):\n from capture_desktop.widgets_analysis_plots import FigureGallery\n\n _png(tmp_path / \"figures/nested/good.png\", \"#445566\")\n bad = tmp_path / \"figures/nested/bad.png\"\n bad.write_bytes(b\"not an image\")\n before = _hashes(tmp_path)\n gallery = FigureGallery()\n gallery.load_job_dir(tmp_path)\n assert _titles(gallery) == [\"Sync\", \"nested / bad\", \"nested / good\"]\n assert gallery._tabs.widget(1).widget().text() == \"Could not load bad.png\"\n assert _color(gallery, 2) == \"#445566\"\n assert _hashes(tmp_path) == before\n gallery.close()\n\n\ndef test_png_discovery_refuses_external_file_links_and_directories(qapp, tmp_path):\n from capture_desktop.widgets_analysis_plots import FigureGallery\n\n job = tmp_path / \"job\"\n outside = tmp_path / \"external.png\"\n _png(outside, \"#aa1122\")\n _png(job / \"figures/nested/good.png\", \"#22aa55\")\n foreign = job / \"figures/foreign.png\"\n try:\n foreign.symlink_to(outside)\n except OSError as exc:\n pytest.skip(f\"This filesystem cannot create the symlink fixture: {exc}\")\n link_before = foreign.readlink()\n assert foreign.samefile(outside)\n (job / \"figures/not_a_file.png\").mkdir()\n before = _hashes(tmp_path)\n gallery = FigureGallery()\n gallery.load_job_dir(job)\n assert _titles(gallery) == [\"Sync\", \"nested / good\"]\n assert _color(gallery, 1) == \"#22aa55\"\n assert gallery._tabs.tabToolTip(1) == \"nested/good.png\"\n # Windows may retain an extended-length prefix in the link target.\n assert foreign.readlink() == link_before\n assert _hashes(tmp_path) == before\n gallery.close()\n"} \ No newline at end of file diff --git a/docs/receiving/windows-nested-gallery-e46e74cdc4f4/root-review.json b/docs/receiving/windows-nested-gallery-e46e74cdc4f4/root-review.json new file mode 100644 index 00000000..f7d6f97a --- /dev/null +++ b/docs/receiving/windows-nested-gallery-e46e74cdc4f4/root-review.json @@ -0,0 +1,28 @@ +{ + "schema": "capturesuite.pr80.root-source-review.v1", + "reviewer": "chatgpt:/root", + "received_by": "chatgpt:/root/source_frontier", + "decision": "accept narrow Windows test-fixture correction for local successor and owner-path integration", + "source_parent": "bd390a9d497e567cd868ba4029b74bbd509b4a78", + "original_test_blob": "0874d6b51b22cbbeaa8b1e309ed92418efcec2c6", + "candidate_test_blob": "746084780e126b103489902f119b8e46c2fd8c98", + "candidate_test_sha256": "566ff56a05014d47ffd887976751c06f259957a908ec34528725a039269b434f", + "native_receipt_sha256": "a47567302f0e0b5b3cf2b205527856aaa1d1a5d48e87ba4d2c22d20027afab48", + "native_method_sha256": "314a5b53ec2ac56a05a57f0ff6ba7e29a7f49a048ec5ab65adf1c160e5cfba9b", + "reviewed_inputs": [ + ".git/source-review.json", + "native/receipt.json", + "native/receive_windows_links.py" + ], + "unchanged_parent_leaves_and_modes": 1070, + "findings": [ + "One existing test source changes; exact candidate blob is root-authored.", + "Native absolute and relative identity controls plus changed-link/regular-file/wrong-initial-target negative controls are discriminating.", + "All other AST nodes in the affected test function remain equal.", + "No Qt/gallery invocation; actual Windows Python 3.11.9 assertion receiving is distinct from the Python3.12 hosted baseline." + ], + "limits": [ + "Updated-head hosted full suite remains required.", + "No production-gallery source change, remote source write, PR state transition, main merge, deployment, or ownership transfer is approved by this receipt." + ] +} diff --git a/docs/receiving/windows-nested-gallery-e46e74cdc4f4/test_analysis_nested_gallery.original.py b/docs/receiving/windows-nested-gallery-e46e74cdc4f4/test_analysis_nested_gallery.original.py new file mode 100644 index 00000000..0874d6b5 --- /dev/null +++ b/docs/receiving/windows-nested-gallery-e46e74cdc4f4/test_analysis_nested_gallery.original.py @@ -0,0 +1,178 @@ +# SPDX-License-Identifier: GPL-3.0-only +"""Native saved PNG discovery across current nested and legacy flat layouts.""" + +from __future__ import annotations + +import hashlib +import json +from pathlib import Path + +import pytest + +pytest.importorskip("PySide6") + + +def _png(path: Path, color: str) -> None: + from PySide6.QtGui import QColor, QImage + + path.parent.mkdir(parents=True, exist_ok=True) + image = QImage(16, 12, QImage.Format.Format_RGB32) + image.fill(QColor(color)) + assert image.save(str(path), "PNG") + + +def _hashes(path: Path) -> dict[str, str]: + return {str(p.relative_to(path)): hashlib.sha256(p.read_bytes()).hexdigest() + for p in path.rglob("*") if p.is_file()} + + +def _numeric_path(job: Path, source: str, stream: str, channel: int = 0) -> Path: + return (job / "figures/numeric" / f"source-{source.encode().hex()}" + / f"stream-{stream.encode().hex()}" / f"channel_{channel}.png") + + +def _titles(gallery) -> list[str]: + return [gallery._tabs.tabText(i) for i in range(gallery._tabs.count())] + + +def _color(gallery, index: int) -> str: + label = gallery._tabs.widget(index).widget() + return label.pixmap().toImage().pixelColor(0, 0).name() + + +def test_flat_figures_and_sync_dashboard_keep_their_existing_behavior(qapp, tmp_path): + from capture_desktop.widgets_analysis_plots import FigureGallery + + _png(tmp_path / "figures/legacy_signal.png", "#2855cc") + _png(tmp_path / "figures/sync_dashboard.png", "#000000") + before = _hashes(tmp_path) + gallery = FigureGallery() + gallery.load_job_dir(tmp_path) + assert _titles(gallery) == ["Sync", "legacy signal"] + assert _color(gallery, 1) == "#2855cc" + assert gallery._tabs.tabToolTip(1) == "legacy_signal.png" + assert _hashes(tmp_path) == before + gallery.close() + + +def test_nested_numeric_figures_preserve_channels_and_linked_series(qapp, tmp_path): + from capture_desktop.widgets_analysis_plots import FigureGallery + + for channel, color in enumerate(("#cc3322", "#22aa55")): + _png(_numeric_path(tmp_path, "lsl", "numeric.stream", channel), color) + doc = { + "schemaId": "capture.sync_dashboard_series/1", "title": "retained numeric", + "window": {"startSessionNs": 0, "endSessionNs": 1_000_000_000}, "gaps": [], + "series": [{"label": f"channel {i}", "t_ns": [0, 500_000_000, 1_000_000_000], + "y": [i, i + 1, i + 2]} for i in range(2)], + } + (tmp_path / "figures/sync_dashboard_series.json").write_text(json.dumps(doc)) + before = _hashes(tmp_path) + gallery = FigureGallery() + gallery.load_job_dir(tmp_path) + assert _titles(gallery) == ["Sync", "lsl / numeric.stream / channel 0", + "lsl / numeric.stream / channel 1"] + assert [_color(gallery, i) for i in (1, 2)] == ["#cc3322", "#22aa55"] + assert len(gallery._sync._linked) == 2 + assert gallery._sync._title.text() == "retained numeric" + for i in (1, 2): + expected = _numeric_path(tmp_path, "lsl", "numeric.stream", i - 1) + assert gallery._tabs.tabToolTip(i) == expected.relative_to(tmp_path / "figures").as_posix() + assert _hashes(tmp_path) == before + gallery.close() + + +def test_same_filename_retains_case_unicode_and_stream_identity(qapp, tmp_path): + from capture_desktop.widgets_analysis_plots import FigureGallery + + identities = [("Arm", "force", "#aabbcc"), ("arm", "force", "#bbccdd"), + ("café", "force / left", "#ccddee")] + for source, stream, color in identities: + _png(_numeric_path(tmp_path, source, stream), color) + before = _hashes(tmp_path) + gallery = FigureGallery() + gallery.load_job_dir(tmp_path) + by_title = {gallery._tabs.tabText(i): _color(gallery, i) + for i in range(1, gallery._tabs.count())} + assert by_title == {f"{source} / {stream} / channel 0": color + for source, stream, color in identities} + tips = [gallery._tabs.tabToolTip(i) for i in range(1, gallery._tabs.count())] + assert len(set(tips)) == 3 + assert _hashes(tmp_path) == before + gallery.close() + + +def test_unknown_nested_paths_and_nested_dashboard_png_remain_inspectable(qapp, tmp_path): + from capture_desktop.widgets_analysis_plots import FigureGallery + + _png(tmp_path / "figures/custom/sync_dashboard.png", "#ddeeff") + _png(tmp_path / "figures/numeric/source-zz/stream-e9/channel_0.png", "#eeff11") + _png(tmp_path / "figures/sync_dashboard.png", "#000000") + gallery = FigureGallery() + gallery.load_job_dir(tmp_path) + assert _titles(gallery) == ["Sync", "custom / sync dashboard", + "numeric / source-zz / stream-e9 / channel 0"] + assert [_color(gallery, i) for i in (1, 2)] == ["#ddeeff", "#eeff11"] + gallery.close() + + +def test_reloading_a_job_replaces_nested_and_flat_tabs(qapp, tmp_path): + from capture_desktop.widgets_analysis_plots import FigureGallery + + first, second, empty = (tmp_path / name for name in ("first", "second", "empty")) + _png(_numeric_path(first, "a", "b"), "#112233") + _png(first / "figures/flat.png", "#223344") + _png(second / "figures/new_signal.png", "#334455") + empty.mkdir() + before = _hashes(tmp_path) + gallery = FigureGallery() + gallery.load_job_dir(first) + assert gallery._tabs.count() == 3 + gallery.load_job_dir(second) + assert _titles(gallery) == ["Sync", "new signal"] + assert _color(gallery, 1) == "#334455" + gallery.load_job_dir(empty) + assert _titles(gallery) == ["Sync"] + assert not gallery._sync._linked + assert _hashes(tmp_path) == before + gallery.close() + + +def test_one_unreadable_png_does_not_hide_other_saved_figures(qapp, tmp_path): + from capture_desktop.widgets_analysis_plots import FigureGallery + + _png(tmp_path / "figures/nested/good.png", "#445566") + bad = tmp_path / "figures/nested/bad.png" + bad.write_bytes(b"not an image") + before = _hashes(tmp_path) + gallery = FigureGallery() + gallery.load_job_dir(tmp_path) + assert _titles(gallery) == ["Sync", "nested / bad", "nested / good"] + assert gallery._tabs.widget(1).widget().text() == "Could not load bad.png" + assert _color(gallery, 2) == "#445566" + assert _hashes(tmp_path) == before + gallery.close() + + +def test_png_discovery_refuses_external_file_links_and_directories(qapp, tmp_path): + from capture_desktop.widgets_analysis_plots import FigureGallery + + job = tmp_path / "job" + outside = tmp_path / "external.png" + _png(outside, "#aa1122") + _png(job / "figures/nested/good.png", "#22aa55") + foreign = job / "figures/foreign.png" + try: + foreign.symlink_to(outside) + except OSError as exc: + pytest.skip(f"This filesystem cannot create the symlink fixture: {exc}") + (job / "figures/not_a_file.png").mkdir() + before = _hashes(tmp_path) + gallery = FigureGallery() + gallery.load_job_dir(job) + assert _titles(gallery) == ["Sync", "nested / good"] + assert _color(gallery, 1) == "#22aa55" + assert gallery._tabs.tabToolTip(1) == "nested/good.png" + assert foreign.readlink() == outside + assert _hashes(tmp_path) == before + gallery.close() diff --git a/tests/ui/test_analysis_history.py b/tests/ui/test_analysis_history.py new file mode 100644 index 00000000..f013473f --- /dev/null +++ b/tests/ui/test_analysis_history.py @@ -0,0 +1,263 @@ +# SPDX-License-Identifier: GPL-3.0-only +"""Saved-result browsing uses actual retained jobs and never launches analysis.""" + +from __future__ import annotations + +import hashlib +import json +import os +import shutil +from pathlib import Path + +import pytest + +os.environ.setdefault("QT_QPA_PLATFORM", "offscreen") +pytest.importorskip("PySide6") + +ROOT = Path(__file__).resolve().parents[2] +FIXTURE = ROOT / "tests" / "fixtures" / "mini_session" + + +def _hashes(package: Path) -> dict[str, str]: + return { + path.relative_to(package).as_posix(): hashlib.sha256(path.read_bytes()).hexdigest() + for path in package.rglob("*") if path.is_file() + } + + +@pytest.fixture +def package(tmp_path: Path) -> Path: + target = tmp_path / "saved results.mmsession" + shutil.copytree(FIXTURE, target) + return target + + +def _qc(package: Path, job_id: str): + from capture_analysis import JobParams, run + + return run(package, JobParams(command="qc", overwrite_job_id=job_id)) + + +def _select(history, job_id: str) -> None: + for index in range(history._jobs.count()): + if history._jobs.itemData(index).job_id == job_id: + history._jobs.setCurrentIndex(index) + return + raise AssertionError(f"saved job not listed: {job_id}") + + +def _finish_real_job(qapp, screen) -> None: + """Run Qt's event loop and settle the worker before any widget teardown.""" + from PySide6.QtCore import QEventLoop, QTimer + + loop = QEventLoop() + deadline = QTimer() + deadline.setSingleShot(True) + deadline.timeout.connect(loop.quit) + assert screen._thread is not None + screen._thread.finished.connect(loop.quit) + deadline.start(30_000) + loop.exec() + deadline.stop() + qapp.processEvents() + try: + assert screen._thread is None, "actual analysis QThread did not finish" + finally: + if screen._thread is not None: + screen._cancel_job() + deadline.start(10_000) + loop.exec() + deadline.stop() + qapp.processEvents() + assert screen._thread is None, "worker did not settle before widget teardown" + + +def test_real_completed_and_failed_jobs_are_read_only(package: Path) -> None: + from capture_analysis import JobParams, run + from capture_desktop.analysis_history import list_saved_jobs, load_saved_job + + _qc(package, "trial-qc") + with pytest.raises(ValueError, match="requires extra.pose_job_id"): + run(package, JobParams(command="kinematics", overwrite_job_id="trial-failed")) + before = _hashes(package) + rows = {job.job_id: job for job in list_saved_jobs(package)} + assert rows["trial-qc"].status == "completed" + assert rows["trial-failed"].status == "failed" + assert not any(row.problem for row in rows.values()) + failed = load_saved_job(package, "trial-failed") + assert json.loads(failed.params_text)["command"] == "kinematics" + assert "requires extra.pose_job_id" in failed.log_text + assert "ERROR:" in failed.log_text + assert _hashes(package) == before + + +def test_copied_package_keeps_its_saved_result(package: Path, tmp_path: Path) -> None: + from capture_desktop.analysis_history import load_saved_job + + original = _qc(package, "relocated-qc") + moved = tmp_path / "renamed copy.mmsession" + shutil.copytree(package, moved) + before = _hashes(moved) + job = load_saved_job(moved, "relocated-qc") + assert job.manifest["packagePath"] == str(package) + assert job.job.directory == moved / "processing/jobs/relocated-qc" + assert job.job.directory != original.job_dir + assert _hashes(moved) == before + + +def test_catalog_explains_unreadable_rows_without_hiding_good_jobs(package: Path) -> None: + from capture_desktop.analysis_history import list_saved_jobs + + result = _qc(package, "good") + parent = result.job_dir.parent + for name, changes in ( + ("future", {"schemaId": "capture.analysis_job/99"}), + ("bad-status", {"status": []}), + ("bad-outputs", {"outputs": ["unexpected"]}), + ("foreign-session", {"sessionId": "another-session"}), + ): + dest = parent / name + dest.mkdir() + manifest = dict(result.manifest, jobId=name, **changes) + (dest / "job_manifest.json").write_text(json.dumps(manifest), encoding="utf-8") + broken = parent / "broken-json" + broken.mkdir() + (broken / "job_manifest.json").write_text("[", encoding="utf-8") + (parent / ".attempt_unfinished").mkdir() + before = _hashes(package) + rows = {job.job_id: job for job in list_saved_jobs(package)} + assert len(rows) == 6 + assert not rows["good"].problem + assert all(row.problem for name, row in rows.items() if name != "good") + assert "different session" in rows["foreign-session"].problem + assert _hashes(package) == before + + +def test_missing_details_and_long_log_are_explicit(package: Path) -> None: + from capture_desktop.analysis_history import load_saved_job + + result = _qc(package, "long-log") + log = result.job_dir / "logs/job.log" + log.write_text("x" * (300 * 1024) + "\nFINAL ORIGINAL DIAGNOSTIC", encoding="utf-8") + before = _hashes(package) + loaded = load_saved_job(package, "long-log") + assert loaded.log_text.startswith("Showing the final 262,144 bytes") + assert loaded.log_text.endswith("FINAL ORIGINAL DIAGNOSTIC") + assert _hashes(package) == before + minimal = result.job_dir.parent / "minimal-failure" + minimal.mkdir() + (minimal / "job_manifest.json").write_text(json.dumps({ + "schemaId": "capture.analysis_job/1", "jobId": minimal.name, + "sessionId": result.manifest["sessionId"], "status": "failed", "outputs": [], + }), encoding="utf-8") + loaded = load_saved_job(package, minimal.name) + assert loaded.job.status == "failed" + assert loaded.params_text.startswith("Parameters unavailable:") + assert loaded.log_text.startswith("Log unavailable:") + + +def test_native_open_and_details_leave_the_package_unchanged(qapp, package: Path) -> None: + from capture_desktop.screen_analysis import AnalysisScreen + from capture_desktop.state import CaptureState + from PySide6.QtWidgets import QPlainTextEdit + + result = _qc(package, "saved-qc") + (result.job_dir / "logs/job.log").write_text( + "Original diagnostic literal text\n", encoding="utf-8" + ) + before = _hashes(package) + screen = AnalysisScreen(CaptureState()) + screen.set_package(str(package)) + assert not screen._last_job_dir + assert screen._history._jobs.count() == 1 + screen._history._open.click() + qapp.processEvents() + assert screen._thread is None + assert screen._last_job_dir == str(result.job_dir) + assert "job_id=saved-qc" in screen._inspector._meta.text() + assert screen._btn_open_report.isEnabled() + screen._history._details.click() + qapp.processEvents() + dialog = screen._history._dialog + assert dialog is not None and dialog.isVisible() + editors = {view.objectName(): view for view in dialog.findChildren(QPlainTextEdit)} + assert all(view.isReadOnly() for view in editors.values()) + assert json.loads(editors["analysisHistoryParameters"].toPlainText())["command"] == "qc" + assert "literal text" in editors["analysisHistoryLog"].toPlainText() + assert json.loads(editors["analysisHistoryManifest"].toPlainText())["jobId"] == "saved-qc" + assert _hashes(package) == before + dialog.close() + screen.close() + + +def test_refresh_preserves_the_view_and_offers_a_new_retained_job(qapp, package: Path) -> None: + from capture_desktop.screen_analysis import AnalysisScreen + from capture_desktop.state import CaptureState + + first = _qc(package, "first") + screen = AnalysisScreen(CaptureState()) + screen.set_package(str(package)) + screen._history._open.click() + second = _qc(package, "second") + before = _hashes(package) + screen._history._refresh.click() + assert screen._history._jobs.count() == 2 + assert screen._last_job_dir == str(first.job_dir) + assert screen._history.loaded_job_id == "first" + _select(screen._history, "second") + assert screen._last_job_dir == str(first.job_dir) + screen._history._open.click() + qapp.processEvents() + assert screen._last_job_dir == str(second.job_dir) + assert screen._history.loaded_job_id == "second" + assert screen._thread is None + assert _hashes(package) == before + screen.close() + + +def test_real_threaded_completion_populates_history(qapp, package: Path) -> None: + from capture_desktop.screen_analysis import AnalysisScreen + from capture_desktop.state import CaptureState + + screen = AnalysisScreen(CaptureState()) + screen.set_package(str(package)) + before = _hashes(package) + screen._btn_run.click() + _finish_real_job(qapp, screen) + assert screen._history._jobs.count() == 1 + assert screen._history.loaded_job_id + assert screen._last_job_dir + assert screen._history._open.isEnabled() + assert "status=completed" in screen._inspector._meta.text() + after = _hashes(package) + assert {name: after[name] for name in before} == before + assert all(name.startswith("processing/") for name in after.keys() - before.keys()) + screen.close() + + +def test_real_threaded_failure_offers_its_retained_diagnostics(qapp, package: Path, + monkeypatch) -> None: + from capture_desktop.screen_analysis import AnalysisScreen + from capture_desktop.state import CaptureState + from PySide6.QtWidgets import QMessageBox + + warnings = [] + monkeypatch.setattr(QMessageBox, "warning", lambda _parent, _title, text: warnings.append(text)) + screen = AnalysisScreen(CaptureState()) + screen.set_package(str(package)) + screen._command.setCurrentIndex(screen._command.findData("kinematics")) + screen._extras._pose_job.setEditText("missing-pose") + before = _hashes(package) + screen._btn_run.click() + _finish_real_job(qapp, screen) + assert warnings and "missing-pose" in warnings[0] + assert screen._history._jobs.count() == 1 + assert screen._history._jobs.currentData().status == "failed" + assert not screen._last_job_dir + screen._history._open.click() + assert "status=failed" in screen._inspector._meta.text() + assert "missing-pose" in screen._history._loaded.log_text + after = _hashes(package) + assert {name: after[name] for name in before} == before + assert all(name.startswith("processing/") for name in after.keys() - before.keys()) + screen.close() diff --git a/tests/ui/test_analysis_nested_gallery.py b/tests/ui/test_analysis_nested_gallery.py new file mode 100644 index 00000000..74608478 --- /dev/null +++ b/tests/ui/test_analysis_nested_gallery.py @@ -0,0 +1,181 @@ +# SPDX-License-Identifier: GPL-3.0-only +"""Native saved PNG discovery across current nested and legacy flat layouts.""" + +from __future__ import annotations + +import hashlib +import json +from pathlib import Path + +import pytest + +pytest.importorskip("PySide6") + + +def _png(path: Path, color: str) -> None: + from PySide6.QtGui import QColor, QImage + + path.parent.mkdir(parents=True, exist_ok=True) + image = QImage(16, 12, QImage.Format.Format_RGB32) + image.fill(QColor(color)) + assert image.save(str(path), "PNG") + + +def _hashes(path: Path) -> dict[str, str]: + return {str(p.relative_to(path)): hashlib.sha256(p.read_bytes()).hexdigest() + for p in path.rglob("*") if p.is_file()} + + +def _numeric_path(job: Path, source: str, stream: str, channel: int = 0) -> Path: + return (job / "figures/numeric" / f"source-{source.encode().hex()}" + / f"stream-{stream.encode().hex()}" / f"channel_{channel}.png") + + +def _titles(gallery) -> list[str]: + return [gallery._tabs.tabText(i) for i in range(gallery._tabs.count())] + + +def _color(gallery, index: int) -> str: + label = gallery._tabs.widget(index).widget() + return label.pixmap().toImage().pixelColor(0, 0).name() + + +def test_flat_figures_and_sync_dashboard_keep_their_existing_behavior(qapp, tmp_path): + from capture_desktop.widgets_analysis_plots import FigureGallery + + _png(tmp_path / "figures/legacy_signal.png", "#2855cc") + _png(tmp_path / "figures/sync_dashboard.png", "#000000") + before = _hashes(tmp_path) + gallery = FigureGallery() + gallery.load_job_dir(tmp_path) + assert _titles(gallery) == ["Sync", "legacy signal"] + assert _color(gallery, 1) == "#2855cc" + assert gallery._tabs.tabToolTip(1) == "legacy_signal.png" + assert _hashes(tmp_path) == before + gallery.close() + + +def test_nested_numeric_figures_preserve_channels_and_linked_series(qapp, tmp_path): + from capture_desktop.widgets_analysis_plots import FigureGallery + + for channel, color in enumerate(("#cc3322", "#22aa55")): + _png(_numeric_path(tmp_path, "lsl", "numeric.stream", channel), color) + doc = { + "schemaId": "capture.sync_dashboard_series/1", "title": "retained numeric", + "window": {"startSessionNs": 0, "endSessionNs": 1_000_000_000}, "gaps": [], + "series": [{"label": f"channel {i}", "t_ns": [0, 500_000_000, 1_000_000_000], + "y": [i, i + 1, i + 2]} for i in range(2)], + } + (tmp_path / "figures/sync_dashboard_series.json").write_text(json.dumps(doc)) + before = _hashes(tmp_path) + gallery = FigureGallery() + gallery.load_job_dir(tmp_path) + assert _titles(gallery) == ["Sync", "lsl / numeric.stream / channel 0", + "lsl / numeric.stream / channel 1"] + assert [_color(gallery, i) for i in (1, 2)] == ["#cc3322", "#22aa55"] + assert len(gallery._sync._linked) == 2 + assert gallery._sync._title.text() == "retained numeric" + for i in (1, 2): + expected = _numeric_path(tmp_path, "lsl", "numeric.stream", i - 1) + assert gallery._tabs.tabToolTip(i) == expected.relative_to(tmp_path / "figures").as_posix() + assert _hashes(tmp_path) == before + gallery.close() + + +def test_same_filename_retains_case_unicode_and_stream_identity(qapp, tmp_path): + from capture_desktop.widgets_analysis_plots import FigureGallery + + identities = [("Arm", "force", "#aabbcc"), ("arm", "force", "#bbccdd"), + ("café", "force / left", "#ccddee")] + for source, stream, color in identities: + _png(_numeric_path(tmp_path, source, stream), color) + before = _hashes(tmp_path) + gallery = FigureGallery() + gallery.load_job_dir(tmp_path) + by_title = {gallery._tabs.tabText(i): _color(gallery, i) + for i in range(1, gallery._tabs.count())} + assert by_title == {f"{source} / {stream} / channel 0": color + for source, stream, color in identities} + tips = [gallery._tabs.tabToolTip(i) for i in range(1, gallery._tabs.count())] + assert len(set(tips)) == 3 + assert _hashes(tmp_path) == before + gallery.close() + + +def test_unknown_nested_paths_and_nested_dashboard_png_remain_inspectable(qapp, tmp_path): + from capture_desktop.widgets_analysis_plots import FigureGallery + + _png(tmp_path / "figures/custom/sync_dashboard.png", "#ddeeff") + _png(tmp_path / "figures/numeric/source-zz/stream-e9/channel_0.png", "#eeff11") + _png(tmp_path / "figures/sync_dashboard.png", "#000000") + gallery = FigureGallery() + gallery.load_job_dir(tmp_path) + assert _titles(gallery) == ["Sync", "custom / sync dashboard", + "numeric / source-zz / stream-e9 / channel 0"] + assert [_color(gallery, i) for i in (1, 2)] == ["#ddeeff", "#eeff11"] + gallery.close() + + +def test_reloading_a_job_replaces_nested_and_flat_tabs(qapp, tmp_path): + from capture_desktop.widgets_analysis_plots import FigureGallery + + first, second, empty = (tmp_path / name for name in ("first", "second", "empty")) + _png(_numeric_path(first, "a", "b"), "#112233") + _png(first / "figures/flat.png", "#223344") + _png(second / "figures/new_signal.png", "#334455") + empty.mkdir() + before = _hashes(tmp_path) + gallery = FigureGallery() + gallery.load_job_dir(first) + assert gallery._tabs.count() == 3 + gallery.load_job_dir(second) + assert _titles(gallery) == ["Sync", "new signal"] + assert _color(gallery, 1) == "#334455" + gallery.load_job_dir(empty) + assert _titles(gallery) == ["Sync"] + assert not gallery._sync._linked + assert _hashes(tmp_path) == before + gallery.close() + + +def test_one_unreadable_png_does_not_hide_other_saved_figures(qapp, tmp_path): + from capture_desktop.widgets_analysis_plots import FigureGallery + + _png(tmp_path / "figures/nested/good.png", "#445566") + bad = tmp_path / "figures/nested/bad.png" + bad.write_bytes(b"not an image") + before = _hashes(tmp_path) + gallery = FigureGallery() + gallery.load_job_dir(tmp_path) + assert _titles(gallery) == ["Sync", "nested / bad", "nested / good"] + assert gallery._tabs.widget(1).widget().text() == "Could not load bad.png" + assert _color(gallery, 2) == "#445566" + assert _hashes(tmp_path) == before + gallery.close() + + +def test_png_discovery_refuses_external_file_links_and_directories(qapp, tmp_path): + from capture_desktop.widgets_analysis_plots import FigureGallery + + job = tmp_path / "job" + outside = tmp_path / "external.png" + _png(outside, "#aa1122") + _png(job / "figures/nested/good.png", "#22aa55") + foreign = job / "figures/foreign.png" + try: + foreign.symlink_to(outside) + except OSError as exc: + pytest.skip(f"This filesystem cannot create the symlink fixture: {exc}") + link_before = foreign.readlink() + assert foreign.samefile(outside) + (job / "figures/not_a_file.png").mkdir() + before = _hashes(tmp_path) + gallery = FigureGallery() + gallery.load_job_dir(job) + assert _titles(gallery) == ["Sync", "nested / good"] + assert _color(gallery, 1) == "#22aa55" + assert gallery._tabs.tabToolTip(1) == "nested/good.png" + # Windows may retain an extended-length prefix in the link target. + assert foreign.readlink() == link_before + assert _hashes(tmp_path) == before + gallery.close() diff --git a/tests/ui/test_analysis_workspace_composition.py b/tests/ui/test_analysis_workspace_composition.py new file mode 100644 index 00000000..8cc55023 --- /dev/null +++ b/tests/ui/test_analysis_workspace_composition.py @@ -0,0 +1,252 @@ +# SPDX-License-Identifier: GPL-3.0-only +"""Receive the current source picker, saved history, comparison and nested gallery together.""" + +from __future__ import annotations + +import hashlib +import json +import os +import threading +from pathlib import Path + +import pytest + +os.environ.setdefault("QT_QPA_PLATFORM", "offscreen") +pytest.importorskip("PySide6") + + +def _files(root: Path) -> dict[str, str]: + return { + path.relative_to(root).as_posix(): hashlib.sha256(path.read_bytes()).hexdigest() + for path in root.rglob("*") if path.is_file() + } + + +def _wait(predicate, timeout_ms: int = 60_000) -> None: + """Use native Qt event delivery while an actual analysis worker is alive.""" + from PySide6.QtCore import QEventLoop, QTimer + + if predicate(): + return + loop = QEventLoop() + poll = QTimer() + deadline = QTimer() + deadline.setSingleShot(True) + poll.timeout.connect(lambda: loop.quit() if predicate() else None) + deadline.timeout.connect(loop.quit) + poll.start(10) + deadline.start(timeout_ms) + try: + loop.exec() + finally: + poll.stop() + deadline.stop() + assert predicate(), "the native analysis event loop did not settle" + + +def test_sources_history_comparison_and_gallery_share_package_lifetime( + qapp, tmp_path: Path, monkeypatch, +): + import capture_analysis + from capture_analysis import JobParams + from PySide6.QtCore import Qt + from PySide6.QtGui import QPixmap + from PySide6.QtTest import QTest + from PySide6.QtWidgets import QLabel + + from tests.analysis.test_numeric_cli_receiving import retained_files + from tests.ui.test_analysis_history import _select + from tests.ui.test_analysis_sources import ( + _choose, + _close, + _package, + _screen, + _warning_timer, + ) + + checks = [] + release = threading.Event() + written = threading.Event() + actual_results = [] + actual_calls = [] + screen = None + timer = None + evidence = Path(os.environ["CAPTURE_ANALYSIS_COMPOSITION_EVIDENCE"]) \ + if os.environ.get("CAPTURE_ANALYSIS_COMPOSITION_EVIDENCE") else tmp_path / "receipt" + evidence.mkdir(parents=True, exist_ok=True) + + def check(name: str, condition: bool, details=None) -> None: + checks.append({"name": name, "passed": bool(condition), "details": details}) + assert condition, name + + first = _package(tmp_path / "first μ.mmsession") + second = _package(tmp_path / "second μ.mmsession") + raw_before = {str(p): retained_files(p) for p in (first, second)} + real_run = capture_analysis.run + # Warm actual plotting synchronously. The held QThread runs a real features + # job; no loader, handler, result, plot or output format is replaced. + a = real_run(first, JobParams(command="all", sources=["sampler.a"], + overwrite_job_id="retained-a")) + b = real_run(first, JobParams(command="all", sources=["sampler.b"], + overwrite_job_id="retained-b")) + seeds = {str(a.job_dir): _files(a.job_dir), str(b.job_dir): _files(b.job_dir)} + check("actual source-filtered retained jobs contain nested numeric figures", + len(list((a.job_dir / "figures/numeric").rglob("*.png"))) == 2 + and len(list((b.job_dir / "figures/numeric").rglob("*.png"))) == 1) + + def held_run(package, params, **kwargs): + actual_calls.append({"package": str(package), "params": params.to_dict()}) + result = real_run(package, params, **kwargs) + actual_results.append(result) + written.set() + if not release.wait(120): + raise AssertionError("receiver did not release the actual written result") + return result + + try: + screen = _screen(qapp, first) + screen.resize(1500, 950) + timer, warnings = _warning_timer(qapp) + screen._command.setCurrentIndex(screen._command.findData("features")) + _choose(qapp, screen._sources, {"sampler.b"}) + _select(screen._history, a.job_id) + QTest.mouseClick(screen._history._open, Qt.MouseButton.LeftButton) + bar = screen._inspector._parameters + check("history binds the retained job to the gallery and comparison inspector", + screen._history.loaded_job_id == a.job_id + and screen._last_job_dir == str(a.job_dir) + and screen._gallery._tabs.count() == 3 + and bar._button.isEnabled() + and bar._source.job_id == a.job_id) + QTest.mouseClick(bar._button, Qt.MouseButton.LeftButton) + prior_dialog = bar._dialog + check("retained parameters can be opened from the history-loaded inspector", + prior_dialog is not None and prior_dialog.isVisible()) + monkeypatch.setattr(capture_analysis, "run", held_run) + QTest.mouseClick(screen._btn_run, Qt.MouseButton.LeftButton) + check("run owns the source snapshot and disables history before thread startup", + screen._thread is not None and screen._worker._sources == ("sampler.b",) + and not screen._btn_run.isEnabled() + and not screen._history._refresh.isEnabled() + and not screen._history._open.isEnabled() + and not screen._history._jobs.isEnabled()) + check("starting an actual job clears all previously loaded result associations", + screen._history.loaded_job_id == "" + and screen._last_job_dir == "" + and screen._gallery._tabs.count() == 1 + and bar._source is None and bar._dialog is None + and not bar._button.isEnabled()) + # Change the future UI choice, without changing the actual worker input. + screen._sources._mode.setCurrentIndex(screen._sources._mode.findData("all")) + check("future source selection refresh cannot re-enable busy history controls", + screen._sources.mode == "all" and screen._worker._sources == ("sampler.b",) + and not screen._history._refresh.isEnabled() + and not screen._btn_run.isEnabled()) + _wait(written.is_set) + result = actual_results[0] + params = json.loads((result.job_dir / "params.json").read_text(encoding="utf-8")) + inventory = json.loads((result.job_dir / "features/_schema.json").read_text()) + check("the real persisted job used the selected source snapshot", + params["sources"] == ["sampler.b"] + and {row["sourceId"] for row in inventory["tables"].values()} == {"sampler.b"} + and actual_calls[0]["params"]["sources"] == ["sampler.b"], + {"job": result.job_id, "params_sources": params["sources"]}) + check("written output does not release busy controls before QThread cleanup", + screen._thread is not None and not screen._history._refresh.isEnabled() + and not screen._btn_run.isEnabled()) + screen.set_package(str(second)) + check("package change clears history, figures and comparison while resetting sources", + screen._history.package == str(second.resolve()) + and screen._history.loaded_job_id == "" + and screen._gallery._tabs.count() == 1 + and bar._source is None and bar._dialog is None + and screen._sources.mode == "all" and screen._sources.selected_ids == () + and not screen._history._refresh.isEnabled()) + release.set() + _wait(lambda: screen._thread is None) + check("late source-filtered completion stays unbound to the current package", + screen._last_job_dir == "" and screen._history.loaded_job_id == "" + and screen._gallery._tabs.count() == 1 + and bar._source is None and not bar._button.isEnabled() + and screen._history._refresh.isEnabled() + and screen._btn_run.isEnabled() + and "previous package" in screen._log.toPlainText()) + check("real worker completed without a failure dialog", + not warnings and len(actual_calls) == 1, warnings) + screen.set_package(str(first)) + _select(screen._history, result.job_id) + QTest.mouseClick(screen._history._open, Qt.MouseButton.LeftButton) + check("returning to the original package reopens the actual late result", + screen._history.loaded_job_id == result.job_id + and bar._source is not None and bar._source.params["sources"] == ["sampler.b"] + and bar._button.isEnabled()) + QTest.mouseClick(bar._button, Qt.MouseButton.LeftButton) + comparison = bar._dialog + assert comparison is not None + # Select the existing comparison target through the owner's dialog seam; + # both originals are still read and verified by its unchanged loader. + comparison._read_other(a.job_dir) + differences = {row.pointer: (row.other_json, row.loaded_json) + for row in comparison._rows} + check("comparison reads the current producer's exact source parameters", + differences.get("/sources/0") == ('"sampler.a"', '"sampler.b"') + and comparison._source.job_id == result.job_id + and not comparison._error.text(), differences) + _select(screen._history, a.job_id) + QTest.mouseClick(screen._history._open, Qt.MouseButton.LeftButton) + check("opening another retained job clears the previous comparison dialog", + bar._dialog is None and bar._source.job_id == a.job_id + and bar._source.params["sources"] == ["sampler.a"] + and screen._history.loaded_job_id == a.job_id) + tabs = screen._gallery._tabs + paths = [tabs.tabToolTip(i) for i in range(1, tabs.count())] + expected = sorted(p.relative_to(a.job_dir / "figures").as_posix() + for p in (a.job_dir / "figures/numeric").rglob("*.png")) + check("reopened nested gallery identifies exactly the selected-source figures", + paths == expected and len(paths) == 2, paths) + pixels = [] + for index, relative in enumerate(paths, 1): + label = tabs.widget(index).findChild(QLabel) + assert label is not None and not label.pixmap().isNull() + pixels.append(label.pixmap().toImage() == + QPixmap(str(a.job_dir / "figures" / relative)).toImage()) + check("both reopened image widgets retain the exact actual saved pixels", all(pixels)) + check("gallery navigation preserves the independent future source choice", + screen._sources.mode == "all" and screen._sources.selected_ids == ()) + qapp.processEvents() + assert screen.grab().save(str(evidence / "composed-history-gallery.png")) + QTest.mouseClick(bar._button, Qt.MouseButton.LeftButton) + check("the replacement inspector opens only its own parameter source", + bar._dialog is not None and bar._dialog._source.job_id == a.job_id) + retained = {str(p): _files(p) for p in (first, second)} + screen.set_package(str(second)) + check("another package switch clears the current comparison and gallery together", + bar._dialog is None and bar._source is None + and screen._history.loaded_job_id == "" + and screen._gallery._tabs.count() == 1 + and screen._sources.mode == "all" and screen._sources.selected_ids == ()) + check("all saved jobs and raw bytes remain unchanged through history and comparison", + retained == {str(p): _files(p) for p in (first, second)} + and raw_before == {str(p): retained_files(p) for p in (first, second)} + and seeds == {str(a.job_dir): _files(a.job_dir), str(b.job_dir): _files(b.job_dir)}) + check("receiving view actions never start a second analysis job", + len(actual_calls) == 1 and screen._thread is None) + finally: + release.set() + if screen is not None and screen._thread is not None: + screen._cancel_job() + _wait(lambda: screen._thread is None, 120_000) + if timer is not None: + timer.stop() + if screen is not None: + _close(qapp, screen) + (evidence / "receipt.json").write_text( + json.dumps({"checks": checks, "passed": sum(row["passed"] for row in checks), + "failed": sum(not row["passed"] for row in checks), + "worker_calls": actual_calls, + "methodology": "Real numeric MCAP jobs and QThread; receiver holds only " + "the return of an already-persisted real feature job. " + "Native Qt event loop, unchanged source chooser and " + "history Open buttons, unchanged comparison read action."}, + indent=2, ensure_ascii=False) + "\n", encoding="utf-8", + ) diff --git a/tools/run_ci_tests.py b/tools/run_ci_tests.py index b5717e9f..358ae418 100644 --- a/tools/run_ci_tests.py +++ b/tools/run_ci_tests.py @@ -155,7 +155,7 @@ def main() -> int: with (out / "pytest.log").open("w", encoding="utf-8") as log: try: result = subprocess.run( - command, cwd=ROOT, env=env, stdout=log, stderr=subprocess.STDOUT, timeout=300 + command, cwd=ROOT, env=env, stdout=log, stderr=subprocess.STDOUT, timeout=600 ) code = result.returncode except subprocess.TimeoutExpired: