Skip to content

feat(cli): vocabulary --drift-insights (M19c) - #38

Open
jgrodziski wants to merge 5 commits into
feat/m19c-word-readersfrom
feat/m19c-drift-insights
Open

jgrodziski wants to merge 5 commits into
feat/m19c-word-readersfrom
feat/m19c-drift-insights

Conversation

@jgrodziski

Copy link
Copy Markdown
Contributor

Fourth step of milestone M19c in PLAN.md §20 (word cloud / glossary, #6). Stacked on #37 (itself on #36, on #35): review those first. This PR's diff is the five commits after #37.

codegraph vocabulary --drift-insights compares the word classes the list assigns with the concerns a model gave the same words in explain. It opens the insights store beside the model. The insights command opens the store alone and cannot do this, because only the model says which class a word takes in a given entity.

The report

  • Technical by the list, judged domain: the words the technical list calls technical that a model called domain somewhere (service in CustomerServiceTicket).
  • Domain by the list, judged technical: candidates for the technical list, or homonyms (order in sortOrder).

Each word is listed with how often each concern was judged. Under it come the judgements its class contradicts, most confident first: confidence, sense, and the identifiers the word is in, in which entity. The text shows five per word and says how many more there are; --json lists every one. Words with the most judgements against come first, and --top N cuts each list (default 40).

With --drift FILE, the business terms are set against both. Each word shows the classes the corpus says it under and the model's concerns, plus why it drifts: list (the list doesn't call it domain), model (a model judged it technical somewhere), or both.

technical by the list, judged domain: 1 of 2 technical words, the most judgements against first
  service  domain 1
    0.60  "after-sales care"  OrderService in java:com.acme.order/OrderService

domain by the list, judged technical: 2 of 4 domain words, the most judgements against first
  trail  technical 2
    0.70  "an audit log"         trail in java:com.acme.order.adapter/LedgerAdapter
    0.65  "a change log"         trail in java:com.acme.order/Order
  order  domain 2 · technical 1
    0.40  "the argument's type"  order in java:com.acme.order/OrderService.bill(com.acme.order.Order)

business terms against both: 2 of 3 drift, a word the list or a model does not call domain

  TERM           WORD     LIST       MODEL                   DRIFT
  Order Line     order    domain     domain 2 · technical 1  model
                 line     domain     not judged
  Service Level  service  technical  domain 1                list
                 level    not said   not judged
  Ledger         ledger   domain     domain 2

(These judgements come from a store built by hand over the Java fixture's ids, not from a model run.)

The code

  • @codegraph/insights: wordHits() with no word returns every entry, matching glossaryEntries(word?). The adapter already had the statement, for the lone-surrogate scan.
  • @codegraph/vocabulary, concern-drift.ts: concernDrift(graph, judgements, { view, technical }) and businessJudged(artifact, terms, drift). Pure computation, with properties for conservation and order independence.
  • CLI: --drift-insights and --insights FILE (the flag name serve uses). The store opener moves from the insights command to insights-paths.ts, and both commands use it.

Worth a look in review:

  • Neither package imports the other. The vocabulary package takes WordJudgements in its own shape and restates the three concerns (JUDGED_CONCERNS); a CLI test pins them equal to the insights block's.
  • The class is per entity, not per word. Each judgement's word is classed as buildVocabulary would class it in that entity's language, under the list in effect (--technical included). In a mixed corpus one word can be two rows: select is domain in Java and keyword in Go.
  • A judgement never sets the exit code. It is an inference. --drift keeps its own exit 3 for a term the corpus never says; said is the corpus-level drift's answer, pinned by a test.
  • Five per word in text. The first version printed every judgement. On a Broadleaf-scale store that came to 6,868 lines, each padded to the longest operation id (~600 characters). The entity now comes last and unpadded, and each word shows its five most confident judgements against, plus "… and N more (--json lists every one)". The cap is a fixed number, not a flag.
  • What is left out is counted, on stderr: records of ids the model no longer has (explained against another version of it), records the view drops, and prompt-1 records.
  • --scope, --level, --class and --svg with --drift-insights, and --insights without it, are usage errors. --json is report: "drift-insights" within codegraph.vocabularyReport/1.

Docs

  • docs/cli.md: the synopsis and the flag.
  • docs/insights.md: the third reader and wordHits(word?).
  • Website: the vocabulary page (two options, an "Against the model" section, exit codes, the example above) and the exit-codes page.
  • PLAN §20.3: an "as built" note. §20.4 lists --drift-insights as in.

Verification

  • Every package except the website builds. The website fails on the untouched base too: snap Hugo 0.168's unknown output format "llms" (pnpm -r build fails on a fresh clone: unknown output format "llms" for kind "home" #23). Typecheck is green, eslint is clean on every changed file, and pnpm run gen:schemas leaves schemas/ unchanged.
  • Tests:
    • vocabulary 345 (13 new: hand cases on a toy corpus, a per-language class, the list given, and a 200-run property for conservation and order independence);
    • cli 1,029 (15 new: both lists, the cut, --top, an empty store, --technical, --drift against both, JSON, the default store beside the model left byte-identical, a missing store, the concern pin, the flag refusals; and two usage errors through the real process, each checked for exit 2 and for not crashing);
    • insights 152 (the projection property now covers wordHits());
    • core 544, viz 143, navigator-ui 105, city 94, extractor-typescript 66, scm 56, navigator 40, llm 34.
    • analyzer 614 of 614 when run alone. Under pnpm -r test on this machine, its corpus-scale test (scale.test.ts, 1.3 s alone) exceeded its 5 s timeout twice while the CLI suite ran in parallel. Nothing in this PR touches the analyzer.
  • Deliberate mutations. I broke the code 26 times, one change at a time, across the package, the store and the CLI. All 26 were caught. Separately, one of my own tests turned out to pass by accident: its confidences descended in the same order as its ids. It now checks the confidence order for real.
  • Scale. I built a store over Broadleaf's own ids: 29,098 records, the words definitionSpeller asks plus parameters and attributes, 109,208 entries, 12% judged against the list. On an x86-64 Linux box the command takes 4.1 s end to end, against 3.2 s for the plain report, at the same peak memory (about 0.5 GB). It writes 572 lines.
  • The single executable. ./build.sh --ts --sea passes its smoke checks.

Still owed for M19c:

  • /glossary.json, with the Vocabulary tab and Navigate panel entries.
  • docs/vocabulary.md and the README.
  • The real Broadleaf side-car checks, the --word order timing, and this report on a re-explained Broadleaf store.
  • A live run on the Java fixture, and the per-word cost measured from it.

Part of #6.

🤖 Generated with Claude Code

https://claude.ai/code/session_01PKCVgyop39vhNa45r7zM8w

jgrodziski and others added 5 commits October 28, 2026 18:24
wordHits() with no word returns every entry, in side-car order then
block order, as glossaryEntries() does: what vocabulary --drift-insights
compares. The adapter already had the statement, for the lone-surrogate
scan. The projection property now checks it for any side-car.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PKCVgyop39vhNa45r7zM8w
concernDrift sets each word a model defined beside the class the list
gives it in that entity's language: the technical words judged domain
somewhere, the domain words judged technical, with the judgements
against, surest first. businessJudged sets a glossary's terms against
both. The judgements come in this package's own shape; it imports
nothing from @codegraph/insights.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PKCVgyop39vhNa45r7zM8w
Reads the insights store beside the first model (--insights FILE names
another) and prints the two lists, five judgements per word (--json:
all); with --drift, the business terms against both. A judgement never
sets the exit code; --drift keeps its exit 3. The store opener moves to
insights-paths.ts, shared with the insights command.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PKCVgyop39vhNa45r7zM8w
cli.md, insights.md (a third reader, beside the model), and the
website's vocabulary and exit-code pages.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PKCVgyop39vhNa45r7zM8w
PLAN 20.3: the decisions and the Broadleaf-scale measurement; 20.4: the
reader is in.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PKCVgyop39vhNa45r7zM8w
@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
codegraph 79e8d19 Commit Preview URL

Branch Preview URL
Oct 28 2026, 06:26 PM

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