mirror of
https://github.com/morluto/rea.git
synced 2026-11-12 01:41:21 +00:00
* refactor(analysis): centralize resource budgets and recovery facts * feat(analysis): expose ASAR and Ghidra runtime admission controls * feat(artifacts): expose reader admission and preserve limited recognition * feat(javascript): expose recoverable semantic precision budgets * feat(web): add recoverable source-map budgets and compact retained views * feat(web): make historical capture decoding budgets recoverable * fix(desktop): enforce selected view policies across capture and export * feat(runtime): make Frida and LLDB retention budgets selectable * feat(native): expose diagnostic budgets and preserve exhaustion causes * feat(managed): expose recoverable snapshot and representation budgets * feat(metadata): make Go and Rust inspection budgets recoverable * feat(wasm): expose representation and producer admissions * feat(evm): expose per-call worker resource budgets * feat(android): make resource and string-pool omissions recoverable * feat(producers): expose command and recorded-capture budgets * docs(analysis): record recovery contracts and integrated validation * fix(docs): link calibration oracle from published verification pages * fix(docs): restore desktop task anchors and receipt links * test(analysis): align fixtures with selectable budget contracts * fix(analysis): remove source-location projector dependency cycle * test(analysis): refresh budget recovery and verifier regressions * test(analysis): preserve format and publication recovery expectations * test(windows): align conformance with owned runtime admission * fix(desktop): preserve selected alias kinds in exported state * test(analysis): align provider fixtures with recoverable budgets * test(desktop): validate emitted alias metadata structurally * fix(ghidra): classify bounded Windows endpoint refusals * test(cli): assert selectable artifact admission recovery * fix(cli): preserve capture provenance in environment builds
127 lines
4.0 KiB
TypeScript
127 lines
4.0 KiB
TypeScript
import type { JavaScriptSemanticPropertyPath } from "./javascriptSemanticPropertyPaths.js";
|
|
import { JAVASCRIPT_SEMANTIC_PRECISION_DEFAULTS } from "./javascriptSemanticPrecision.js";
|
|
|
|
type PropertyKey = JavaScriptSemanticPropertyPath[number];
|
|
|
|
/** Finite alternatives retain selected keys without admitting unrelated slots. */
|
|
export type SemanticAliasSelection =
|
|
| PropertyKey
|
|
| { readonly alternatives: readonly PropertyKey[] };
|
|
|
|
export type SemanticAliasSelectionPath = readonly SemanticAliasSelection[];
|
|
|
|
export const semanticAliasSelectionChoices = (
|
|
key: SemanticAliasSelection,
|
|
): readonly PropertyKey[] =>
|
|
key !== null && typeof key === "object" && "alternatives" in key
|
|
? key.alternatives
|
|
: [key];
|
|
|
|
const selection = (choices: readonly PropertyKey[]): SemanticAliasSelection => {
|
|
if (choices.includes(null)) return null;
|
|
const alternatives = [
|
|
...new Map(choices.map((choice) => [JSON.stringify(choice), choice])),
|
|
]
|
|
.sort(([left], [right]) => (left < right ? -1 : left > right ? 1 : 0))
|
|
.map(([, choice]) => choice);
|
|
return alternatives.length === 1 ? alternatives[0]! : { alternatives };
|
|
};
|
|
|
|
const selectionCovers = (
|
|
prior: SemanticAliasSelection,
|
|
next: SemanticAliasSelection,
|
|
): boolean => {
|
|
if (prior === null) return true;
|
|
const choices = new Set(
|
|
semanticAliasSelectionChoices(prior).map((key) => JSON.stringify(key)),
|
|
);
|
|
return semanticAliasSelectionChoices(next).every((key) =>
|
|
choices.has(JSON.stringify(key)),
|
|
);
|
|
};
|
|
|
|
const pathCovers = (
|
|
prior: SemanticAliasSelectionPath,
|
|
next: SemanticAliasSelectionPath,
|
|
): boolean =>
|
|
prior.every(
|
|
(key, index) =>
|
|
next[index] !== undefined && selectionCovers(key, next[index]!),
|
|
);
|
|
|
|
/** Only one differing selector can be joined without inventing crossed paths. */
|
|
const joinSelections = (
|
|
prior: SemanticAliasSelectionPath,
|
|
next: SemanticAliasSelectionPath,
|
|
): SemanticAliasSelectionPath | undefined => {
|
|
let changed = -1;
|
|
for (let index = 0; index < prior.length; index++) {
|
|
if (JSON.stringify(prior[index]) === JSON.stringify(next[index])) continue;
|
|
if (changed !== -1) return undefined;
|
|
changed = index;
|
|
}
|
|
return prior.map((key, index) =>
|
|
index === changed
|
|
? selection([
|
|
...semanticAliasSelectionChoices(key),
|
|
...semanticAliasSelectionChoices(next[index]!),
|
|
])
|
|
: key,
|
|
);
|
|
};
|
|
|
|
/** Preserve correlated selector alternatives while coalescing complete grids. */
|
|
export class SemanticAliasSelections {
|
|
#paths = new WeakMap<object, Map<number, SemanticAliasSelectionPath[]>>();
|
|
#calls = 0;
|
|
#limited = false;
|
|
|
|
constructor(
|
|
readonly onLimit: () => void,
|
|
readonly maxSelections: number = JAVASCRIPT_SEMANTIC_PRECISION_DEFAULTS.alias_selections,
|
|
) {}
|
|
|
|
get limited(): boolean {
|
|
return this.#limited;
|
|
}
|
|
|
|
normalize(
|
|
node: object,
|
|
next: SemanticAliasSelectionPath,
|
|
): SemanticAliasSelectionPath {
|
|
if (this.#limited) return next.map(() => null);
|
|
const existing = this.#paths.get(node);
|
|
const byDepth = existing ?? new Map<number, SemanticAliasSelectionPath[]>();
|
|
const paths = [...(byDepth.get(next.length) ?? [])];
|
|
let candidate = next.map((key) =>
|
|
selection(semanticAliasSelectionChoices(key)),
|
|
);
|
|
const covered = paths.find((prior) => pathCovers(prior, candidate));
|
|
if (covered !== undefined) return covered;
|
|
if (existing !== undefined && ++this.#calls > this.maxSelections) {
|
|
this.#limited = true;
|
|
this.#paths = new WeakMap();
|
|
this.onLimit();
|
|
return next.map(() => null);
|
|
}
|
|
for (let index = 0; index < paths.length;) {
|
|
const prior = paths[index]!;
|
|
if (pathCovers(prior, candidate)) return prior;
|
|
const joined = pathCovers(candidate, prior)
|
|
? candidate
|
|
: joinSelections(prior, candidate);
|
|
if (joined === undefined) {
|
|
index++;
|
|
continue;
|
|
}
|
|
candidate = [...joined];
|
|
paths.splice(index, 1);
|
|
index = 0;
|
|
}
|
|
paths.push(candidate);
|
|
byDepth.set(candidate.length, paths);
|
|
this.#paths.set(node, byDepth);
|
|
return candidate;
|
|
}
|
|
}
|