Skip to content

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

Closed as not planned

Description

@rahlk

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

Problem

src/schema/v2/emit.ts:350 builds the application root with the language outermost:

const appId = `can://${LANGUAGE}/${appName}`;

so every durable id is can://typescript/<app>/<file>/<type>/<sig>, with no deployment
dimension. A polyglot microservice therefore has no single id root — its TypeScript and Python
halves land under unrelated authorities — and cocoa has had to build one outside the schema
(cocoa/system/facts.py:39 wraps our id as fn:<service>/can://…).

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

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

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, does not touch cocoa, and does not touch codeanalyzer-python
(its own issue). The can:// scheme name is settled and not in scope.

Does not attempt to reconcile the two known sibling divergences recorded in the
codeanalyzer-dotnet spec — UTF-16 vs UTF-8 span offsets, and unprefixed vs per-language Neo4j
labels. Both are real, both make this repo the outlier, and both are their own design session.

Goals

  • src/schema/v2/emit.ts:350 — service becomes the outermost segment; <app> removed
  • src/schema/v2/model.ts:39 — the id: string; // can://<lang>/<app> comment follows
  • src/cli.ts:19 — --app-name <name> → --service <name>, same default (input dir name);
    src/options/options.ts:15 appName renamed with it
  • src/build/neo4j/schema.ts — SCHEMA_VERSION → "2.1.0"; CanNode keys follow the ids
  • homeExternals (emit.ts:301) — verify @external ids still compose from appId with no
    logic change: can://<service>/typescript/@external/<module>/<name>
  • Anonymous-callback ordinal ids (<enclosing-can-id>@<line>:<col>) unchanged
  • v2 tests + test/neo4j-schema.test.ts conformance updated

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 CanNode MERGE key — this repo's own rule in src/build/neo4j/schema.ts
    says MAJOR on a renamed key. Deliberate erratum, valid only because no consumer holds a
    can:// id today (typescript-sdk is pre-v2, zero references). Not precedent later.
  • Persisted Neo4j graphs need a full re-ingest, not an incremental MERGE.
  • Shared code is analyzed once per service by design: one run per service (spec D5).
  • Renaming --app-name is a CLI break for existing callers. Whether to keep a deprecated
    alias is an open call the spec does not decide.
  • Must land in lockstep with codeanalyzer-python's equivalent change; cocoa is gated on both.

Definition of done

  • A no-flag run on a TS project emits can://<dir-name>/typescript/src/… — verified on a
    real run, not an asserted shape
  • --service checkout emits can://checkout/typescript/src/cart.ts/CartService/checkout(userId)
  • No emitted id contains an <app> segment distinct from the service
  • External library targets resolve as can://<service>/typescript/@external/<module>/<name>
    and every callee backfilled at L2 points at a resolvable id
  • Every edge endpoint resolves — call_graph, extends_ids/implements_ids,
    param_in/param_out — with zero dangling references
  • Ordinal ids below the callable unchanged, including anonymous callbacks
  • schema_version reads "2.1.0" in both the JSON envelope and the Neo4j contract
  • test/neo4j-schema.test.ts passes — the emitter produces no undeclared label,
    relationship, or property

Activity

  1. rahlk commented on Aug 19, 2026

    @rahlk
    ContributorAuthor

    Version reshuffle: this moves to schema 2.2.0.

    #92 (materialize anonymous callables as first-class callables) takes 2.1.0 instead. Rationale: the EXP-001 Juice Shop dataflow measurement is blocked behind #92 — no req.body.email fact reaches the DDG until anonymous handlers are graphed — whereas the <service> segment is a cocoa-facing identity concern with no analysis blocked behind it.

    No design conflict between the two. #92 changes the id suffix (a <anon@L:C> segment contributed under the enclosing callable); this issue changes the id prefix. Orthogonal productions, so whichever merges second rebases without a semantic collision. Both remain provisional pending roadmap candidate 4 (can:// grammar conformance, collision group A).

    Spec for #92: docs/design/specs/anonymous-callable-materialization.md

  2. rahlk commented on Aug 20, 2026

    @rahlk
    ContributorAuthor

    Won't fix — the <app> segment stays. Closed in lockstep with codellm-devkit/codeanalyzer-python#123 and the parent epic codellm-devkit/.github#39; codeanalyzer-python is the reference implementation for the identity grammar and it is keeping can://<lang>/<app>/….

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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