Skip to content

can:// ids gain a <service> segment; collapse <app> (schema 2.1.0) #123

Description

@rahlk

Spec: codellm-devkit/.githubdocs/design/specs/can-uri-service-segment.md
Coordination: codellm-devkit/.github#39

Problem

codeanalyzer/schema/ids.py hard-codes the language into the scheme constant and builds the
application root beneath it:

_SCHEME = "can://python"

def application_id(app_name: str) -> str:
    return f"{_SCHEME}/{app_name}"

So every durable id is can://python/<app>/<file>/<type>/<sig>, with no deployment dimension.
A polyglot microservice has no single id root, and cocoa has had to invent one outside the
schema (cocoa/system/facts.py:39 wraps our id as fn:<service>/can://python/…).

Per the spec, <service> becomes the outermost segment and <app> collapses into it:

before  can://python/<app>/<file>/<type>/<sig>
after   can://<service>/python/<file>/<type>/<sig>

Because the service must sit above the language, _SCHEME can no longer be a literal prefix —
it becomes can://{service}/python. Everything below application_id composes from it unchanged
(module_id, child_id, callable_sig_segment, ordinal_id are pure and parent-relative).

Scope boundary

This repo only. Does not add cross-service edges (no RPC/HTTP call family — Epic E), does not
touch the keystone grammar docs in cldk-devtools/cldk-skillset, does not touch cocoa, and
does not touch codeanalyzer-typescript (its own issue). The can:// scheme name is settled.

Does not change the Neo4j property-graph version in codeanalyzer/dataflow/builder.py:741
(schema_version="1.0.0") — that is a separate contract from the analysis.json envelope.

Goals

  • schema/ids.py — service becomes the outermost segment; <app> removed
  • CLI: --app-name--service, same default (input directory name)
  • schema/py_schema.pyAnalysis.schema_version default → "2.1.0"
  • core.py:728 cache freshness gate → != "2.1.0" (auto-invalidates every 2.0.0 cache)
  • Neo4j projection (neo4j/project.py, neo4j/schema.py) — ids and SCHEMA_VERSION follow
  • v2 test suite updated (test_v2_ids.py, test_v2_conformance.py, test_v2_cache.py, conftest_v2.py, test_cli.py)
  • .claude/SCHEMA_DECISIONS.md — record the five locked decisions from the spec

Caveats and known risks

  • The version number understates the break. 2.1.0 is MINOR for a change that rewrites every
    durable id and the Neo4j MERGE key. Deliberate erratum, valid only because no consumer holds a
    can:// id today (python-sdk is pre-v2 and addresses by signature). Not precedent later.
  • Persisted Neo4j graphs need a full re-ingest, not an incremental MERGE — every node key
    changes, so merging against a 2.0.0 database builds a parallel graph.
  • Shared libraries are analyzed once per service by design: one run per service, so a libs/
    imported by six services yields six id sets for the same source. Accepted (spec D5).
  • Renaming --app-name is a CLI break for any existing caller. Whether to keep it as a
    deprecated alias is an open call — the spec does not decide it.
  • Must land in lockstep with codeanalyzer-typescript's equivalent change; cocoa is gated on
    both.

Definition of done

  • canpy -i ./python-sdk with no flags emits can://python-sdk/python/cldk/core.py/CLDK/…
    — verified on a real run, not an asserted shape
  • canpy -i ./svc --service emailservice emits can://emailservice/python/…
  • No emitted id contains an <app> segment distinct from the service
  • Every edge endpoint resolves — call_graph, param_in/param_out, backfilled callee
    with zero dangling references on an L4 run of a real repo
  • Ordinal ids below the callable unchanged (<callable-id>@<line>:<col>, @entry,
    @formal_in:0, @16:2/actual_in:0)
  • schema_version reads "2.1.0"; a cached 2.0.0 analysis.json is rejected and rebuilt
  • L1 ⊆ L2 ⊆ L3 ⊆ L4 monotonicity holds on a real repo — the prov:["ssa"] DDG set is
    identical at L3 and L4, with L4 adding only points-to and reaching-defs
  • --emit neo4j produces a graph whose node keys are the new ids and whose declared schema
    matches the emitter (existing conformance test still passes)

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