Repository navigation
feat(manifest): record each subproject's dependency tree in JVM facts - #1585
Conversation
Facts merged every resolution root's edges into one graph keyed by coordinate, so a package's dependencies in one subproject leaked into every other subproject that also uses it. Edges move out of components into a top-level dependencies list: each entry is a component with one exact subtree, shared by every position whose subtree is identical, and each project lists the entries at the roots of its own tree (its configurations merged). Identical subtrees are found by partition refinement, so cycles merge exactly too. The compute-artifacts sidecar keeps its contract: projects still carry their direct dependency ids. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
In the dependency-tree shape, a subproject's own build files go on projects[].manifestFiles, and components no longer carry manifestFiles. Consumers attribute a direct component to the build files of the projects whose children include it, and every component to the facts file itself, so neither is written per component. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The sbt facts plugin read lm-coursier's update report too literally, which left resolved nodes unreachable from a project's direct dependencies. The assembler then rooted those nodes in projects[].children, mixing them with real direct dependencies. - Match callers by org:name. lm-coursier stamps a caller with its declared version rather than the resolved one, so exact-GAV matching dropped edges from conflict winners. - Take sibling subprojects from the build structure, following sbt's own Classpaths.interSort. The update report lists every inter-project dependency in every configuration, and cross-versioning can merge distinct siblings into one module. - Fail on unreached nodes instead of rooting them, so projects[].children is exactly the direct dependencies. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With per-subproject trees in .socket.facts.json, Coana's socket fix reads each project's direct dependencies from the facts file itself. - Stop refusing an existing .socket.facts.json; upload it like any other manifest. --dynamic-sbom-inference regenerates it. - Stop writing the resolved-paths sidecar for socket fix and drop --compute-artifacts-sidecar, along with runDynamicSbomInference's now unused sidecar option. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
children holds exactly the subproject's direct dependencies; the assembler fails on unreached nodes instead of rooting them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
This draft targets the correct branch, v1.x. Keep the coordinated backend and Coana changes as merge prerequisites. High: preserve existing facts before generationThe PR removes the pre-existing facts guard from Suggestion 💡: back up existing files before generation and restore them on success and failure. Add a regression that begins with an existing facts file and checks its original bytes after cleanup. Integration check: confirm the replacement for the fix sidecarThe patch removes Suggestion 💡: link the coordinated Coana change that replaces this input, or retain the sidecar until it lands. Verify an actual fix application, as well as facts ingestion, before merging. |
…cy-tree # Conflicts: # CHANGELOG.md # src/commands/fix/coana-fix.mts # src/commands/manifest/scripts/assemble.mts # src/commands/manifest/scripts/assemble.test.mts # src/commands/manifest/scripts/facts.mts # src/commands/manifest/scripts/sidecar.mts # src/commands/manifest/scripts/sidecar.test.mts # src/commands/manifest/scripts/socket-facts.plugin.scala
…rence Facts files present before generation were overwritten before any backup, and removed by the cleanup after a fix or a failed generation. Back them up first and restore them afterwards; upload a regenerated file only once.
…roject graph Build each subproject's merged graph once and read projects[].children, the sidecar's direct dependencies and its classpath from it. Also drop a dead build-module ext lookup in the sbt plugin and pass socket fix's facts generation a single facts-file finder.
…d file A facts tree names each project's direct dependencies, so the build file on projects[].manifestFiles only has to mark the subproject. Gradle's API does not say which script declared a dependency, so use the project's configured build file, present or not, and drop the declaring-script records recovered from stack frames.
…lm-coursier callers
|
[agent] Thanks, both addressed:
|
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 2 potential issues.
Bugbot Autofix is ON, but none of the reported issues met your autofix severity threshold.
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 0361123. Configure here.
socket fix can run an older Coana (--fix-version) that reads each project's classpath from the sidecar rather than from facts trees. A Coana that reads facts trees ignores the sidecar for them.
|
[agent] Update to my reply above: |
Martin Torp (mtorp)
left a comment
There was a problem hiding this comment.
LGTM ✅
Don't know if Oskar Haarklou Veileborg (@BarrensZeppelin) has some comments since he reviewed the Coana PR.
The bare .socket.facts.json is Coana's report, not producer output, so socket fix skips it as reachability scans already do.
…cy-tree # Conflicts: # CHANGELOG.md
|
[agent] End-to-end check with the published socket 1.8.0 and Coana 15.12.5:
No generated facts files are left behind after any run. |

LLM Description written by Claude Code:claude-opus-5-5
JVM facts merged every resolution root's edges into one graph keyed by coordinate. A package's dependencies in one subproject therefore leaked into every other subproject that also uses it, mis-attributing dependency chains and manifests. This records each subproject's own dependency tree instead.
Merge gate: release with a Coana bump that contains coana-tech/coana-package-manager#2544, whose
socket fixreads per-project trees. depscan already reads the format (SocketDev/depscan#27464, merged).Format
{ "components": [ { "type": "maven", "namespace": "…", "name": "jackson-databind", "version": "2.15.2", "id": "…" }, … ], "dependencies": [ { "component": 1 }, { "component": 2, "children": [0] }, { "component": 0 }, { "component": 2, "children": [2, 0] } ], "projects": [ { "id": "g:worker:1", "name": "worker", "subprojectDir": "worker", "manifestFiles": [{ "file": "worker/pom.xml" }], "children": [1] }, { "id": "g:api:1", "name": "api", "subprojectDir": "api", "manifestFiles": [{ "file": "api/pom.xml" }], "children": [3] } ] }dependencies(new, top level): a component with one exact subtree.componentindexescomponents;childrenindexesdependencies. Positions with identical subtrees share an entry.projects[].childrenreplacesprojects[].dependencies: the subproject's direct dependencies, the roots of its tree. A resolved dependency the direct ones don't reach fails the run.componentsno longer carrydependenciesormanifestFiles. A consumer attributes every component to the facts file, and a direct component to themanifestFilesof each project whosechildreninclude it.projects[].manifestFilesis the build file the tool reports for the project: Maven's POM, sbt's files defining the project's settings, and Gradle's configured build file even when absent on disk (Gradle doesn't expose where a dependency was declared). This replaces the per-dependency declaring-script marks of feat(manifest): attribute Gradle direct dependencies to their declaring build script #1593.devstays a per-component flag.Also in this PR
dependenciesandclasspath, keyed by project id) and is still passed to Coana bysocket fixand reachability, since the Coana version can be chosen independently (--fix-version,--reach-version). An older Coana gets reachability as today; itssocket fixknows from the sidecar which subprojects resolve a package but can't read direct dependencies or edges from a tree.socket fixaccepts Socket facts files already in the repo instead of refusing to run. With--dynamic-sbom-inferencethey are backed up before generation and restored afterwards, also when generation fails.Verification
socket fixCLI test that depends on the local API token.🤖 Generated with Claude Code