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
kind-conjuring-dawn.md (local plan) — implements the application-anchored slice of the committed spec docs/design/specs/repository-artifact-layer.md (codellm-devkit/.github), roadmap candidates 15–17.
Problem
codeanalyzer-python emits a source-only view: application.symbol_table plus git provenance (app.repository, core.py:625). It has no model of the repository's non-source files, its declared dependencies, or its configuration keys — the producer-side evidence a cross-service / whole-application analysis needs. This issue adds an application-anchored artifact layer (three new node families) as the first of the group-D units, mirroring the existing repository field's ungated, all-levels shape.
Scope boundary
Adds artifact / dependency / config_key nodes only — the three application-anchored families.
Does NOT add config_use (the PY_USES_CONFIG body-node edge, candidate 18) or the PyCallArgument.value extension it needs — that is a follow-up PR. (.env config keys ARE emitted now, namespace env, so the follow-up edge has definitions to resolve against.)
Does NOT touch the source tree, call graph, or dataflow output; existing symbol_table/call_graph/cfg/cdg/ddg emission is unchanged.
PyArtifact / PyDependency / PyConfigKey Pydantic models (schema/py_schema.py), all fields optional-with-default so exclude_none emits no null leaves; artifacts: Dict[str, PyArtifact] map on PyApplication.
can://…/@artifact/… id helpers in schema/ids.py (artifact_id / dependency_id / config_key_id), reusing child_id + path normalization.
Artifact inventory builder (discovery walk reusing _SKIP_DIRS; sha256 hash; text-capture policy — decodable→text, binary→none, over-cap→text_truncated), attached at core.py:625 alongside repository_info (ungated, all levels). Classify the Python-ecosystem file set explicitly (.env/.env.*/.flaskenv, manifests, lockfiles, Dockerfile/compose, *.tf, CI); unknown → other, never dropped.
Dependency parse — extend the pyproject.toml/requirements.txt reader in entrypoints/detect.py (share span/strip helpers; add version_spec/scope/ecosystem/direct) with the §5 scope mapping. Also parse Pipfile, setup.cfg deps, and poetry.lock/uv.lock/Pipfile.lock for resolved_version (lockfile-only transitive deps → direct=False).
Config-key parse (overlay — parse failure never drops the artifact node) for .env/.env.*/.flaskenv (KEY=value, namespace env), yaml/json/properties/ini/toml: dotted keys, value, recognized references[].
--artifact-text/--no-artifact-text (default True) and --artifact-text-max-bytes (default 262144), skip_tests wiring — disabling text drops only the payload, not the inventory.
Neo4j: PyArtifact/PyDependency/PyConfigKey NodeLabels + PY_HAS_ARTIFACT/PY_DECLARES_DEPENDENCY/PY_DEFINES_CONFIG RelTypes in neo4j/schema.py; matching _*_props + b.node/b.edge walk in neo4j/project.py; SCHEMA_VERSION MINOR bump (2.0.0→2.1.0).
Secret capture..env and config files often hold secrets, and text capture is on by default (spec's uniform raw-text policy — the file is already on disk). --no-artifact-text is the off-switch; --artifact-text-max-bytes bounds size. This is a documented, deliberate default, not an oversight.
TOML config parsing needs tomllib (3.11+ stdlib). Verify requires-python before relying on it; if the floor is below 3.11, skip config-key extraction for .toml while still inventorying the artifact (config parsing is a pure overlay — never blocks the node). yaml is already a dependency.
Neo4j props and the DDL catalog are two hand-maintained lists (project.py builds props manually; it imports only SCHEMA_VERSION from schema.py). They must be kept in agreement by hand — the acceptance check is --emit schema reflecting the new families.
Monotonicity: the artifact layer is ungated/all-levels, so its section must be byte-identical across -a 1|2|3|4. test_v2_superset.py must cover it.
Lockfile format drift.poetry.lock/uv.lock/Pipfile.lock have distinct schemas; parse defensively and treat an unparseable lockfile as "no resolved_version" (deps still emitted from the manifest), never a hard failure.
Definition of done
A fixture project (with pyproject.toml incl. optional-dependencies, requirements.txt, a lockfile, a .env, a .yml + .properties config, a binary file, an over-cap text file) produces an artifacts map where: artifact_kind classification is correct (unknown→other, never dropped); dependencies carry the hand-verified scope/version_spec/ecosystem, with resolved_version present where the lockfile pins it; config keys are the exact dotted-key set with references[], and .env keys carry namespace env; the binary file is inventoried with no text; the over-cap file has text_truncated=True.
assert_conformant + _assert_no_nulls pass on the fixture output.
The artifacts section is byte-identical across -a 1|2|3|4 (monotonicity gate green).
--no-artifact-text run: the inventory (paths/kinds/hashes/deps/config keys) is identical to the default run; only text/text_encoding/text_truncated are absent. --artifact-text-max-bytes set below a fixture file's size yields text_truncated=True with a prefix of exactly that many bytes.
--emit schema lists the three node labels + three rel types and SCHEMA_VERSION2.1.0; a projection run emits PY_HAS_ARTIFACT/PY_DECLARES_DEPENDENCY/PY_DEFINES_CONFIG with artifact text present in the graph.
uv run pytest test/ green; a fixture diff shows symbol_table/call_graph/cfg output unchanged.
Plan
kind-conjuring-dawn.md(local plan) — implements the application-anchored slice of the committed specdocs/design/specs/repository-artifact-layer.md(codellm-devkit/.github), roadmap candidates 15–17.Problem
codeanalyzer-pythonemits a source-only view:application.symbol_tableplus git provenance (app.repository,core.py:625). It has no model of the repository's non-source files, its declared dependencies, or its configuration keys — the producer-side evidence a cross-service / whole-application analysis needs. This issue adds an application-anchored artifact layer (three new node families) as the first of the group-D units, mirroring the existingrepositoryfield's ungated, all-levels shape.Scope boundary
artifact/dependency/config_keynodes only — the three application-anchored families.config_use(thePY_USES_CONFIGbody-node edge, candidate 18) or thePyCallArgument.valueextension it needs — that is a follow-up PR. (.envconfig keys ARE emitted now, namespaceenv, so the follow-up edge has definitions to resolve against.)symbol_table/call_graph/cfg/cdg/ddgemission is unchanged.Goals
PyArtifact/PyDependency/PyConfigKeyPydantic models (schema/py_schema.py), all fields optional-with-default soexclude_noneemits nonullleaves;artifacts: Dict[str, PyArtifact]map onPyApplication.can://…/@artifact/…id helpers inschema/ids.py(artifact_id/dependency_id/config_key_id), reusingchild_id+ path normalization._SKIP_DIRS; sha256 hash; text-capture policy — decodable→text, binary→none, over-cap→text_truncated), attached atcore.py:625alongsiderepository_info(ungated, all levels). Classify the Python-ecosystem file set explicitly (.env/.env.*/.flaskenv, manifests, lockfiles,Dockerfile/compose,*.tf, CI); unknown →other, never dropped.pyproject.toml/requirements.txtreader inentrypoints/detect.py(share span/strip helpers; addversion_spec/scope/ecosystem/direct) with the §5 scope mapping. Also parsePipfile,setup.cfgdeps, andpoetry.lock/uv.lock/Pipfile.lockforresolved_version(lockfile-only transitive deps →direct=False)..env/.env.*/.flaskenv(KEY=value, namespaceenv), yaml/json/properties/ini/toml: dotted keys,value, recognizedreferences[].--artifact-text/--no-artifact-text(defaultTrue) and--artifact-text-max-bytes(default262144),skip_testswiring — disabling text drops only the payload, not the inventory.PyArtifact/PyDependency/PyConfigKeyNodeLabels +PY_HAS_ARTIFACT/PY_DECLARES_DEPENDENCY/PY_DEFINES_CONFIGRelTypes inneo4j/schema.py; matching_*_props+b.node/b.edgewalk inneo4j/project.py;SCHEMA_VERSIONMINOR bump (2.0.0→2.1.0)..claude/SCHEMA_DECISIONS.mdentry (first-class-nodes decision, ungated placement, id grammar, closed enums, deferred config_use).Caveats and known risks
.envand config files often hold secrets, and text capture is on by default (spec's uniform raw-text policy — the file is already on disk).--no-artifact-textis the off-switch;--artifact-text-max-bytesbounds size. This is a documented, deliberate default, not an oversight.tomllib(3.11+ stdlib). Verifyrequires-pythonbefore relying on it; if the floor is below 3.11, skip config-key extraction for.tomlwhile still inventorying the artifact (config parsing is a pure overlay — never blocks the node).yamlis already a dependency.project.pybuilds props manually; it imports onlySCHEMA_VERSIONfromschema.py). They must be kept in agreement by hand — the acceptance check is--emit schemareflecting the new families.-a 1|2|3|4.test_v2_superset.pymust cover it.poetry.lock/uv.lock/Pipfile.lockhave distinct schemas; parse defensively and treat an unparseable lockfile as "noresolved_version" (deps still emitted from the manifest), never a hard failure.Definition of done
pyproject.tomlincl. optional-dependencies,requirements.txt, a lockfile, a.env, a.yml+.propertiesconfig, a binary file, an over-cap text file) produces anartifactsmap where:artifact_kindclassification is correct (unknown→other, never dropped); dependencies carry the hand-verifiedscope/version_spec/ecosystem, withresolved_versionpresent where the lockfile pins it; config keys are the exact dotted-key set withreferences[], and.envkeys carry namespaceenv; the binary file is inventoried with notext; the over-cap file hastext_truncated=True.assert_conformant+_assert_no_nullspass on the fixture output.artifactssection is byte-identical across-a 1|2|3|4(monotonicity gate green).--no-artifact-textrun: the inventory (paths/kinds/hashes/deps/config keys) is identical to the default run; onlytext/text_encoding/text_truncatedare absent.--artifact-text-max-bytesset below a fixture file's size yieldstext_truncated=Truewith a prefix of exactly that many bytes.--emit schemalists the three node labels + three rel types andSCHEMA_VERSION2.1.0; a projection run emitsPY_HAS_ARTIFACT/PY_DECLARES_DEPENDENCY/PY_DEFINES_CONFIGwith artifacttextpresent in the graph.uv run pytest test/green; a fixture diff showssymbol_table/call_graph/cfgoutput unchanged.