mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-29 17:02:28 +00:00
Merge branch 'unstable' into area/storage-cors
This commit is contained in:
commit
888807baf6
20 files changed
+709
-12
No files matched your search
@@ -0,0 +1 @@
|
||||
Client9 at c5b678f7; investigate HEAD owner cancellation only via actual observer/controller and controlled fetch. No product/retained tests/full/build/browser. HLS/torrent remain separate. Success: counts for disposal/shared/rejoin/cache/timers/media and scoped proposal to dispatch.
|
||||
@@ -0,0 +1 @@
|
||||
Client9 HEAD-only candidate ready: controller cancel hook/abort+raced prompt settlement/timer identity cleanup;23new HEAD+37existing scenarios pass,16failing isolated mutants/cancelled0,lint11 pass. No existing test expectation edits. Explicit strict contract/integrity notes. Next commit candidate, merge current unstable, request full/browser slot; do not submit or run expensive jobs without grant. HLS/torrent separately open.
|
||||
@@ -0,0 +1 @@
|
||||
Client9 HEAD-only fix durably landed f41ac656 after normal435-filegate exit0, ancestry0; sequential build/artifact exit0. Heavy slot released. Await separate bounded native browser slot; no browser started. HLS/torrent/RangeGET and wholeStage3 remain open. No additional product changes.
|
||||
@@ -0,0 +1 @@
|
||||
HEAD slice complete locally: durablef41ac656 normal435unique/exit0/ancestry0; build/artifact0; controlled native Chromium+Firefox lifecycle pass with synthetic media completion/public-deny. Browser/heavy resources released. Pending docs-only evidence landing; HLS/torrent/RangeGET remain open, await bounded routing/HEAD closure disposition.
|
||||
@@ -0,0 +1,3 @@
|
||||
- HEAD slice only. Current media cancellation hook does not cover fetch; reproduce real ownership flow before proposing hook reuse.
|
||||
- Do not change product/tests without dispatch contract routing. Keep HLS/torrent and wide Stage3 completion open.
|
||||
- No redundant full/lint/build/browser for scratch investigation; QA slot untouched.
|
||||
@@ -1,10 +1,11 @@
|
||||
{
|
||||
"id": "client-reliability-9",
|
||||
"area": "client-reliability",
|
||||
"status": "open",
|
||||
"status": "in-progress",
|
||||
"title": "Measure remaining active HEAD HLS torrent cancellation at current HEAD",
|
||||
"blockedOn": null,
|
||||
"addedOn": "2026-10-22",
|
||||
"filedAt": "fb54cea3a2ba99b4860421724a5050af6b97c293",
|
||||
"brief": "docs/agents/CAMPAIGN-2026-10-22.md"
|
||||
"brief": "docs/agents/CAMPAIGN-2026-10-22.md",
|
||||
"evidence": "HEAD-only fix e9c960ed/merged09f52bdd durably landed f41ac656 normalgateexit0,435discovered/435unique starts missingextra0,ancestry0;build/artifactexit0;controlled native Chromium+Firefox lifecycle PASS with synthetic loadeddata/publicdeny. Prior60focused/16mutants/lint11. Resources released. HLS/torrent/RangeGET separately OPEN; no wholeStage3 claim. test_logs/TEST_LOG_2026-10-22_20-52-00_client-reliability-9-browser.md"
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
# Active HEAD owner cancellation
|
||||
|
||||
Source: docs/performance-efficiency-plan.md Stage3, campaign2026-10-22 priority2, fleet/RULE-CHANGES.md2026-10-22 and explicit dispatch routing56417d11 durably landed e04549f8.
|
||||
|
||||
Old scoped behavior: queued work and active media cancel on final-owner disposal, but active HEAD fetch remains until response/error/timeout. A fresh observer may join that obsolete inflight record. Controlled11-mode reproduction independently confirmed3 failures/8 controls.
|
||||
|
||||
New contract: final registered owner loss invalidates active HEAD synchronously, requests transport abort when supported and promptly settles the observer chain null independently of transport cooperation. HEAD timer and cancellation hook are released. Same-turn/later consumers start fresh work; obsolete response/error/timer/finalizer cannot affect replacement, cache, badges, media or mirrors. Unsupported AbortController still permits logical settlement and cleanup, but cannot promise transport abort.
|
||||
|
||||
Preserve shared and cross-controller ownership, legacy consumers, live HEAD success/error/timeout/opaque/bad-status media fallback and cache, media-hook handoff and FIFO/cap. Existing29 media lifecycle scenarios and4+4 adjacent controller/multisource scenarios remain unchanged. No retained assertion was relaxed or removed;23 new HEAD scenarios tighten previously uncovered behavior. This is a scope extension, not retroactive proof of HEAD cancellation by item8.
|
||||
|
||||
Only js/ui/urlHealthController.js HEAD phase changes. Observer, cache, app, HLS, torrent, RangeGET and limits/TTLs unchanged. HLS/torrent remain separately open. No browser/real network bytes/fullStage3 qualification.
|
||||
@@ -562,16 +562,44 @@ export default class UrlHealthController {
|
||||
return result;
|
||||
};
|
||||
|
||||
const lifecycle = options.lifecycle;
|
||||
if (lifecycle && (lifecycle.cancelled || !lifecycle.owners.size)) {
|
||||
lifecycle.cancelled = true;
|
||||
return { outcome: "cancelled" };
|
||||
}
|
||||
const supportsAbort = typeof AbortController !== "undefined";
|
||||
const controller = supportsAbort ? new AbortController() : null;
|
||||
let timeoutId = null;
|
||||
let resolveCancellation;
|
||||
const cancellation = new Promise((resolve) => {
|
||||
resolveCancellation = resolve;
|
||||
});
|
||||
const cancelActive = () => {
|
||||
// Invalidate before resolving: same-turn rejoin must start fresh work.
|
||||
lifecycle.cancelled = true;
|
||||
resolveCancellation({ outcome: "cancelled" });
|
||||
// Settlement must not depend on the transport observing this signal.
|
||||
controller?.abort();
|
||||
};
|
||||
if (lifecycle) lifecycle.cancelActive = cancelActive;
|
||||
const cleanupHead = () => {
|
||||
if (timeoutId) clearTimeout(timeoutId);
|
||||
if (lifecycle?.cancelActive === cancelActive) {
|
||||
lifecycle.cancelActive = null;
|
||||
}
|
||||
};
|
||||
|
||||
const racers = [
|
||||
fetch(trimmed, {
|
||||
method: "HEAD",
|
||||
mode: "no-cors",
|
||||
cache: "no-store",
|
||||
signal: controller ? controller.signal : undefined
|
||||
cancellation,
|
||||
new Promise((resolve) => {
|
||||
resolve(
|
||||
fetch(trimmed, {
|
||||
method: "HEAD",
|
||||
mode: "no-cors",
|
||||
cache: "no-store",
|
||||
signal: controller ? controller.signal : undefined
|
||||
})
|
||||
);
|
||||
})
|
||||
];
|
||||
|
||||
@@ -596,9 +624,8 @@ export default class UrlHealthController {
|
||||
try {
|
||||
responseOrTimeout = await Promise.race(racers);
|
||||
} catch (err) {
|
||||
if (timeoutId) {
|
||||
clearTimeout(timeoutId);
|
||||
}
|
||||
cleanupHead();
|
||||
if (lifecycle?.cancelled) return { outcome: "cancelled" };
|
||||
this.logger.warn(`[probeUrl] HEAD request failed for ${trimmed}:`, err);
|
||||
const fallback = await confirmWithVideoElement();
|
||||
if (fallback) {
|
||||
@@ -609,8 +636,9 @@ export default class UrlHealthController {
|
||||
: { outcome: "unknown", error: err };
|
||||
}
|
||||
|
||||
if (timeoutId) {
|
||||
clearTimeout(timeoutId);
|
||||
cleanupHead();
|
||||
if (lifecycle?.cancelled || responseOrTimeout?.outcome === "cancelled") {
|
||||
return { outcome: "cancelled" };
|
||||
}
|
||||
|
||||
if (responseOrTimeout && responseOrTimeout.outcome === "timeout") {
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
# HEAD lifecycle integrity
|
||||
|
||||
```yaml
|
||||
test_integrity_note:
|
||||
change_type: ["new_tests", "spec_correction"]
|
||||
scenarios:
|
||||
- id: SCN-head-final-owner
|
||||
given: "actual observer/controller HEAD with abortable, ignoring-abort or missing AbortController transport"
|
||||
when: "final owner disposes, including duplicate disposal and already-completed HEAD boundary"
|
||||
then: "prompt null settlement, timer cleanup, no cache/media/mirror/stale badge; abort if supported"
|
||||
- id: SCN-head-replacement
|
||||
given: "same-turn or later rejoin after disposal"
|
||||
when: "obsolete success, error or timeout callback runs"
|
||||
then: "fresh HEAD and inflight identity preserved, fresh healthy result only reaches live badge"
|
||||
- id: SCN-head-sharing
|
||||
given: "same-controller, cross-controller or legacy live survivor"
|
||||
when: "other observer disposes then HEAD/media completes"
|
||||
then: "one un-aborted HEAD, survivor gets healthy cache/badge, disposed badge unchanged"
|
||||
- id: SCN-head-live-fallback
|
||||
given: "live HEAD success/error/timeout/opaque/405 or failing media and mirror"
|
||||
when: "controlled transport/media settles"
|
||||
then: "healthy fallback or honest offline cache, timers/media slots released"
|
||||
- id: SCN-head-handoff-fifo
|
||||
given: "HEAD transitioning to media or saturated real media queue"
|
||||
when: "owner leaves or live media releases slots"
|
||||
then: "new media cancellation hook works, live FIFO and cap3 remain intact"
|
||||
- id: SCN-head-before-start
|
||||
given: "lifecycle already cancelled or without owners"
|
||||
when: "real probeUrl entry is called"
|
||||
then: "cancelled result, no fetch/media/timer"
|
||||
observable_outcomes:
|
||||
- "fetch count/AbortSignal, settled value, timer/source/listener cleanup"
|
||||
- "real cache/inflight identity, live/disposed badges and media queue/FIFO"
|
||||
determinism_controls:
|
||||
- "controlled fetch with native AbortSignal and optional ignored abort"
|
||||
- "manually driven positive-delay timers, native zero-delay JSDOM tasks"
|
||||
- "actual observer/controller/cache/DOM media events; external network never used"
|
||||
- "cleanup completes controlled transports/media and restores globals before natural exit"
|
||||
anti_cheat_rationale:
|
||||
prevents:
|
||||
- "abort signal without prompt settlement"
|
||||
- "null-only fake fix retaining transport or timer"
|
||||
- "reuse of obsolete request or cache-on-cancel"
|
||||
- "dropping shared/legacy owners or fallback/FIFO behavior"
|
||||
- "stale inflight finalizer deleting fresh work"
|
||||
- "retry/sleep/assertion relaxation"
|
||||
relaxation:
|
||||
did_relax_any_assertion: false
|
||||
if_true_explain_spec_basis: ""
|
||||
```
|
||||
|
||||
Spec scope extension: docs/spec_changes/2026-10-22-client-reliability-9-active-head.md. No existing test was changed. Original controller fails12/23 assertions and passes11 controls, cancelled0. Fixed controller23/23. All16 isolated mutants exit1 with actual failed assertions/cancelled0; production source never contains a mutant. Isolated cache-finalizer mutant changes a scratch copy only.
|
||||
|
||||
| Mutant | Failed scenarios | Pass | Exit |
|
||||
|---|---:|---:|---:|
|
||||
| baseline | 12 | 11 | 1 |
|
||||
| no-head-hook | 10 | 13 | 1 |
|
||||
| no-head-abort | 2 | 21 | 1 |
|
||||
| no-prompt-settlement | 8 | 15 | 1 |
|
||||
| no-sync-invalidation | 3 | 20 | 1 |
|
||||
| retained-head-timer | 21 | 2 | 1 |
|
||||
| no-prestart-guard | 2 | 21 | 1 |
|
||||
| lost-shared-owner | 3 | 20 | 1 |
|
||||
| cache-on-cancel | 12 | 11 | 1 |
|
||||
| no-live-error-fallback | 1 | 22 | 1 |
|
||||
| lost-media-hook | 1 | 22 | 1 |
|
||||
| healthy-cache-corrupted | 14 | 9 | 1 |
|
||||
| no-live-timeout-abort | 1 | 22 | 1 |
|
||||
| no-mirror-fallback | 1 | 22 | 1 |
|
||||
| fifo-reversed | 1 | 22 | 1 |
|
||||
| stale-inflight-finalizer | 3 | 20 | 1 |
|
||||
|
||||
Mutant generation/reproduction: /tmp/client9-run-mutants.py; per-mutant source/test/TAP under /tmp/client9-mutant-*.mjs/.tap; structured /tmp/client9-mutants.json. Changes disable HEAD hook/abort/prompt settlement/synchronous marker/timer cleanup/prestart guard, lose shared owner, cache on cancellation, lose live error fallback/media hook/timeout abort/mirror fallback, corrupt healthy cache, reverse FIFO and remove cache finalizer identity guard. Baseline uses pre-change git controller. Every scenario is rejected by at least one mutant (grouped coverage); none survived. No forced termination, retries or waits for real timeout.
|
||||
@@ -0,0 +1,13 @@
|
||||
# client-reliability-9 HEAD investigation
|
||||
|
||||
- HEAD: c5b678f7c9d0b92fbf786b16ae831f1be1d0b899; filedAt fb54cea3. Controller/observer/cache diff between filedAt and HEAD is empty. Item still applies; claimed.
|
||||
- Scratch: /tmp/client9-head-repro.mjs, derived from real lifecycle fixture; imports actual observer/controller/cache. Controlled fetch and AbortSignal; manually driven positive-delay timeout callbacks; actual DOM/media events. Zero-delay JSDOM tasks use native timers. No public IO, sleep, retry, forced exit or internal probe override.
|
||||
- Command per mode: `env -u NODE_TEST_CONTEXT node /tmp/client9-head-repro.mjs <mode>`; /tmp/client9-<mode>.tap; structured /tmp/client9-results.json.
|
||||
- Three natural failures (1 scenario each, exit1, cancelled0): disposed, same-turn, later. Last owner leaves HEAD1/abort0/timer1(5000ms)/unsettled/cache0/media0/video slots0/queued0/original inflight retained. Rejoin starts1 HEAD total, expected2. This is retained network work, not media-slot retention: HEAD has no shared slot cap in this controller.
|
||||
- Eight natural passes (exit0, 1 scenario each, cancelled0): shared, cross, legacy, live-success, live-error, live-timeout, late-success, late-error. Shared survivor remains un-aborted and receives healthy result; disposed badge checking. Live HEAD success/error/timeout proceed to successful controlled media and healthy cache; timeout abort1. Completed probe timers0, video slots0. Late HEAD success/error after disposal settles null/cache0/media0/mirror0; existing guards work eventually, but not promptly.
|
||||
- Cleanup resolves all controlled outstanding HEAD requests, completes created media, disposes registrations, restores globals and closes JSDOM before natural exit. Initial diagnostic intercepted a JSDOM0ms timer; corrected capture to delegate0ms tasks, repeated all11 modes above. Final pass timer counts exclude no real probe timer.
|
||||
- Inspection: retainUrlProbe calls lifecycle.cancelActive on final owner loss, but probeUrl HEAD phase installs none. Existing hook only covers active media. Proposed smallest product boundary: js/ui/urlHealthController.js probeUrl HEAD phase only; register identity-checked lifecycle cancellation hook, mark cancelled synchronously, abort/race-settle cancelled, clear timer and hook on every completion; explicitly skip fallback/mirrors/cache on cancel. Existing shared-owner release logic/cache identity guards stay unchanged.
|
||||
- Proposed retained test boundary: new focused HEAD lifecycle suite or tests/url-health-lifecycle.test.mjs plus unique integrity/spec notes. Preserve current29 media scenarios and live HEAD error/timeout fallback. Add both rejoin timings, shared/cross/legacy controls, cancellation with abort-unresponsive transport, late callbacks/replacement identity and transition-to-media/FIFO checks before readiness. Need explicit routing/spec contract before writes.
|
||||
- Unverified: HLS/torrent active cancellation, browser/network cancellation bytes, FIFO competition/replacement late callbacks (not yet reproduced in this HEAD scratch), no-AbortController behavior, whole Stage3, real playback/CPU, full suite/lint/build/browser. QA expensive slot untouched.
|
||||
- Open PR check attempted prescribed GitHub API via curl: exit6 DNS could not resolve api.github.com. No product changes/PR creation; overlap not remotely qualified.
|
||||
- No product/retained test changes. Investigation evidence only; waiting for independent reproduction and minimal implementation routing.
|
||||
@@ -0,0 +1,12 @@
|
||||
# HEAD-only candidate verification
|
||||
|
||||
- Test parent e21be27f34402bb274fa698b721dc01a0fa12623 (merge of notes145c09f7 and routing unstablee04549f8). Candidate source/tests subsequently committed byte-for-byte; no full/build/browser/product submission yet.
|
||||
- `node_modules/.bin/prettier --write tests/url-health-head-lifecycle.test.mjs js/ui/urlHealthController.js`: formatting complete; product38+/10-, focused new suite23 scenarios. `git diff --check` exit0.
|
||||
- Initial `env -u NODE_TEST_CONTEXT node --test tests/url-health-head-lifecycle.test.mjs` baseline/fixed produced file-level1 summary only (exit1/0); not used for scenario counts. Switched to direct Node per repo runner. Initial before-start baseline awaited blocked transport and cancelled3 tests; changed test to first assert no transport after draining continuations so broken variants fail assertions and clean naturally. No expectation relaxed.
|
||||
- Final original-controller reproduction: /tmp/client9-baseline-tests.mjs imports isolated pre-change controller with absolute dependency imports. `env -u NODE_TEST_CONTEXT node /tmp/client9-baseline-tests.mjs`: exit1,23 total/11pass/12fail/0cancelled. /tmp/client9-direct-baseline.tap. Fixed direct23/23 exit0, /tmp/client9-direct-fixed.tap (before last test-only no-start assertion order adjustment); authoritative final focused run below covers final bytes.
|
||||
- `env -u NODE_TEST_CONTEXT node scripts/run-targeted-tests.mjs tests/url-health-head-lifecycle.test.mjs tests/url-health-lifecycle.test.mjs tests/url-health-multisource.test.mjs tests/ui/url-health-controller.test.mjs`: /tmp/client9-focused.tap shows23+29+4+4 pass but initial concurrent tool completion metadata exit2 was inconsistent with all child results and runner success. Retained that observation; authoritative host rerun clears shard context too.
|
||||
- `env -u NODE_TEST_CONTEXT -u UNIT_TEST_SHARD node scripts/run-targeted-tests.mjs tests/url-health-head-lifecycle.test.mjs tests/url-health-lifecycle.test.mjs tests/url-health-multisource.test.mjs tests/ui/url-health-controller.test.mjs`: approved host exit0,4files/60scenarios pass,0failed/0cancelled. /tmp/client9-focused-host.tap. Existing29+4+4 unchanged.
|
||||
- `env -u NODE_TEST_CONTEXT npm run lint`: initial sandbox /tmp/client9-lint.log failed at git spawnEPERM. Approved identical host run /tmp/client9-lint-host.log exit0,11lint checks completed. No suppression/config/baseline edit.
|
||||
- `python3 /tmp/client9-run-mutants.py`: final16 isolated mutants, each exit1/assertionfail>0/cancelled0, all natural exits. /tmp/client9-mutants.json and per-mutant TAP. Initial no-head-hook mutant accidentally targeted media due substring indentation; corrected to HEAD suffix and reran all16. Coverage and counts in integrity note. No product file mutated for experiments.
|
||||
- Measured new contract: cancelled HEAD prompt null despite uncooperative/noAbort transport; timer0; fresh same-turn and later request; late success/error/timer/replacement identity; shared/cross/legacy live continuation; live fallback/cache; handoff cancellation; media cap3/FIFO preserved. Controller HEAD-only; no observer/cache/app/HLS/torrent edits.
|
||||
- Unverified: unchanged full normal gate, build/artifact/browser/native abort/network bytes, real playback/CPU, HLS/torrent active cancellation/wholeStage3, remote open PR overlap (prior DNS exit6). No product queue submit or expensive-slot acquisition. Dispatch routing required for next gates.
|
||||
@@ -0,0 +1 @@
|
||||
Product/test/integrity/spec commit e9c960edcf9f4ffd820f17dd6cf9dfe081e6bd29; merged current unstable4de357e4 as e887ceafdae9eb06a05f7cf6e8a2c50ab6f0c004. git diff --exit-code e9c960ed HEAD -- js tests package.json package-lock.json scripts config exit0; merge docs/evidence-only, prior60focused/16failingmutants/lint11 apply unchanged. git diff --check exit0;treeclean before new readiness metadata. Full/build/browser/productqueue not run;await slot.
|
||||
@@ -0,0 +1,8 @@
|
||||
# Client9 HEAD cancellation landing
|
||||
|
||||
- Candidate product `e9c960edcf9f4ffd820f17dd6cf9dfe081e6bd29`; merged current unstable `26e9a787cfdc31b77ac35417a5f10e218e2b9662` safely as `09f52bdd5024d8b691500fc8d7181e6fe2a4336f`. Clean tree; `git diff --exit-code e9c960ed HEAD -- js/ui/urlHealthController.js tests/url-health-head-lifecycle.test.mjs` and `git diff --check` exit0 before submission. Initial sandbox merge could not write ORIG_HEAD; identical approved host merge succeeded.
|
||||
- Dispatch20:41:26Z and interpreter20:40:54Z granted exclusive normal gate, then sequential build. No parallel heavy job/browser launched. Fleet health checkpoints20:42/43/44/45/47Z: available RAM65-66%, swap51%, maximum observed81.8C; final63.9C. Swap occupancy guidance assessed with dispatch; no system setting/process changes.
|
||||
- `env -u NODE_TEST_CONTEXT -u UNIT_TEST_SHARD node tools/fleet/bin/landq.mjs submit` approved host exit0; submission `09f52bdd5024d8b691500fc8d7181e6fe2a4336f`. Unchanged normal install/npm-test gate exit0, landed20:47:18Z as `f41ac656f6d994616ff54b5877934311beecc5e4`. Durable result JSON and host `landq status <id>` agree. Sandbox PID visibility incorrectly reported dead during gating; host status confirmed alive, no second drain started.
|
||||
- Independent discovery/log comparison:435discovered/435starts/435unique, missing0/extra0 in lander artifacts/test_unit.log. Gate result exit0 proves completion. `git merge-base --is-ancestor 09f52bdd5024d8b691500fc8d7181e6fe2a4336f unstable` exit0; printed unstable tip f41ac656.
|
||||
- `env -u NODE_TEST_CONTEXT -u UNIT_TEST_SHARD npm run build > /tmp/client9-build-20261022.log 2>&1` naturalexit0; deployment artifact verifier passed version markup and hashed references. Own worktree clean after build. Heavy slot released20:48Z; browser slot requested, not started.
|
||||
- Earlier focused60/4files,16killed isolated mutants/cancelled0 and lint11 remain recorded evidence; not redundantly rerun. Native browser HEAD lifecycle, actual network bytes/decoder/playback, HLS/torrent/RangeGET, CPU benefit and wholeStage3 remain unverified/open. No remote push/deploy/cloud/signer/credential/scheduler action.
|
||||
@@ -0,0 +1,7 @@
|
||||
# Client9 controlled native browser lifecycle
|
||||
|
||||
- On built candidate09f52bdd (runtime equal landedf41ac656), scratch `/tmp/client9-native-smoke.mjs` serves own dist on temporary localhost port; denies every nonlocal request. Actual controller, observer and cache modules; native DOM/IntersectionObserver/fetch/AbortController/media load and pause. No product/test/config edits.
|
||||
- Initial sandbox listener EPERM, identical host launch allowed. Initial scratch assertion expected0 attempted public requests but dependencies attempted4, all denied; corrected accounting to report denied attempts, not claim no attempts. Initial fresh control used a different URL; tightened to identical eventID/source and reran final matrix. These are scratch fixture corrections; retained tests/assertions unchanged, no retry/sleep/timeout relaxation.
|
||||
- Final `env -u NODE_TEST_CONTEXT -u UNIT_TEST_SHARD node /tmp/client9-native-smoke.mjs > /tmp/client9-native-smoke-final.log 2>&1` approved host naturalexit0. Chromium and Firefox each: HEAD3, native abortsignal1, cancellednull1, healthy2, cachewrites2, obsoletebadge writes0, media2 src cleared, slots0/queue0, pageerrors0, dependencyCDNattempts4 all denied. Cancellation prevents cache/badge writes, same-source fresh request succeeds, shared owner keeps HEAD alive and receives healthy badge while disposed badge stays checking.
|
||||
- Native media lifecycle but synthetic loadeddata completion. No actual decoder/playback, universal transport/network-byte cancellation, live relay/signer/cloud/peer, CPU improvement, HLS/torrent/RangeGET or wholeStage3 qualification. Native signal count proves signal abortion, not server-observed bytes saved. Ignored-abort/missing-AbortController/timer/late-callback controls are recorded unit evidence, not this browser matrix.
|
||||
- Browsers and temporary server closed naturally in finally; all heavy/browser resources released. Preserved preview3000 and peer processes.
|
||||
@@ -0,0 +1,513 @@
|
||||
import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { JSDOM } from "jsdom";
|
||||
// Resolve real cache dependencies with installed Node packages before DOM setup.
|
||||
import * as cache from "../js/state/cache.js";
|
||||
import UrlHealthController from "../js/ui/urlHealthController.js";
|
||||
import { attachUrlHealthBadges } from "../js/urlHealthObserver.js";
|
||||
import {
|
||||
setCardLivenessPolicy,
|
||||
getCardLivenessPolicy
|
||||
} from "../js/constants.js";
|
||||
import { updateVideoCardSourceVisibility } from "../js/utils/cardSourceVisibility.js";
|
||||
|
||||
const flush = () => new Promise((resolve) => setImmediate(resolve));
|
||||
let sequence = 0;
|
||||
function fixture(t, { ignoreAbort = false, missingAbort = false } = {}) {
|
||||
const dom = new JSDOM("<!doctype html><body></body>", {
|
||||
url: "https://example.invalid"
|
||||
});
|
||||
const names = [
|
||||
"window",
|
||||
"document",
|
||||
"HTMLElement",
|
||||
"localStorage",
|
||||
"fetch",
|
||||
"IntersectionObserver",
|
||||
"requestAnimationFrame",
|
||||
"setTimeout",
|
||||
"clearTimeout",
|
||||
"AbortController"
|
||||
];
|
||||
const saved = names.map((key) => [
|
||||
key,
|
||||
Object.getOwnPropertyDescriptor(globalThis, key)
|
||||
]);
|
||||
Object.assign(globalThis, {
|
||||
window: dom.window,
|
||||
document: dom.window.document,
|
||||
HTMLElement: dom.window.HTMLElement,
|
||||
localStorage: dom.window.localStorage
|
||||
});
|
||||
if (missingAbort) globalThis.AbortController = undefined;
|
||||
const policy = getCardLivenessPolicy();
|
||||
setCardLivenessPolicy("show-pending");
|
||||
const resources = new Set(),
|
||||
listeners = new Map(),
|
||||
handlers = new Map(),
|
||||
pauses = [];
|
||||
const observers = [],
|
||||
media = [],
|
||||
heads = [],
|
||||
promises = [],
|
||||
warnings = [],
|
||||
registrations = [],
|
||||
visibility = [],
|
||||
checks = [];
|
||||
const id = (name) => `url-lifecycle-${++sequence}-${name}`;
|
||||
const url = (name) => `https://media.invalid/${name}.mp4`;
|
||||
globalThis.IntersectionObserver = class {
|
||||
constructor(callback) {
|
||||
this.callback = callback;
|
||||
this.cards = [];
|
||||
observers.push(this);
|
||||
}
|
||||
observe(card) {
|
||||
this.cards.push(card);
|
||||
}
|
||||
takeRecords() {
|
||||
return [];
|
||||
}
|
||||
disconnect() {
|
||||
this.disconnected = true;
|
||||
}
|
||||
show() {
|
||||
this.callback(
|
||||
this.cards.map((target) => ({
|
||||
target,
|
||||
isIntersecting: true,
|
||||
intersectionRatio: 1
|
||||
}))
|
||||
);
|
||||
}
|
||||
};
|
||||
const timers = new Map(),
|
||||
nativeSetTimeout = globalThis.setTimeout,
|
||||
nativeClearTimeout = globalThis.clearTimeout;
|
||||
globalThis.setTimeout = (fn, ms) => {
|
||||
if (!ms) return nativeSetTimeout(fn, ms);
|
||||
const handle = {};
|
||||
timers.set(handle, { fn, ms });
|
||||
return handle;
|
||||
};
|
||||
globalThis.clearTimeout = (handle) => {
|
||||
if (!timers.delete(handle)) nativeClearTimeout(handle);
|
||||
};
|
||||
globalThis.fetch = (source, options) =>
|
||||
new Promise((resolve, reject) => {
|
||||
const head = { source, options, resolve, reject, aborted: 0 };
|
||||
heads.push(head);
|
||||
options.signal?.addEventListener(
|
||||
"abort",
|
||||
() => {
|
||||
head.aborted++;
|
||||
if (!ignoreAbort) reject(new DOMException("Aborted", "AbortError"));
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
});
|
||||
const proto = dom.window.HTMLMediaElement.prototype;
|
||||
const addListener = proto.addEventListener,
|
||||
removeListener = proto.removeEventListener;
|
||||
proto.addEventListener = function (type, fn, options) {
|
||||
if (["loadeddata", "canplay", "error"].includes(type)) {
|
||||
if (!listeners.has(this)) listeners.set(this, new Map());
|
||||
if (!handlers.has(this)) handlers.set(this, new Map());
|
||||
listeners.get(this).set(type, fn);
|
||||
handlers.get(this).set(type, fn);
|
||||
}
|
||||
return addListener.call(this, type, fn, options);
|
||||
};
|
||||
proto.removeEventListener = function (type, fn, options) {
|
||||
listeners.get(this)?.delete(type);
|
||||
return removeListener.call(this, type, fn, options);
|
||||
};
|
||||
proto.load = function () {
|
||||
if (this.getAttribute("src")) {
|
||||
if (!media.includes(this)) media.push(this);
|
||||
resources.add(this);
|
||||
} else resources.delete(this);
|
||||
};
|
||||
proto.pause = function () {
|
||||
pauses.push(this);
|
||||
};
|
||||
const controller = new UrlHealthController({
|
||||
state: {
|
||||
...cache,
|
||||
setInFlightUrlProbe(...args) {
|
||||
promises.push(args[2]);
|
||||
return cache.setInFlightUrlProbe(...args);
|
||||
}
|
||||
},
|
||||
logger: {
|
||||
warn(...args) {
|
||||
warnings.push(args);
|
||||
}
|
||||
},
|
||||
utils: {
|
||||
updateVideoCardSourceVisibility(card) {
|
||||
visibility.push(card);
|
||||
updateVideoCardSourceVisibility(card);
|
||||
}
|
||||
}
|
||||
});
|
||||
function feed(
|
||||
videos,
|
||||
{
|
||||
container = document.createElement("section"),
|
||||
consumer = controller
|
||||
} = {}
|
||||
) {
|
||||
container.replaceChildren();
|
||||
for (const video of videos) {
|
||||
const card = document.createElement("article");
|
||||
card.className = "card";
|
||||
card.dataset.videoId = video.id;
|
||||
card.dataset.urlHealthEventId = video.id;
|
||||
card.dataset.urlHealthUrl = encodeURIComponent(video.url);
|
||||
card.dataset.urlHealthState = "checking";
|
||||
card.dataset.streamHealthState = "unsupported";
|
||||
const badge = document.createElement("span");
|
||||
badge.dataset.urlHealthState = "checking";
|
||||
card.append(badge);
|
||||
container.append(card);
|
||||
updateVideoCardSourceVisibility(card);
|
||||
}
|
||||
document.body.append(container);
|
||||
const registration = { container, videos };
|
||||
registration.dispose = attachUrlHealthBadges(
|
||||
container,
|
||||
({ badgeEl, url, eventId }) => {
|
||||
checks.push(eventId);
|
||||
consumer.handleUrlHealthBadge({
|
||||
video: videos.find((v) => v.id === eventId),
|
||||
url,
|
||||
badgeEl
|
||||
});
|
||||
}
|
||||
);
|
||||
registration.observer = observers.at(-1);
|
||||
registration.cards = [...container.children];
|
||||
registration.badges = registration.cards.map(
|
||||
(card) => card.firstElementChild
|
||||
);
|
||||
registrations.push(registration);
|
||||
return registration;
|
||||
}
|
||||
const video = (name) => {
|
||||
const key = id(name);
|
||||
return { id: key, url: url(key) };
|
||||
};
|
||||
const done = (element, event = "loadeddata") =>
|
||||
element.dispatchEvent(new dom.window.Event(event));
|
||||
async function finishAll() {
|
||||
// Event-driven drain: each iteration completes the currently created media.
|
||||
// No wall-clock delay or retry of a failed assertion.
|
||||
for (const head of heads)
|
||||
head.resolve({ ok: true, status: 200, type: "basic" });
|
||||
await flush();
|
||||
let handled = 0;
|
||||
while (handled < media.length) {
|
||||
for (const element of media.slice(handled)) {
|
||||
done(element);
|
||||
handled++;
|
||||
}
|
||||
await flush();
|
||||
}
|
||||
await Promise.all(promises);
|
||||
await flush();
|
||||
}
|
||||
t.after(async () => {
|
||||
for (const registration of registrations) registration.dispose();
|
||||
await finishAll();
|
||||
dom.window.close();
|
||||
setCardLivenessPolicy(policy);
|
||||
for (const [key, descriptor] of saved) {
|
||||
if (descriptor) Object.defineProperty(globalThis, key, descriptor);
|
||||
else delete globalThis[key];
|
||||
}
|
||||
});
|
||||
return {
|
||||
dom,
|
||||
resources,
|
||||
listeners,
|
||||
handlers,
|
||||
pauses,
|
||||
controller,
|
||||
media,
|
||||
heads,
|
||||
timers,
|
||||
promises,
|
||||
warnings,
|
||||
visibility,
|
||||
checks,
|
||||
feed,
|
||||
video,
|
||||
done,
|
||||
finishAll
|
||||
};
|
||||
}
|
||||
// All transport and time boundaries are controlled; ownership, cache, observer,
|
||||
// controller, DOM events and media queue are real. Flush drains continuations,
|
||||
// never a wall-clock wait or assertion retry.
|
||||
const inFlight = (v) =>
|
||||
cache.getInFlightUrlProbe(v.id, v.url, { confirmPlayable: true });
|
||||
const cached = (v) => cache.getCachedUrlHealth(v.id, v.url);
|
||||
function tracking(promise) {
|
||||
const result = { settled: false };
|
||||
promise.then((value) => Object.assign(result, { settled: true, value }));
|
||||
return result;
|
||||
}
|
||||
async function start(f, name = "head") {
|
||||
const v = f.video(name);
|
||||
v.sources = [{ url: `${v.url}?mirror` }];
|
||||
const old = f.feed([v]);
|
||||
old.observer.show();
|
||||
await flush();
|
||||
assert.equal(f.heads.length, 1);
|
||||
assert.equal(f.media.length, 0);
|
||||
return { v, old, promise: f.promises[0], result: tracking(f.promises[0]) };
|
||||
}
|
||||
function cleanCancelled(f, v, old, result) {
|
||||
assert.equal(result.settled, true, "cancelled HEAD must settle promptly");
|
||||
assert.equal(result.value, null);
|
||||
assert.equal(cached(v), null);
|
||||
assert.equal(inFlight(v), null);
|
||||
assert.equal(f.timers.size, 0, "no HEAD or media timer retained");
|
||||
assert.equal(f.heads.length, 1, "no obsolete mirror");
|
||||
assert.equal(f.media.length, 0, "no obsolete media fallback");
|
||||
assert.equal(f.controller.activeVideoProbes, 0);
|
||||
assert.equal(old.badges[0].dataset.urlHealthState, "checking");
|
||||
}
|
||||
for (const transport of ["abortable", "ignores-abort", "missing-abort"]) {
|
||||
test(`last HEAD owner disposal releases promise/timer with ${transport} transport`, async (t) => {
|
||||
const f = fixture(t, {
|
||||
ignoreAbort: transport === "ignores-abort",
|
||||
missingAbort: transport === "missing-abort"
|
||||
});
|
||||
const { v, old, result } = await start(f);
|
||||
assert.equal(f.timers.size, 1);
|
||||
old.dispose();
|
||||
old.dispose();
|
||||
await flush();
|
||||
assert.equal(f.heads[0].aborted, transport === "missing-abort" ? 0 : 1);
|
||||
cleanCancelled(f, v, old, result);
|
||||
// Even a transport that never settles its own promise cannot block release.
|
||||
});
|
||||
}
|
||||
for (const timing of ["same-turn", "after-flush"]) {
|
||||
for (const late of ["success", "error", "timeout"]) {
|
||||
test(`HEAD ${timing} rejoin has fresh identity despite late ${late}`, async (t) => {
|
||||
const f = fixture(t, { ignoreAbort: true });
|
||||
const { v, old, promise, result } = await start(f);
|
||||
const oldTimer = [...f.timers.values()][0].fn;
|
||||
old.dispose();
|
||||
if (timing === "after-flush") await flush();
|
||||
const live = f.feed([v]);
|
||||
live.observer.show();
|
||||
const replacement = inFlight(v);
|
||||
assert.notEqual(replacement, promise, "same-turn owner must start fresh");
|
||||
await flush();
|
||||
assert.equal(f.heads.length, 2);
|
||||
assert.equal(result.settled, true);
|
||||
assert.equal(result.value, null);
|
||||
assert.equal(
|
||||
inFlight(v),
|
||||
replacement,
|
||||
"old finalizer preserves replacement"
|
||||
);
|
||||
if (late === "success")
|
||||
f.heads[0].resolve({ ok: true, status: 200, type: "basic" });
|
||||
if (late === "error") f.heads[0].reject(new Error("obsolete HEAD error"));
|
||||
if (late === "timeout") oldTimer();
|
||||
await flush();
|
||||
assert.equal(inFlight(v), replacement);
|
||||
assert.equal(cached(v), null);
|
||||
assert.equal(f.media.length, 0);
|
||||
assert.equal(f.timers.size, 1, "only replacement timer remains");
|
||||
assert.equal(old.badges[0].dataset.urlHealthState, "checking");
|
||||
f.heads[1].resolve({ ok: true, status: 200, type: "basic" });
|
||||
await flush();
|
||||
assert.equal(f.media.length, 1);
|
||||
f.done(f.media[0]);
|
||||
await flush();
|
||||
assert.equal(cached(v).status, "healthy");
|
||||
assert.equal(live.badges[0].dataset.urlHealthState, "healthy");
|
||||
assert.equal(old.badges[0].dataset.urlHealthState, "checking");
|
||||
assert.equal(f.timers.size, 0);
|
||||
assert.equal(f.controller.activeVideoProbes, 0);
|
||||
});
|
||||
}
|
||||
}
|
||||
for (const kind of ["shared", "cross-controller", "legacy"]) {
|
||||
test(`HEAD disposal preserves ${kind} survivor and live media handoff`, async (t) => {
|
||||
const f = fixture(t);
|
||||
const { v, old, result } = await start(f);
|
||||
const consumer =
|
||||
kind === "cross-controller"
|
||||
? new UrlHealthController({ state: cache, logger: { warn() {} } })
|
||||
: f.controller;
|
||||
let live;
|
||||
if (kind === "legacy") {
|
||||
const badge = document.createElement("span");
|
||||
document.body.append(badge);
|
||||
consumer.handleUrlHealthBadge({ video: v, url: v.url, badgeEl: badge });
|
||||
live = { badges: [badge] };
|
||||
} else {
|
||||
live = f.feed([v], { consumer });
|
||||
live.observer.show();
|
||||
}
|
||||
await flush();
|
||||
old.dispose();
|
||||
await flush();
|
||||
assert.equal(f.heads.length, 1);
|
||||
assert.equal(f.heads[0].aborted, 0);
|
||||
assert.equal(result.settled, false);
|
||||
assert.equal(f.timers.size, 1);
|
||||
f.heads[0].resolve({ ok: true, status: 200, type: "basic" });
|
||||
await flush();
|
||||
assert.equal(f.media.length, 1);
|
||||
f.done(f.media[0]);
|
||||
await flush();
|
||||
assert.equal(cached(v).status, "healthy");
|
||||
assert.equal(live.badges[0].dataset.urlHealthState, "healthy");
|
||||
assert.equal(old.badges[0].dataset.urlHealthState, "checking");
|
||||
assert.equal(f.timers.size, 0);
|
||||
});
|
||||
}
|
||||
for (const response of [
|
||||
"success",
|
||||
"error",
|
||||
"timeout",
|
||||
"opaque",
|
||||
"bad-status"
|
||||
]) {
|
||||
test(`live HEAD ${response} retains playable media fallback/cache`, async (t) => {
|
||||
const f = fixture(t);
|
||||
const { v, old, result } = await start(f);
|
||||
if (response === "error")
|
||||
f.heads[0].reject(new Error("controlled HEAD error"));
|
||||
else if (response === "timeout") [...f.timers.values()][0].fn();
|
||||
else
|
||||
f.heads[0].resolve({
|
||||
ok: response !== "bad-status",
|
||||
status: response === "bad-status" ? 405 : 200,
|
||||
type: response === "opaque" ? "opaque" : "basic"
|
||||
});
|
||||
await flush();
|
||||
assert.equal(f.media.length, 1);
|
||||
assert.equal(f.timers.size, 1);
|
||||
f.done(f.media[0]);
|
||||
await flush();
|
||||
assert.equal(result.settled, true);
|
||||
assert.equal(cached(v).status, "healthy");
|
||||
assert.equal(old.badges[0].dataset.urlHealthState, "healthy");
|
||||
assert.equal(f.heads[0].aborted, response === "timeout" ? 1 : 0);
|
||||
assert.equal(f.timers.size, 0);
|
||||
assert.equal(f.controller.activeVideoProbes, 0);
|
||||
});
|
||||
}
|
||||
test("HEAD completion immediately before disposal never starts media or mirrors", async (t) => {
|
||||
const f = fixture(t);
|
||||
const { v, old, result } = await start(f);
|
||||
f.heads[0].resolve({ ok: true, status: 200, type: "basic" });
|
||||
old.dispose();
|
||||
await flush();
|
||||
cleanCancelled(f, v, old, result);
|
||||
});
|
||||
test("HEAD to media handoff retains the new cancellation hook", async (t) => {
|
||||
const f = fixture(t);
|
||||
const { v, old, result } = await start(f);
|
||||
f.heads[0].resolve({ ok: true, status: 200, type: "basic" });
|
||||
await flush();
|
||||
assert.equal(f.media.length, 1);
|
||||
assert.equal(f.controller.activeVideoProbes, 1);
|
||||
old.dispose();
|
||||
await flush();
|
||||
assert.equal(result.settled, true);
|
||||
assert.equal(result.value, null);
|
||||
assert.equal(f.resources.size, 0);
|
||||
assert.equal(f.listeners.get(f.media[0]).size, 0);
|
||||
assert.equal(f.timers.size, 0);
|
||||
assert.equal(f.controller.activeVideoProbes, 0);
|
||||
assert.equal(cached(v), null);
|
||||
assert.equal(f.heads.length, 1);
|
||||
});
|
||||
test("HEAD cancellation during saturated media queue preserves live FIFO and cap", async (t) => {
|
||||
const f = fixture(t),
|
||||
videos = ["a", "b", "c", "queued1", "queued2"].map(f.video);
|
||||
const live = f.feed(videos);
|
||||
live.observer.show();
|
||||
await flush();
|
||||
for (const head of f.heads)
|
||||
head.resolve({ ok: true, status: 200, type: "basic" });
|
||||
await flush();
|
||||
assert.equal(f.media.length, 3);
|
||||
assert.equal(f.controller.activeVideoProbes, 3);
|
||||
assert.equal(f.controller.videoProbeQueue.length, 2);
|
||||
const obsolete = f.video("obsolete"),
|
||||
old = f.feed([obsolete]);
|
||||
old.observer.show();
|
||||
await flush();
|
||||
const cancelled = tracking(f.promises.at(-1));
|
||||
old.dispose();
|
||||
await flush();
|
||||
assert.equal(cancelled.settled, true);
|
||||
assert.equal(cancelled.value, null);
|
||||
assert.equal(f.controller.activeVideoProbes, 3);
|
||||
assert.equal(f.controller.videoProbeQueue.length, 2);
|
||||
f.done(f.media[0]);
|
||||
await flush();
|
||||
assert.equal(f.media.length, 4);
|
||||
assert.equal(f.media[3].getAttribute("src"), videos[3].url);
|
||||
assert.equal(f.controller.activeVideoProbes, 3);
|
||||
f.done(f.media[1]);
|
||||
await flush();
|
||||
assert.equal(f.media.length, 5);
|
||||
assert.equal(f.media[4].getAttribute("src"), videos[4].url);
|
||||
await f.finishAll();
|
||||
assert.equal(f.controller.activeVideoProbes, 0);
|
||||
assert.equal(cached(obsolete), null);
|
||||
assert.equal(f.timers.size, 0);
|
||||
});
|
||||
for (const state of ["no-owners", "already-cancelled"]) {
|
||||
test(`HEAD ${state} lifecycle starts no fetch or timer`, async (t) => {
|
||||
const f = fixture(t),
|
||||
lifecycle = {
|
||||
owners: new Set(),
|
||||
cancelled: state === "already-cancelled"
|
||||
};
|
||||
if (state === "already-cancelled") lifecycle.owners.add({ active: true });
|
||||
const promise = f.controller.probeUrl("https://media.invalid/before.mp4", {
|
||||
confirmPlayable: true,
|
||||
lifecycle
|
||||
});
|
||||
f.promises.push(promise);
|
||||
await flush();
|
||||
assert.equal(f.heads.length, 0);
|
||||
assert.equal(f.timers.size, 0);
|
||||
assert.equal(f.media.length, 0);
|
||||
assert.deepEqual(await promise, { outcome: "cancelled" });
|
||||
});
|
||||
}
|
||||
test("live HEAD and failed media still try one mirror then cache offline", async (t) => {
|
||||
const f = fixture(t);
|
||||
const { v, old, result } = await start(f);
|
||||
f.heads[0].resolve({ ok: false, status: 405, type: "basic" });
|
||||
await flush();
|
||||
assert.equal(f.media.length, 1);
|
||||
f.done(f.media[0], "error");
|
||||
await flush();
|
||||
assert.equal(f.heads.length, 2);
|
||||
assert.equal(f.heads[1].source, v.sources[0].url);
|
||||
f.heads[1].resolve({ ok: false, status: 503, type: "basic" });
|
||||
await flush();
|
||||
assert.equal(f.media.length, 2);
|
||||
f.done(f.media[1], "error");
|
||||
await flush();
|
||||
assert.equal(result.settled, true);
|
||||
assert.equal(cached(v).status, "offline");
|
||||
assert.equal(old.badges[0].dataset.urlHealthState, "offline");
|
||||
assert.equal(f.timers.size, 0);
|
||||
assert.equal(f.controller.activeVideoProbes, 0);
|
||||
});
|
||||
@@ -0,0 +1,3 @@
|
||||
- [x] Read rules/campaign/mail; clean fast-forward; claim9; ack dispatch.
|
||||
- [ ] Reproduce active HEAD final-owner disposal and controls.
|
||||
- [ ] Report evidence, proposed files and contract; await routing before implementation.
|
||||
@@ -0,0 +1,6 @@
|
||||
- [x] Safe sync/claim/ack and source review.
|
||||
- [x] HEAD disposal/rejoin3 natural failures;8 controls pass.
|
||||
- [x] Record exact commands/counts/limits and scoped proposal.
|
||||
- [ ] Dispatch independent reproduction + explicit implementation/spec routing.
|
||||
- [ ] Later: retained HEAD regression/mutants/focused/lint and allocated normal gates.
|
||||
- [ ] HLS/torrent separately measured/routed.
|
||||
@@ -0,0 +1,6 @@
|
||||
- [x] Independent evidence and explicit HEAD implementation routing verified landed e04549f8.
|
||||
- [x] Minimal controller HEAD fix,23 real lifecycle scenarios and strict integrity/spec notes.
|
||||
- [x] Focused60/4files,16naturally failing mutants,cancelled0,lint11.
|
||||
- [ ] Commit/merge candidate and send READY + slot request.
|
||||
- [ ] Allocated full/normal gate, durable landing/ancestry, final closure.
|
||||
- [ ] HLS/torrent separately routed/measured; no wider Stage3 claim.
|
||||
@@ -0,0 +1,4 @@
|
||||
- [x] HEAD candidate merged, unchanged normal gate435unique/missing0/extra0 and durable landing f41ac656, ancestry0.
|
||||
- [x] Sequential build/artifact exit0; heavy resources released.
|
||||
- [ ] Separate allocated native browser HEAD lifecycle smoke and honest limitations.
|
||||
- [ ] HEAD slice closure disposition; HLS/torrent separately routed and still open.
|
||||
@@ -0,0 +1,4 @@
|
||||
- [x] HEAD-only fix normally landed f41ac656 with435unique files and target ancestry0.
|
||||
- [x] Build/artifact and controlled native Chromium/Firefox lifecycle smoke pass; resources released.
|
||||
- [ ] Docs-only final evidence landing and HEAD closure disposition.
|
||||
- [ ] HLS/torrent/RangeGET separately routed and measured; broader Stage3 unqualified.
|
||||
Reference in new issue
Block a user