Milestone v1 (v2.0.0): Mokosh — Session Capture #1

Merged
strategy155 merged 297 commits from gsd/phase-04-harden-clean-up-optional into main 2026-05-31 15:34:17 +00:00
Showing only changes of commit b064a214b2 - Show all commits

View File

@@ -14,6 +14,8 @@ const VIDEO_MIME = 'video/webm;codecs=vp9'; // D-20 strict — no fallbac
const VIDEO_BITRATE = 400_000; // CON-video-codec
const TIMESLICE_MS = 2_000; // SPEC §4.1
const PORT_NAME = 'video-keepalive'; // Plan 04 owns the ping loop
const PORT_PING_MS = 25_000; // < 30 s SW idle threshold
const PORT_RECONNECT_MS = 290_000; // pre-empt the ~5 min port cap (Pitfall 4)
const logger = new OffscreenLogger('Recorder');
@@ -137,20 +139,79 @@ function stopRecording(): void {
}
}
// ─── Bootstrap (Plan 04 wires the full port + handshake) ────────────────
// Plan 03 commits this minimal bootstrap so that Plan 02's ring-buffer +
// codec tests can mock `chrome.runtime` without crashing on module import.
// Plan 04 elaborates the OFFSCREEN_READY handshake and the port reconnect
// loop without rewriting this module's exports.
// ─── Bootstrap: handshake + port lifecycle (D-17, RESEARCH.md Patterns 4 & 5) ──
// T-1-04 sender-id check: defense-in-depth on the offscreen side. The SW-side
// `onConnect` listener (Plan 05) MUST also validate
// `port.sender?.id === chrome.runtime.id` to reject port-hijack attempts
// from other extensions. See threat register T-1-04 in 01-04-PLAN.md.
function isFromOwnExtension(sender: chrome.runtime.MessageSender | undefined): boolean {
return sender?.id === chrome.runtime.id;
}
// Бутстрап (Plan 03 stub; Plan 04 wires the full handshake + reconnect).
// Stable handles for the ping interval and the pre-emptive reconnect timer,
// so we can clear them on disconnect / re-init.
let pingIntervalId: ReturnType<typeof setInterval> | null = null;
let preemptiveReconnectId: ReturnType<typeof setTimeout> | null = null;
function teardownPortTimers(): void {
if (pingIntervalId !== null) {
clearInterval(pingIntervalId);
pingIntervalId = null;
}
if (preemptiveReconnectId !== null) {
clearTimeout(preemptiveReconnectId);
preemptiveReconnectId = null;
}
}
function onPortMessage(message: unknown): void {
// Defense-in-depth: explicit shape check before destructuring (T-1-04)
if (typeof message !== 'object' || message === null) {
return;
}
const type = (message as { type?: unknown }).type;
if (type === 'REQUEST_BUFFER') {
if (keepalivePort !== null) {
keepalivePort.postMessage({ type: 'BUFFER', chunks: getBuffer() });
}
}
// Any unknown port message type is silently dropped (T-1-04 defense-in-depth).
}
function connectPort(): void {
teardownPortTimers();
try {
keepalivePort = chrome.runtime.connect({ name: PORT_NAME });
} catch (err) {
logger.error('port connect failed:', err);
keepalivePort = null;
return;
}
keepalivePort.onMessage.addListener(onPortMessage);
keepalivePort.onDisconnect.addListener(() => {
logger.warn('port disconnected — reconnecting');
teardownPortTimers();
keepalivePort = null;
// Synchronous reconnect — tests/offscreen/port.test.ts pins this
connectPort();
});
pingIntervalId = setInterval(() => {
keepalivePort?.postMessage({ type: 'PING' });
}, PORT_PING_MS);
preemptiveReconnectId = setTimeout(() => {
logger.log('pre-emptive port reconnect (290 s cap)');
keepalivePort?.disconnect();
// onDisconnect handler above triggers a fresh connectPort() call
}, PORT_RECONNECT_MS);
}
// Бутстрап (handshake + port lifecycle).
// Guarded so the pure ring-buffer + codec-check tests can import the module
// without providing a chrome stub. Production runs always have chrome.runtime
// available, so the guard is a no-op there.
// without providing a full chrome stub. Production always has chrome.runtime
// fully populated, so the guard is a no-op there. Order matters per Pattern 4:
// onMessage listener registration MUST happen BEFORE OFFSCREEN_READY is sent,
// so the SW can safely send START_RECORDING the moment it sees the ready signal.
function bootstrap(): void {
if (typeof chrome === 'undefined' || !chrome.runtime) {
return;
@@ -175,9 +236,8 @@ function bootstrap(): void {
}
});
}
// Plan 04 will replace this stub with the full reconnect + ping loop.
if (typeof chrome.runtime.connect === 'function') {
keepalivePort = chrome.runtime.connect({ name: PORT_NAME });
connectPort();
}
if (typeof chrome.runtime.sendMessage === 'function') {
chrome.runtime.sendMessage({ type: 'OFFSCREEN_READY' });
@@ -186,10 +246,6 @@ function bootstrap(): void {
bootstrap();
// Touch the keepalive var so noUnusedLocals doesn't complain — Plan 04
// uses it. Once Plan 04 lands, this line is removed in its refactor pass.
void keepalivePort;
// ─── D-13 fallback: restart-segments skeleton (pre-staged per CONTEXT.md) ──
// Activated only if the Phase 07 ffprobe gate fails on the simpler
// continuous-recorder + age-trim approach. See RESEARCH.md Pattern 3.