Skip to content

Repository-artifact layer: artifacts, dependencies, config keys (python parity) #101

Description

@rahlk

Plan

docs/design/specs/artifacts-and-dependencies.md (committed on the work branch). Parity anchor: codeanalyzer-python's SHIPPED layer (51ee29e) — implementation over draft where they differ.

Problem

Schema v2 is code-only: nothing represents package.json manifests, lockfiles, tsconfig/rc configs, Dockerfiles, CI workflows, or the dependencies an app declares. Python shipped the three-family answer (artifact / dependency / config_key contained under the application node, ungated at every level); TS emits none of it, so cross-analyzer artifact queries dead-end at this repo.

Scope boundary

Additive only: no existing field, id tier, or level moves; schema_version stays put (python precedent), Neo4j contract bumps additively to 2.2.0. NOT in scope: import→package binding / unresolved_imports / purl (not in python's shipped unit), transitive lockfile records (direct:false reserved), YAML parsing (yarn.lock/pnpm-lock/yaml configs are inventory-only artifacts), caching of the scan.

Goals

  • Model: TSArtifact / TSDependency / TSConfigKey mirroring python's shipped shapes field-for-field; application.artifacts{} with contained children; ids stamped per-run by assignIds (@artifact/ marker)
  • src/artifacts/ — walk (SKIP_DIRS, sorted) + rules table → artifact_kind/format; sha256 + size always; text capture under --artifact-text-max-bytes (256 KiB default, truncate+flag)
  • deps extraction: every package.json (workspaces included) → declared records with scope mapping incl. the coined additive peer token; JSON lockfile family (package-lock / npm-shrinkwrap / bun.lock) backfills resolved_version on declared records only
  • config extraction: .env-family flat keys (namespace "env") + JSON dotted keys
  • Neo4j 2.2.0: :TSArtifact/:TSDependency/:TSConfigKey + TS_HAS_ARTIFACT/TS_DECLARES_DEPENDENCY/TS_DEFINES_CONFIG + constraints; schema.neo4j.json regen
  • Wire gate: artifact content_hash MUST appear on the wire — restructure the internal-field strip so the module-cache trio's key names don't eat artifact fields
  • Fixture app covering every format + level-invariance, conformance, determinism, Neo4j row tests; python-sdk TS-model extras-tolerance verified

Caveats and known risks

  • The strip-filter collision (module content_hash internal vs artifact content_hash wire) is called out in the spec — key-name stripping must become structural or scoped.
  • TSArtifact.source = producing subsystem (python's field), colliding in NAME with module.source semantics — inherited parity, documented, not "fixed".
  • One shared-vocabulary token coined: dependency scope peer — recorded in the spec + SCHEMA_DECISIONS; python's Literal grows when next touched.
  • yarn.lock / pnpm-lock.yaml ship as artifacts WITHOUT resolved_version — absence is the documented signal, not a parse failure.

Definition of done

Spec's DoD verbatim: identical artifacts at all levels; fixture asserts every format + peer scope + wire content_hash; Neo4j 2.2.0 rows + regen; two-run byte-identical determinism; suite/typecheck green; CLAUDE.md + SCHEMA_DECISIONS + README/--help updated.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions