Skip to content

Repo impact map#33

Draft
mattford63 wants to merge 13 commits into
mainfrom
repo-impact-map
Draft

Repo impact map#33
mattford63 wants to merge 13 commits into
mainfrom
repo-impact-map

Conversation

@mattford63
Copy link
Copy Markdown

Add the capability to use an impact map with Allium. The skills require you to say "use map" in order to invoke it otherwise it produces normal Allium output.

mattford63 and others added 13 commits May 7, 2026 22:04
Introduces allium:impact, a narrow skill that builds and queries a
bidirectional JSON map linking spec constructs to implementation symbols
via the built-in LSP tool. Python ships as the first language adapter
(pyright-lsp); additional languages are added by dropping an adapter
file under skills/impact/adapters/ -- no change to the core pipeline or
schema.

Wires weed, distill, propagate and tend to consult the map before
falling back to grep-based correlation. All callers degrade gracefully
when no adapter matches or the LSP is unavailable, so the map is an
accuracy/consistency win rather than a prerequisite.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Re-runs against a real Python codebase showed the impact map was pulling
weed toward structural findings (fields, types, renames) at the expense
of behavioural ones (does the code actually emit the warning this rule
promises?). The first fix split "How you work" into structural and
behavioural passes; the second recognised that @guidance and @Guarantee
live on surfaces, not rules, and extended the behavioural pass to
iterate spec:Surface.* and spec:Invariant.* links alongside spec:Rule.*

After both edits, weed recovered 6/6 of the behavioural findings the
no-map baseline caught, plus produced surface-obligation tick-lists and
contract-level per-invariant reads that neither run could produce
before.

Also adds one line to the impact-map reference's "Reading the map"
contract: the map points consumers at code, it does not replace
reading it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The adapter named `pyright-lsp` as its LSP plugin dependency but didn't
say how to get it. Adds uv tool / uv pip install commands for the
pyright binary and the /plugin marketplace steps for the Claude Code
plugin, plus /reload-plugins as the no-restart path.

Also tidies pre-existing MD032 lint warnings in §5 (blank lines around
bullet lists under bold framework headings).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Empirical testing against a real Python project with pyright installed
on PATH showed Claude Code's LSP tool runs pyright in single-file mode:
documentSymbol and hover work, workspaceSymbol returns empty, and
cross-file findReferences / goToDefinition don't resolve project-internal
imports. The impact skill was designed assuming workspace-wide symbol
search via LSP workspaceSymbol, which is not available.

Rewrites the Build pipeline's step 3 to use Glob + per-file
documentSymbol for candidate discovery, with workspaceSymbol treated as
an optional additional source rather than the primary one. Surface
mapping now uses Grep + documentSymbol instead of workspaceSymbol +
findReferences.

Adds a fourth degraded-exit reason tag (lsp-single-file-mode), clarifies
the other three with required details strings, and explicitly instructs
callers to quote the reason and details verbatim rather than paraphrase
— the prior paraphrase-as-diagnosis pattern turned "Executable not found
in $PATH" into "workspaceSymbol doesn't accept query strings" in a weed
report footer, which was misleading.

The Python adapter's install note now makes explicit that uv pip install
into a project venv does not put pyright-langserver on the global PATH
that Claude Code's LSP tool inspects; uv tool install is required.
Added a "which pyright-langserver" verification step.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two related tightenings to weed's §How you work, both driven by
empirical regressions observed in runs against a real Python project
with a working impact map.

Run 4 showed that a dense impact map can crowd out behavioural
coverage: weed visited 2 of 9 specs and called the report done. Adds a
testable coverage constraint: count the specs in the map, count the
specs mentioned in the report, the two numbers must match. Adds a
per-spec budget rule: behavioural pass first, structural/orphan
findings collected in a batch at the end, so structural signal
doesn't exhaust context before later specs get visited.

Run 5 confirmed 9/9 coverage but showed that surface-level `@guidance`
and `@guarantee` narrative findings were still getting lost (streaming
guidance and FK target-table guarantee missed) — the behavioural pass's
sub-bullets were present but not producing structured output, so
surfaces were being compressed into one-line summaries. Adds a required
output format: every visited `spec:Surface.*` MUST appear as a tick-list
sub-section with one row per obligation, each tagged ✓/✗/⚠ with a
file:line citation. All-✓ surfaces still belong in the report as
positive alignment evidence. Includes a worked example showing exactly
the target output shape.

Run 6 (post-edit) achieved 9/9 coverage and 5/6 behavioural recovery —
both previously missed narrative findings returned, plus new signal
only the tick-list format could produce (exposed-but-not-rendered ✗
rows, undeclared state-graph transitions, all-✓ positive-evidence
rows). The remaining miss (`batch_size` hardcoded) is a separate
failure class — declared config values not referenced by any rule —
not addressed by these edits.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two follow-ups after run 6:

The surface tick-list format required every visited surface to emit
every obligation (✓/✗/⚠). That made the report heavy — surfaces with
no issues still produced long subsections of positive evidence. The
internal walk stays exhaustive (still load-bearing for @guidance /
@Guarantee catches), but output is now filtered: only ✗ and ⚠ rows
are emitted, and a surface with no issues produces no subsection.

