Skip to content

docs(spec): <app> becomes the outermost can:// segment; the root gets an id - #68

Open
rahlk wants to merge 2 commits into
mainfrom
docs/can-uri-app-outermost-spec
Open

docs(spec): <app> becomes the outermost can:// segment; the root gets an id#68
rahlk wants to merge 2 commits into
mainfrom
docs/can-uri-app-outermost-spec

Conversation

@rahlk

@rahlk rahlk commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Answers two things surfaced while releasing codeanalyzer-java 3.1.x: a multi-service application is queryable but not addressable, and the graph's application root carries no id at all.

A — the deployment unit moves outermost

before   can://<lang>/<app>/<file>/<type>/<signature>
after    can://<app>/<lang>/<file>/<type>/<signature>

With <lang> outermost, one unit written in two languages fragments into can://python/… and can://typescript/… with nothing joining them.

B — the application root gets its id

analysis.json already emits application.id = can://java/daytrader8. The Neo4j projection drops it: :JApplication merges on name, the raw --app-name string, and has no id property. codeanalyzer-python's :PyApplication is identical. Three live defects follow — two services sharing a name silently merge into one node; the root cannot be reached by id; and it is the one node the prefix-scoped destructive statements structurally cannot see, because RowBuilder attaches the :JCanNode index anchor only to values starting with can://.

Supersedes the Aug 7 spec, and why

can-uri-service-segment.md proposed the same positional change. That argument survives; two others did not.

Repo Aug 7 spec said Today
codeanalyzer-java "nothing — still v1, emits no can:// ids at all" v2 emitter, 180 refs, released 3.1.1
python-sdk "nothing — pre-v2, zero can:// references" 372 refs on release/2.0

Its D3 shipped a breaking id change as MINOR 2.1.0, justified by "no consumer holds a can:// id today." Every clause of that is now false. The window it called "the cheapest it will ever be" closed while it sat in draft.

It also could not have known about 2026-09-02-prune-scope-on-can-id-prefix.md: destructive statements are now scoped on the id prefix, so the outermost segment is load-bearing for a safety mechanism, not just identity.

<app>, not <service>

A monolith has no service. That name would force a category error on most projects. The concept the positional argument needs is the unit built and deployed together — one for a monolith, one per service — and CLDK already calls that app. Keeping it deletes the predecessor's --app-name--service rename entirely, so this version is strictly cheaper.

Two things that get better, not just fixed

  • The pseudo-segments regularise. The artifact scheme is today can://artifact/<app>/<path> — a third outermost shape, neither lang nor app. It becomes can://<app>/artifact/<path>. One rule instead of three.
  • The delete scope becomes expressible. Today an app analyzed by two analyzers has two unrelated prefixes, so a cross-language delete scope cannot be written. After this, can://<app>/ covers every node of that app in every language — what the scoping spec wanted and could not have.

Proposes carrying #50

The graph contract is held at 2.0.0 pending "a coordinated re-baseline across all three analyzers" (#50), which has had no forcing function. This is one: breaking, touches every analyzer, must land in lockstep or the grammar fragments. So both schema_version and the graph contract move to 3.0.0 together.

Not part of codeanalyzer-java 3.1.1

3.1.1 is a patch carrying an opt-in CLI flag. Shipping a MAJOR contract break under it would be dishonest versioning.

Open for review

Decomposition (§6) is proposed, not decided — six children across the keystone, three analyzers, the SDK and docs, with a hard lockstep requirement. Migration (§5) is the sharp edge: L1 caches, persisted analysis.json and existing Neo4j graphs are all invalidated, and old graphs cannot be cleaned by the new scoped delete because the prefix differs.

… an id

Two identity defects, designed together because the second is only half-useful
without the first and they share one migration.

The deployment unit moves outermost — `can://<app>/<lang>/<file>/...` — so a unit
written in two languages stops fragmenting into unrelated id roots. And the
application root finally carries the `can://` id it already emits in
`analysis.json`: the Neo4j projection drops it today, merging `:JApplication` on
free-text `--app-name`, so two services sharing a name silently unify, the root
is unaddressable by id, and it is the one node the prefix-scoped destructive
statements structurally cannot reach.

Supersedes can-uri-service-segment.md, whose positional argument survives but
whose cost table and version decision did not: it recorded codeanalyzer-java and
python-sdk as unaffected when they now hold 180 and 372 `can://` references, and
justified a MINOR bump for a breaking id change on the grounds that no consumer
held an id.

Names the segment `<app>`, not `<service>` — a monolith has no service, and that
also deletes the predecessor's `--app-name` → `--service` rename entirely.

Proposes this change carry the coordinated re-baseline #50 has been waiting for:
schema_version and the graph contract both to 3.0.0, in lockstep across every
analyzer. #50 has had no forcing function; a breaking change that must land
everywhere at once is one.

Explicitly not part of codeanalyzer-java 3.1.1, which is a patch carrying an
opt-in CLI flag.
The maintainer's call, with the costs on the table: the grammar fragments until
the sibling analyzers follow, a breaking id change ships under a PATCH number,
and python-sdk's pin bump becomes a fixture migration rather than a version edit.

Recorded rather than re-argued. The paragraph that said this must not ride 3.1.1
is marked as deliberately overridden, not resolved — so a later reader sees the
objection and the override, not a spec that never raised it.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant