Compare commits

...
Author SHA1 Message Date
Kaoru0822andClaude Opus 5.5 c6cda443c1 docs(javascript): state that duplicate unmapped content stays ambiguous
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 03:33:36 +00:00
Kaoru0822andClaude Opus 5.5 e308f35c43 fix(javascript): keep unmapped captured runtime scripts unknown
A captured script whose bytes matched no static digest was reported as
high-confidence unmatched even when no automatic or caller-declared
mapping applied to its location in any static layer. The matcher now
computes mapping presence once while locating candidates and shares one
no-candidate classification between the captured-source and source-free
branches, so an unmapped location stays unknown with
no-authorized-location-mapping and is not counted as unmatched.

Fixes #6061.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 02:20:21 +00:00
3 changed files with 267 additions and 35 deletions

No files matched your search

+6 -1
View File
@@ -106,7 +106,12 @@ nodes. REA evaluates compatible static candidates conservatively:
that disagreement. If a mapped candidate's digest is unavailable and no that disagreement. If a mapped candidate's digest is unavailable and no
mapped content match is known, the comparison remains `unknown`. mapped content match is known, the comparison remains `unknown`.
6. Missing authorization mappings and incomplete or truncated input coverage 6. Missing authorization mappings and incomplete or truncated input coverage
remain unknown or truncated rather than becoming absence claims. remain unknown or truncated rather than becoming absence claims. A runtime
location with no automatic artifact-root or caller-declared mapping into
any layer, and no content match, is `unknown` with
`no-authorized-location-mapping`, with or without captured bytes; several
content matches remain `ambiguous` under rule 4. Only a mapped location can
be `unmatched` with `no-static-content-match`.
Every successful cross-layer `observed_as` edge has Every successful cross-layer `observed_as` edge has
`authority: cross-layer-reconciliation` and `state: inferred`. The underlying `authority: cross-layer-reconciliation` and `state: inferred`. The underlying
@@ -77,14 +77,13 @@ const reconcileEntity = (
reason: "runtime-location-unresolved", reason: "runtime-location-unresolved",
candidates: [], candidates: [],
}); });
const locations = candidatesWithLocation(entity, index, layers); const { locations, mapped } = locateEntity(entity, index, layers);
if (entity.sourceSha256 !== null) if (entity.sourceSha256 !== null)
return reconcileCapturedSource( return reconcileCapturedSource(entity, entity.sourceSha256, {
entity,
entity.sourceSha256,
locations, locations,
mapped,
index, index,
); });
const location = locations.at(0); const location = locations.at(0);
if (locations.length === 1 && location !== undefined) { if (locations.length === 1 && location !== undefined) {
@@ -103,20 +102,40 @@ const reconcileEntity = (
reason: "ambiguous-static-candidates", reason: "ambiguous-static-candidates",
candidates: locations.map(({ candidate }) => candidate), candidates: locations.map(({ candidate }) => candidate),
}); });
const mapped = layers.some( return withoutStaticCandidate(entity, mapped, "unknown");
(layer) => mappedRuntimePaths(layer, entity).length > 0,
);
return unresolved(entity, {
status: mapped ? "unmatched" : "unknown",
basis: "none",
confidence: "unknown",
reason: mapped
? "no-static-content-match"
: "no-authorized-location-mapping",
candidates: [],
});
}; };
/**
* Classify an entity with no qualifying static candidate. Absence is claimed
* only beneath an automatic or caller-declared mapping; without one, the
* runtime location has no authorized static counterpart and stays unknown.
* Captured bytes compared against every static digest support a high-confidence
* absence; a location-only absence does not.
*/
const withoutStaticCandidate = (
entity: RuntimeReconciliationEntity,
mapped: boolean,
absenceConfidence: JavaScriptRuntimeReconciliationItem["confidence"],
): EvaluatedMatch =>
unresolved(
entity,
mapped
? {
status: "unmatched",
basis: "none",
confidence: absenceConfidence,
reason: "no-static-content-match",
candidates: [],
}
: {
status: "unknown",
basis: "none",
confidence: "unknown",
reason: "no-authorized-location-mapping",
candidates: [],
},
);
interface LocatedCandidate { interface LocatedCandidate {
readonly candidate: StaticRuntimeCandidate; readonly candidate: StaticRuntimeCandidate;
readonly mapping: MappedRuntimePath; readonly mapping: MappedRuntimePath;
@@ -125,8 +144,15 @@ interface LocatedCandidate {
const reconcileCapturedSource = ( const reconcileCapturedSource = (
entity: RuntimeReconciliationEntity, entity: RuntimeReconciliationEntity,
sourceSha256: string, sourceSha256: string,
locations: readonly LocatedCandidate[], {
index: CandidateIndex, locations,
mapped,
index,
}: {
readonly locations: readonly LocatedCandidate[];
readonly mapped: boolean;
readonly index: CandidateIndex;
},
): EvaluatedMatch => { ): EvaluatedMatch => {
// A known mapped candidate owns the comparison. Unrelated equal bytes cannot // A known mapped candidate owns the comparison. Unrelated equal bytes cannot
// repair a disagreement or establish the content of a candidate without a digest. // repair a disagreement or establish the content of a candidate without a digest.
@@ -176,23 +202,19 @@ const reconcileCapturedSource = (
candidates: locations.map(({ candidate: located }) => located), candidates: locations.map(({ candidate: located }) => located),
}); });
} }
return unresolved(entity, { return withoutStaticCandidate(entity, mapped, "high");
status: "unmatched",
basis: "none",
confidence: "high",
reason: "no-static-content-match",
candidates: [],
});
}; };
const candidatesWithLocation = ( const locateEntity = (
entity: RuntimeReconciliationEntity, entity: RuntimeReconciliationEntity,
index: CandidateIndex, index: CandidateIndex,
layers: readonly ParsedStaticLayer[], layers: readonly ParsedStaticLayer[],
): LocatedCandidate[] => { ): { readonly locations: LocatedCandidate[]; readonly mapped: boolean } => {
const located = new Map<string, LocatedCandidate>(); const located = new Map<string, LocatedCandidate>();
let mapped = false;
for (const layer of layers) for (const layer of layers)
for (const mapping of mappedRuntimePaths(layer, entity)) for (const mapping of mappedRuntimePaths(layer, entity)) {
mapped = true;
for (const candidate of [ for (const candidate of [
...(index.byLayerCategoryPath.get( ...(index.byLayerCategoryPath.get(
layerCategoryPathKey(layer.layerId, entity.staticKind, mapping.path), layerCategoryPathKey(layer.layerId, entity.staticKind, mapping.path),
@@ -215,12 +237,16 @@ const candidatesWithLocation = (
const key = candidateKey(candidate); const key = candidateKey(candidate);
if (!located.has(key)) located.set(key, { candidate, mapping }); if (!located.has(key)) located.set(key, { candidate, mapping });
} }
return [...located.values()].sort((left, right) => }
compareUnicodeCodePoints( return {
candidateKey(left.candidate), locations: [...located.values()].sort((left, right) =>
candidateKey(right.candidate), compareUnicodeCodePoints(
candidateKey(left.candidate),
candidateKey(right.candidate),
),
), ),
); mapped,
};
}; };
const indexCandidates = ( const indexCandidates = (
@@ -229,3 +229,204 @@ it("keeps unavailable mapped digests unknown instead of borrowing unrelated matc
reason: "static-or-runtime-coverage-incomplete", reason: "static-or-runtime-coverage-incomplete",
}); });
}); });
const UNRELATED = "export const unrelated = 17;\n";
type LayerSetup = {
readonly root: string;
readonly mapping: "none" | "explicit";
};
/** Reconcile one captured script, located at absent.js under live, against layers. */
const reconcileCapturedScript = async (input: {
readonly layers: readonly LayerSetup[];
readonly live: string;
readonly source: string;
readonly includeWorker?: boolean;
}) => {
const result = reconcileJavaScriptRuntime(
parseRuntimeReconciliationInput(
reconcileJavaScriptRuntimeInputSchema.parse({
static_layers: await Promise.all(
input.layers.map(async ({ root, mapping }, index) => ({
role: (["application", "cache", "assets"] as const)[index],
analysis: await analyzeFixture(root),
runtime_mappings:
mapping === "explicit"
? [{ kind: "file-root", root: input.live, artifact_prefix: "" }]
: [],
})),
),
runtime_observations: [
electronRuntimeEvidence(input.live, input.source, {
scriptFile: "absent.js",
includeWorker: input.includeWorker ?? false,
}),
],
}),
),
);
const item = (kind: string) =>
result.reconciliations.find(({ entity_kind }) => entity_kind === kind);
return { result, script: item("script"), worker: item("worker") };
};
it("keeps an unmapped captured script without a content match unknown", async () => {
const root = await applicationFixture();
const live = await createTestTempDirectory("rea-runtime-unmapped-");
const { result, script, worker } = await reconcileCapturedScript({
layers: [{ root, mapping: "none" }],
live,
source: UNRELATED,
includeWorker: true,
});
const unknown = {
status: "unknown",
basis: "none",
confidence: "unknown",
reason: "no-authorized-location-mapping",
static_layer_id: null,
static_node_id: null,
candidate_static_count: 0,
};
expect(script).toMatchObject(unknown);
// A source-free worker at an unmapped location shares the same rule.
expect(worker).toMatchObject(unknown);
expect(result.summary).toMatchObject({ matched: 0, unmatched: 0 });
expect(
result.graph.edges.some(({ relation }) => relation === "observed_as"),
).toBe(false);
});
it.each(["explicit", "implicit-root"] as const)(
"reports a mapped captured script without a content match as unmatched (%s)",
async (mapping) => {
const root = await applicationFixture();
const live =
mapping === "explicit"
? await createTestTempDirectory("rea-runtime-mapped-absent-")
: root;
const { result, script } = await reconcileCapturedScript({
layers: [{ root, mapping: mapping === "explicit" ? "explicit" : "none" }],
live,
source: UNRELATED,
});
expect(script).toMatchObject({
status: "unmatched",
basis: "none",
confidence: "high",
reason: "no-static-content-match",
candidate_static_count: 0,
});
expect(result.summary.unmatched).toBe(1);
},
);
it.each([
["only the second", ["none", "explicit"], "unmatched"],
["only the first", ["explicit", "none"], "unmatched"],
["neither", ["none", "none"], "unknown"],
] as const)(
"classifies an unmatched captured script when %s of two layers maps it",
async (_label, mappings, status) => {
const live = await createTestTempDirectory("rea-runtime-layer-mapping-");
const { script } = await reconcileCapturedScript({
layers: await Promise.all(
mappings.map(async (mapping) => ({
root: await applicationFixture(),
mapping,
})),
),
live,
source: UNRELATED,
});
expect(script).toMatchObject({
status,
reason:
status === "unknown"
? "no-authorized-location-mapping"
: "no-static-content-match",
});
},
);
it.each([
[1, "matched", "unique-content-match"],
[2, "ambiguous", "ambiguous-static-candidates"],
] as const)(
"keeps unmapped content-only correspondence with %i digest candidates",
async (copies, status, reason) => {
const live = await createTestTempDirectory("rea-runtime-unmapped-content-");
const { result, script } = await reconcileCapturedScript({
layers: await Promise.all(
Array.from({ length: copies }, async () => {
const root = await applicationFixture();
await writeFile(join(root, "other.js"), CAPTURED);
return { root, mapping: "none" as const };
}),
),
live,
source: CAPTURED,
});
expect(script).toMatchObject({
status,
basis: copies === 1 ? "content-sha256" : "none",
reason,
candidate_static_count: copies,
});
expect(result.summary.unmatched).toBe(0);
},
);
it.each([
["https://example.test/assets/absent.js", "unmatched"],
["https://other.test/assets/absent.js", "unknown"],
] as const)(
"applies URL-prefix mapping presence to captured script %s",
async (url, status) => {
const root = await applicationFixture();
const parsed = parseRuntimeReconciliationInput(
reconcileJavaScriptRuntimeInputSchema.parse({
static_layers: [
{
role: "application",
analysis: await analyzeFixture(root),
runtime_mappings: [
{
kind: "url-prefix",
prefix: "https://example.test/assets/",
artifact_prefix: "",
},
],
},
],
runtime_observations: [
electronRuntimeEvidence(root, UNRELATED, { includeWorker: false }),
],
}),
);
// Model a URL-located capture at the matcher boundary; browser and
// Inspector projections supply URL locations to the same classifier.
const entities = projectRuntimeCaptures(parsed.captures).entities.map(
(entity) =>
entity.kind === "script"
? { ...entity, location: { kind: "url" as const, value: url } }
: entity,
);
const result = reconcileRuntimeEntities({
entities,
candidates: collectStaticRuntimeCandidates(parsed.layers),
layers: parsed.layers,
});
expect(
result.items.find(({ entity_kind }) => entity_kind === "script"),
).toMatchObject({
status,
confidence: status === "unknown" ? "unknown" : "high",
reason:
status === "unknown"
? "no-authorized-location-mapping"
: "no-static-content-match",
});
},
);