* fix: repair the static-check failures on the default branch
The default branch fails its own required `Static checks` job three ways, so
every pull request reports that job as failed regardless of its own change.
- `npm run format:check` reports `src/domain/functionComparison.test.ts` and
`src/ida/IdaOperationRunner.ts`.
- `npm run lint` reports a duplicate `import { join } from "node:path"` in
`tests/boundary/mcp/ghidraInventoryMcp.test.ts` (lines 4 and 17).
- `npm run typecheck` reports `format: "devin"` missing from the client format
union in `src/application/SupportedClients.ts`, and an unchecked index in
`tests/boundary/cli/clientProfileLifecycle.test.ts`, whose pair array is
inferred as `string[][]`.
Apply the pinned formatter, drop the duplicate import, list the `"devin"` format
that its own definition already uses, and mark the pair array `as const`.
Validation: `npm run check:fast` and `npm run format:check` pass.
* fix(setup): keep Devin on the JSON configuration dialect
---------
Co-authored-by: 吴佳浩 <wujiahao@supremind.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
Split two over-long test functions into module-level helpers
(max-lines-per-function): IdaSessionClient transport cases, IDA provider
composition, and function comparison identity cases keep their names and
assertions.
Also fix three typecheck errors: default omitted
direct_invokes_exhaustive to null so the result schema stays JsonValue
compatible, parse the ghidra dossier before spreading it, and delete the
optional beforeCall hook instead of assigning undefined under
exactOptionalPropertyTypes.
* fix(reconstruction): reject contradictory function comparison status
* test(reconstruction): cover imported function match precedence
---------
Co-authored-by: maxazure <405711+maxazure@users.noreply.github.com>
* feat(ghidra): decode Swift String literals in function dossiers
Swift passes a String as two words. Small literals keep their UTF-8 bytes
inside those words, and immortal large literals keep a count plus a pointer
to their bytes biased by 32. Ghidra creates no data reference for either, so
analyze_function reported no strings for Swift code.
On AArch64 programs that contain Swift metadata, the Ghidra bridge now runs
constant propagation over the function and decodes register pairs where
Swift consumes a String: consecutive argument registers at calls and tail
calls, x0 and x1 at returns, and both registers of one STP. Large literals
must resolve to terminated bytes inside one initialized block that is not
executable. A pair whose registers both come from conditional selects is
skipped, because Ghidra forks each select without correlating the
condition and could otherwise pair words from different cases.
Decoded values are a derivation from the ABI layout rather than observed
references, so they appear in a new optional swift_string_literals field
with their source instruction, registers and raw words, and in a matching
inspect_analysis_view facet. referenced_strings is unchanged.
Refs #2030
* fix(ghidra): bound Swift literal reads and compare decoded strings
Large immortal literals are measured against the remaining heap before
allocation, and a failed fit stays visible as a limitation. The canonical
empty string is kept. Small and large literals now require matching
address nullability, and function comparison treats decoded literals as
string evidence without equating a missing record to an empty one.
* fix(ghidra): budget Swift literal decoding and tighten use sites
Large literals now draw on one heap budget per dossier, measured once
before decoding, instead of a separate check per literal. A literal that
does not fit is listed in a new swift_string_literal_omissions field
with its address, byte length and reason, so consumers read omissions
from structured data rather than from limitation text.
strings_names comparison checks referenced strings and names first and
reports a change there even when Swift literal coverage differs; it
returns unknown only when those facts match and literal coverage is
absent on one side or partial.
A computed jump counts as a tail call only when it has no resolved
target inside the function, so jump tables no longer qualify, and a
return requires a RETURN p-code operation, so traps no longer qualify.
Decoded literals keep control characters, which Swift strings may
contain and JSON escapes. The Swift verifier builds the literal fixture
for arm64 on any Mac host and now also covers the empty string and a
literal containing a tab.
* fix(ghidra): charge escaped JSON and follow copied selects
The Swift literal budget now charges the worst case per UTF-8 byte: UTF-16
text, six escaped JSON characters held in Gson's growing buffer and in the
returned String, and the UTF-8 bytes written to the socket. Literals made
of control characters can no longer exceed the reserved heap.
A jump counts as a tail call only when every resolved target lies outside
the function. The conditional select check follows register copies back
to their definition, so selects copied into argument registers are
recognized like selects written there directly.
strings_names reports a change when both dossiers decoded different
literals at the same use site, even when either side has omissions; it
returns unknown only when no such use site disagrees.
* fix(ghidra): bound literal records and trace selects across branches
Every Swift literal record now pays a fixed cost against the dossier
budget in addition to its text, so many empty or small literals are
bounded as well. The first record that does not fit is kept as an
omission and decoding stops there, which keeps the omission record
itself bounded; omissions now describe small or large literals.
The conditional select check searches every predecessor path for the
reaching definitions, following register copies, so selects made
before a branch into the use block are recognized.
A dossier records Swift literals and their omissions together. Coverage
reads omissions first, and strings_names compares every use site that
neither side omitted: a decoded literal is known where it was recorded,
and an absence is known only in a dossier whose decoding examined every
use site.
* fix(ghidra): stop every flow at the literal budget and route omissions
Ending one flow from the evaluator leaves other queued flows running, so
the budget now records a shared stop that every flow checks before it
examines another instruction. A record that exceeds the budget is routed
by that capacity result rather than by whether text was decoded, so a
small literal over budget becomes an omission instead of a literal.
When coverage is partial, the per site comparison keeps each literal's
representation as well as its value, matching the full strings_names
projection.
* fix(ghidra): keep unresolved Swift tail-call sites unknown
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
Treat missing, partial, unknown, and unresolved call coverage as insufficient for call-set equality. Combine IDA caller/callee coverage without losing either explanation and recheck source coverage when verifying historical comparisons.
Scope generated function-comparison unknowns with optional typed comparison/dimension facts, preserving legacy IDs and revision digests when absent. Keep unrelated dimensions conclusive, explicit dependencies applicable, and ambiguous function identity unknown. A confirmed change for matched functions remains a failure even if calls are incomplete.
Validation: function/reconstruction/residual-unknown and bundle tests, recorded IDA protocol regression, public MCP comparison/verification, and advertised SDK JSON Schema checks. Real IDA provider execution was not verified.
Fixes#2222
Share parser modes and collision-free composite keys, enforce architecture guards, and consolidate redundant unit assertions into filesystem, CLI, MCP, and producer-backed workflows. Preserve concurrent upstream boundary fixes and exclude legacy Objective-C class-name bookkeeping labels.
Validation: source/composition suites (3358 passing), focused canonical digest and MCP checks, typecheck/lint, Knip, formatting, architecture guards, and real Foundation archive and Apple legacy simulator CLI/MCP verification. No real Hopper, Ghidra, or IDA verification claim.
Reject omitted segment bounds, procedure classification and body facts, unresolved-call observations, dossier facets, and Ghidra parameter flow metadata. Providers emit explicit nulls for unsupported facets. Verify those unknowns in the real Hopper workflow.
BREAKING CHANGE: Provider analysis outputs must explicitly supply metadata previously repaired with defaults; unsupported nullable facets must be reported as null.
Remove forwarding wrappers and shadow aliases, migrate callers and verification scripts to their owners, and share one exhaustive semantic resource-bound projection.
Compare complete function dossiers directly, remove unreachable truncation and collection wrappers, and preserve deterministic Unicode ordering. Require real external reference targets instead of display placeholders.
BREAKING CHANGE: function comparison results no longer advertise the unreachable truncated state or counter.
Equivalent hexadecimal addresses no longer collapse a fully observed CFG to unknown, and duplicate numeric block starts are rejected even when spelled differently.
* refactor(test): colocate pure-domain tests and reduce test debt
Move focused immutable domain/contracts/adapter tests from
tests/composition/** beside their production owners under src/** as
colocated *.test.ts/*.fixture.ts, and relocate persistence-shaped
composition tests under tests/boundary/filesystem/**. Update import
paths, the Vitest project topology (shared worker context for pure
domain/contracts and recording-port service projects), the test
migration ledger, testing docs, and AGENTS.md to match.
Generated with [Devin](https://devin.ai)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* docs: remove test migration ledger
The cutover is complete and the ledger is no longer referenced anywhere
in source, scripts, or the docs gate. Drop the standalone artifact.
Generated with [Devin](https://devin.ai)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* docs: clean up stale migration artifacts
Remove empty directories left by the test migration and replace the
"final cutover" language in docs/testing.md with standing PR guidance
that no longer references the completed migration.
Generated with [Devin](https://devin.ai)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* fix: repair CI failures from schema, knip, and stale generated artifacts
Three root causes fixed:
1. catalog-schemas.mjs: valuesAt only traversed anyOf from Zod's
toJSONSchema, not oneOf. The webScreenshotDiffSchema change to a
discriminated union produces oneOf, so the product catalog generator
could not derive the web_screenshot_diff schema version. Add oneOf
traversal.
2. conformancePackage.ts: the test rewrite removed the only imports of
ScenarioManifest, ReplayPlan, ShimPlan, and ExpectedEvidence, making
them unused exports that knip flags. Remove the dead type aliases.
3. Regenerate stale artifacts (product catalog, MCP tool catalog, skill
metadata, conformance manifest) that drifted from the source changes.
Generated with [Devin](https://devin.ai)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
---------
Co-authored-by: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-08-10 14:57:44 +08:00
Renamed from tests/composition/analysis-sessions/functionComparison.test.ts (Browse further)