Run 6 caught 5/6 of the behavioural baseline — the missing finding was
`config.batch_size` declared in the spec, hardcoded `BATCH_SIZE = 200`
in code, with no rule referencing the config value so the rule-level
"each referenced config value" sub-check never fired. Adds a
per-spec-config pass: enumerate every declared config value and check
both (a) at least one rule references it by qualified name, and
(b) code reads from the config layer using that name. Catches values
no rule happens to mention.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds skills/impact/adapters/java.md covering jdtls-lsp with JDK 17+.
Name-variant generator handles Java's layered-architecture conventions
(<Name>Service, <Name>Repository, <Name>Controller, <Name>Impl,
<Name>Dto, <Name>Factory, I<Name> interface prefix) plus CQRS-style
handlers (<VerbPhrase>Command, handle<VerbPhrase>).

Surface entry-points cover Spring Boot (@RestController, @GetMapping
etc.), JAX-RS (@path, @get), Micronaut, Quarkus, Servlet API, gRPC,
and the integration patterns Spring/Micronaut projects actually use
(@KafkaListener, @RabbitListener, @JmsListener, @scheduled,
@eventlistener, AWS Lambda RequestHandler).

Project-root rule handles Maven multi-module (topmost pom.xml with
packaging=pom wins), Gradle multi-module (settings.gradle* marker),
and excludes the usual generated-sources paths that Lombok, MapStruct
and codegen tools produce.

Install path is more involved than pyright — brew install jdtls on
macOS, AUR on Arch, manual download elsewhere — and a first-call
cost warning is included since JDT.LS indexes the classpath on cold
start.

Registers the adapter in the impact SKILL.md fingerprint table and
the "currently supported" list.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds skills/impact/adapters/typescript.md covering typescript-lsp
(typescript-language-server + tsserver). Name-variant generator handles
camelCase / PascalCase conventions plus React's use<Name> hook prefix,
CQRS suffixes (<VerbPhrase>Command / Handler / UseCase), and common
DTO / schema / props suffixes.

Surface entry-points cover Express / Fastify / Koa / NestJS / Hono for
HTTP APIs, Next.js App Router and Pages Router (both), tRPC
procedures, GraphQL resolvers (Apollo and NestJS), React / Vue /
Svelte / React Native for UI, and the JS-ecosystem integration
patterns (BullMQ, node-cron, kafkajs, NATS, WebSocket, AWS Lambda,
Vercel/Netlify functions, Cloudflare Workers, Temporal workflows).

Project-root rule handles monorepos: npm/pnpm/yarn workspaces, Nx,
Turborepo. Exclusions cover the build outputs (dist, .next, .turbo,
.vercel), test/story files, ambient .d.ts types, and the generated-code
patterns TS codegen produces (graphql-codegen, Prisma, Protobuf).

Notes the tsconfig scope caveat: tsserver degrades on files outside
the nearest tsconfig.json's include/files set, which matters when
picking sentinel files. Registers the adapter in the impact SKILL.md
fingerprint table and currently-supported list.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds skills/impact/adapters/kotlin.md covering kotlin-lsp (JetBrains'
official LSP at github.com/Kotlin/kotlin-lsp, installed via
`brew install JetBrains/utils/kotlin-lsp`). Requires JDK 17+ shared
with the Java adapter when both are loaded.

Name-variant generator handles Kotlin-idiomatic patterns not shared
with Java: companion-object factories (Foo.Companion.create instead
of createFoo), `suspend fun` coroutine handlers, extension functions,
data/sealed classes, and the clean-architecture / Android MVVM
suffixes Kotlin projects use heavily (<Name>UseCase, <Name>ViewModel,
<Name>UiState, <Name>Screen, <Name>Composable).

Surface entry-points cover Ktor (routing DSL, plugin install, WebSocket
blocks), Spring Boot / Micronaut / Quarkus / JAX-RS (reuses the Java
annotations), Android (Activity, Fragment, Hilt @androidentrypoint),
Jetpack Compose (@composable), graphql-kotlin, gRPC Kotlin, and
coroutines-based integration surfaces (Flow collectors, Channel
receivers, Retrofit suspend interfaces, WorkManager workers).

Project-root rule handles Gradle multi-module, Kotlin Multiplatform
source sets (commonMain / jvmMain / androidMain / nativeMain), and
Android buildSrc exclusion. Generated-code exclusions cover Hilt,
Dagger, Room, DataBinding, kapt, KSP output.

Notes three call-hierarchy quirks specific to Kotlin: extension
functions appearing as methods on the receiver type, top-level
functions with no enclosing class, and companion-object members
showing as static-like in the LSP. Plus the Gradle-dependency
prerequisite caveat (./gradlew help must succeed before impact can
map cleanly).

Registers the adapter in the impact SKILL.md fingerprint table and
currently-supported list.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
weed, propagate and distill previously auto-invoked the impact skill at
startup, bending their default flow around the map's existence. Revert
each to its pre-impact behaviour (grep + read correlation) and gate map
use behind explicit user direction ("use the impact map", "in map mode",
"via impact"). Each affected skill grows a "Map mode" appendix listing
per-step overrides, so the default body stays stable and the map's
surface area is one section per skill.

tend keeps its defensive pre-rename orphan-link check (one-shot warning,
not a gate) and now quotes the map's built_at so a stale map is visible.
The impact-map reference doc gains an "Opting in" section and the "When
to rebuild" triggers are reframed as user-initiated.

Addresses TODO item #1.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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