You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Implement the repository-artifact layer in codeanalyzer-java — the producer-side evidence a cross-service / whole-application analysis needs but no analyzer emits today. Contract of record: docs/design/specs/repository-artifact-layer.md (committed in codellm-devkit/.github), tracked by epic codellm-devkit/.github#45.
This is the first PR for the Java train, the application-anchored slice, into the canonical schema v2 model (--schema v2, package com.ibm.cldk.schema.*):
artifact nodes (JArtifact) — a non-source file inventory with raw-text capture
dependency nodes (JDependency) — normalized deps parsed from pom.xml / Gradle coordinates (net-new — today deps are only downloaded as jars, never modeled)
config_key nodes (JConfigKey) — normalized keys from structured config files
All three anchor on the application node (stable, no body-node risk). The shared vocabulary (scope enum, artifact_kind enum, @artifact/ id grammar) is coined verbatim per the spec's parity clause, identical to the python/typescript trains.
Two Java-specific divergences (found by inspecting the code, not just the spec)
Neo4j is now available for this layer — the premise this issue was written on is obsolete. When this issue was filed, analyzeV2() rejected --emit neo4j and the Neo4j projector ran entirely off the legacy v1 IR, so a v2 addition could reach analysis.json but never the graph. That is no longer true: PR feat(l4): interprocedural SDG — param_in/param_out, semantic DDG, summary edges, graph 2.1.0 #203 shipped the canonical v2 graph projection (V2GraphProjector, V2SchemaCatalog, graph contract 2.0.0, since bumped to 2.1.0 by the L4 overlay), removed the guard, and made --schema v2 the default. "Roadmap candidate 9", the v1→v2 Neo4j migration this issue deferred to, is done. Whoever picks this up should decide afresh whether to project the artifact layer into the graph in the same PR — the epic's J_USES_CONFIG-only deferral and this issue's broader whole-layer deferral were both consequences of a blocker that no longer exists. Note that V2SchemaCatalog already reserves un-prefixed Artifact and Package labels as cross-language merge targets, declared but not emitted, so the graph vocabulary is partly staked out already.
Artifact discovery needs a new repo-wide walk. The v2 walk (L1Extractor.extractAll) is source-root scoped — it only enumerates .java files under JavaParser source roots and never sees a repo-root pom.xml / application.yml / Dockerfile. The inventory needs its own Files.walk of the project root, homed alongside utils/ProjectDirectoryScanner.java, not hooked into L1Extractor.
CanId.artifactId / dependencyId / configKeyId helpers (@artifact/ marker keeps them out of the signatureOf id space)
Repo-wide inventory + classification walk (new com.ibm.cldk.artifacts package); other catch-all — a file is never dropped
Raw-text capture (utf-8 / binary / over-cap truncation), --artifact-text / --no-artifact-text (default on) + --artifact-text-max-bytes (default 262144); parsing reads a decode buffer independent of capture so the flag drops only the raw-text payload
Dependency parse: pom.xml (JDK DOM, on the classpath) with groupId:artifactId identity, version_spec, <scope>/<optional> → shared scope; build.gradle/.kts shallow regex reader; gradle.lockfile → resolved_version; ecosystem="maven"
Config parse (overlay — failure never drops the artifact): .properties (java.util.Properties), application.yml/.yaml (needs a new YAML dep — see open decision), Jakarta EE .xml descriptors; dotted keys, value, references[] (${VAR} → env:VAR)
Extend the local conformance schema src/test/resources/schema/analysis.v2.schema.json ($defs + enum constraints + application.artifacts) — the L1 conformance gate validates against it with additionalProperties:false
Decision-log entry
Out (follow-ups / other trains):
config_use / J_USES_CONFIG edge (follow-up PR; Java is well-positioned — JBodyNode already carries receiverExpr/argumentExpr at L1, so System.getenv reads are visible without a PyCallArgument.value-style extension; @Value/@ConfigurationProperties reads anchor on JDecorator)
YAML dependency: add SnakeYAML to build.gradle now (enables application.yml config-key extraction; needs a reflect-config.json entry for native-image), or ship .yml inventoried-but-unparsed this PR. Recommendation: add now — application.yml is the dominant Spring Boot config surface.
Gradle depth: shallow regex reader misses version-catalog (libs.*) / dynamic deps. Accept as a documented, logged limitation for PR 1 (Maven pom.xml is the complete path), or scope Gradle out of PR 1.
Acceptance
application.artifacts emitted as a contained named map of artifact nodes with stable can://…/@artifact/… ids; unrecognized files artifact_kind:"other", never dropped
pom.xml (and best-effort Gradle) parsed into dependency nodes with groupId:artifactId identity and correct scope; gradle.lockfile pins resolved_version
Structured config exposes config_key nodes with dotted keys and recognized references[]
Text-decodable artifacts carry verbatim text + text_encoding/text_truncated; binary/over-cap remain inventoried with path + content_hash
--no-artifact-text drops only the text payload; inventory + deps + config overlay unchanged
artifacts section byte-identical across -a 1|2|3 (ungated / all-levels)
L1ConformanceGateTest green (local v2 schema extended); no null leaves
Neo4j untouched: Neo4jSchemaConformanceTest green, schema_version 1.0.0 unchanged, --schema v2 --emit neo4j still errors, no artifact labels in the graph catalog — obsolete. The v1 catalog is no longer what --emit schema emits (it now always emits the v2 catalog, currently 2.1.0), and --schema v2 --emit neo4j is the supported default path. Replace with whatever the re-scoping decides.
Update (2026-08-29): the Neo4j premise above was invalidated by PR #203 (v2 graph projection) and PR #205 (@entry defines the formals). Struck text is left visible rather than deleted so the original reasoning stays auditable. The rest of the scope — application-anchored JArtifact/JDependency/JConfigKey, pom.xml/Gradle coordinate parsing, config-key extraction, and the repo-wide walk L1Extractor cannot do — is unaffected and still accurate.
Summary
Implement the repository-artifact layer in
codeanalyzer-java— the producer-side evidence a cross-service / whole-application analysis needs but no analyzer emits today. Contract of record:docs/design/specs/repository-artifact-layer.md(committed incodellm-devkit/.github), tracked by epic codellm-devkit/.github#45.This is the first PR for the Java train, the application-anchored slice, into the canonical schema v2 model (
--schema v2, packagecom.ibm.cldk.schema.*):artifactnodes (JArtifact) — a non-source file inventory with raw-text capturedependencynodes (JDependency) — normalized deps parsed frompom.xml/ Gradle coordinates (net-new — today deps are only downloaded as jars, never modeled)config_keynodes (JConfigKey) — normalized keys from structured config filesAll three anchor on the application node (stable, no body-node risk). The shared vocabulary (
scopeenum,artifact_kindenum,@artifact/id grammar) is coined verbatim per the spec's parity clause, identical to the python/typescript trains.Two Java-specific divergences (found by inspecting the code, not just the spec)
Neo4j is now available for this layer — the premise this issue was written on is obsolete. When this issue was filed,
analyzeV2()rejected--emit neo4jand the Neo4j projector ran entirely off the legacy v1 IR, so a v2 addition could reachanalysis.jsonbut never the graph. That is no longer true: PR feat(l4): interprocedural SDG — param_in/param_out, semantic DDG, summary edges, graph 2.1.0 #203 shipped the canonical v2 graph projection (V2GraphProjector,V2SchemaCatalog, graph contract2.0.0, since bumped to2.1.0by the L4 overlay), removed the guard, and made--schema v2the default. "Roadmap candidate 9", the v1→v2 Neo4j migration this issue deferred to, is done. Whoever picks this up should decide afresh whether to project the artifact layer into the graph in the same PR — the epic'sJ_USES_CONFIG-only deferral and this issue's broader whole-layer deferral were both consequences of a blocker that no longer exists. Note thatV2SchemaCatalogalready reserves un-prefixedArtifactandPackagelabels as cross-language merge targets, declared but not emitted, so the graph vocabulary is partly staked out already.Artifact discovery needs a new repo-wide walk. The v2 walk (
L1Extractor.extractAll) is source-root scoped — it only enumerates.javafiles under JavaParser source roots and never sees a repo-rootpom.xml/application.yml/Dockerfile. The inventory needs its ownFiles.walkof the project root, homed alongsideutils/ProjectDirectoryScanner.java, not hooked intoL1Extractor.Scope
In (this PR):
JArtifact/JDependency/JConfigKeyLombok@DataPOJOs +JApplication.artifactsmap (com.ibm.cldk.schema.*)CanId.artifactId/dependencyId/configKeyIdhelpers (@artifact/marker keeps them out of thesignatureOfid space)com.ibm.cldk.artifactspackage);othercatch-all — a file is never dropped--artifact-text/--no-artifact-text(default on) +--artifact-text-max-bytes(default 262144); parsing reads a decode buffer independent of capture so the flag drops only the raw-text payloadpom.xml(JDK DOM, on the classpath) withgroupId:artifactIdidentity,version_spec,<scope>/<optional>→ sharedscope;build.gradle/.ktsshallow regex reader;gradle.lockfile→resolved_version;ecosystem="maven".properties(java.util.Properties),application.yml/.yaml(needs a new YAML dep — see open decision), Jakarta EE.xmldescriptors; dotted keys,value,references[](${VAR}→env:VAR)src/test/resources/schema/analysis.v2.schema.json($defs+ enum constraints +application.artifacts) — the L1 conformance gate validates against it withadditionalProperties:falseOut (follow-ups / other trains):
config_use/J_USES_CONFIGedge (follow-up PR; Java is well-positioned —JBodyNodealready carriesreceiverExpr/argumentExprat L1, soSystem.getenvreads are visible without aPyCallArgument.value-style extension;@Value/@ConfigurationPropertiesreads anchor onJDecorator)All Neo4j projection of the artifact layer — rides candidate 9— obsolete: candidate 9 landed in PR feat(l4): interprocedural SDG — param_in/param_out, semantic DDG, summary edges, graph 2.1.0 #203. Re-scope when picked up.Open decisions (resolve before/at review)
build.gradlenow (enablesapplication.ymlconfig-key extraction; needs areflect-config.jsonentry for native-image), or ship.ymlinventoried-but-unparsed this PR. Recommendation: add now —application.ymlis the dominant Spring Boot config surface.libs.*) / dynamic deps. Accept as a documented, logged limitation for PR 1 (Mavenpom.xmlis the complete path), or scope Gradle out of PR 1.Acceptance
application.artifactsemitted as a contained named map ofartifactnodes with stablecan://…/@artifact/…ids; unrecognized filesartifact_kind:"other", never droppedpom.xml(and best-effort Gradle) parsed intodependencynodes withgroupId:artifactIdidentity and correctscope;gradle.lockfilepinsresolved_versionconfig_keynodes with dotted keys and recognizedreferences[]text+text_encoding/text_truncated; binary/over-cap remain inventoried withpath+content_hash--no-artifact-textdrops only the text payload; inventory + deps + config overlay unchangedartifactssection byte-identical across-a 1|2|3(ungated / all-levels)L1ConformanceGateTestgreen (local v2 schema extended); nonullleavesNeo4j untouched:— obsolete. The v1 catalog is no longer whatNeo4jSchemaConformanceTestgreen,schema_version 1.0.0unchanged,--schema v2 --emit neo4jstill errors, no artifact labels in the graph catalog--emit schemaemits (it now always emits the v2 catalog, currently2.1.0), and--schema v2 --emit neo4jis the supported default path. Replace with whatever the re-scoping decides.symbol_table/call_graphoutput byte-identicalPart of epic codellm-devkit/.github#45. Sibling: codeanalyzer-python#152.
Update (2026-08-29): the Neo4j premise above was invalidated by PR #203 (v2 graph projection) and PR #205 (
@entrydefines the formals). Struck text is left visible rather than deleted so the original reasoning stays auditable. The rest of the scope — application-anchoredJArtifact/JDependency/JConfigKey,pom.xml/Gradle coordinate parsing, config-key extraction, and the repo-wide walkL1Extractorcannot do — is unaffected and still accurate.