fix(browser): preserve passive network inventory uncertainty

Preserve uncertainty in offline passive network comparisons when request
identity, metadata, or per-kind inventory coverage is incomplete. Retain
proven HTTP/WebSocket changes without using missing information to infer
membership, duplicate counts, or equality.

Compare redirect resource types only where both observations retain them.
Keep metadata completeness with its owner, stream HTTP content digests,
and require full coverage for multiplicity and WebSocket stream inventories.
Preserve independently known metadata changes and full-inventory counts.

Keep the original JavaScript configuration-escape, JSON, cancellation,
SAZ and schema-documentation fixes compatible with current main. Split
public CLI comparisons into isolated test cases without loosening timeouts.
Validate actual Chromium/HTTP captures through CLI and real stdio SDK,
with explicit limits and unchanged source bytes.

Co-authored-by: To3akaRin <131595336+To3akaRin@users.noreply.github.com>
Co-authored-by: N0zoM1z0 <161784452+N0zoM1z0@users.noreply.github.com>
Co-authored-by: Kaoru0822 <208281322+kaoru0822-kitauji@users.noreply.github.com>
Co-authored-by: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
This commit is contained in:
authored and GitHub committed 2026-10-15 02:28:46 +08:00
1 parent b8510ee00b
commit e79e014f23
20 files changed
+1500 -121

No files matched your search

@@ -69,21 +69,30 @@ export function* collectSemanticMemberMutationsSteps(
node: t.Node | undefined,
): void => {
const identity = semanticRequireExportsIdentity(specifier, path);
// Node stores process.env values and process.argv entries as strings, so
// passing one to a call exposes no object that the callee could mutate.
// Replacing an entry records its own write or receiver escape.
let effectPath = identity.path;
// Only known value slots are primitive. Unknown or inherited selections
// can expose the container prototype and affect any subsequently read slot.
if (
effect === "escape" &&
identity.specifier === "process" &&
identity.path.length === 2 &&
(identity.path[0] === "env" || identity.path[0] === "argv")
)
return;
effectPath.length === 2 &&
(effectPath[0] === "env" || effectPath[0] === "argv")
) {
const selected = effectPath[1];
if (
(typeof selected === "string" || typeof selected === "number") &&
(effectPath[0] === "env"
? !Object.hasOwn(Object.prototype, selected)
: selected === "length" || semanticArrayIndex(selected) !== null)
)
return;
effectPath = [effectPath[0], null];
}
const key = JSON.stringify([
"required",
identity.specifier,
effect,
identity.path,
effectPath,
node?.start,
node?.end,
]);
@@ -91,7 +100,7 @@ export function* collectSemanticMemberMutationsSteps(
recordedRequiredEffects.add(key);
recordedEffectCount += 1;
const effects = state.requiredModuleEffects.get(identity.specifier) ?? [];
effects.push({ path: identity.path, node, kind: effect });
effects.push({ path: effectPath, node, kind: effect });
state.requiredModuleEffects.set(identity.specifier, effects);
};
// Ambient indexing owns aliases of global objects. Consume its canonical