Skip to content

R380 In Review -> Done: approve @reference join-subquery filter conditions - #503

Closed
alf wants to merge 3438 commits into
mainfrom
claude/graphitron-rewrite-ff-uc9avo
Closed

R380 In Review -> Done: approve @reference join-subquery filter conditions#503
alf wants to merge 3438 commits into
mainfrom
claude/graphitron-rewrite-ff-uc9avo

Conversation

@alf

@alf alf commented Jul 1, 2026

Copy link
Copy Markdown
Collaborator

Independent-session review (reviewer session != implementer session
session_01Xhs2BcPVDn18MRfAngVovm). Verdict: approve.

  • Spec -> diff alignment: both filter surfaces fixed (input-object filter
    fields + direct scalar arguments) via the shared RemoteColumnPredicate
    model + TypeConditionsGenerator EXISTS emitter spine; Design A honored
    (EXISTS inside the generated method, call sites unchanged). All v1
    deferrals (ConditionJoin rejection, composite-emitter-only, @splitQuery
    no-op) recorded in the implementation commit as the spec required.
  • Architecture: sealed wrapper keeps local-vs-remote off the
    operator/value-arity ColumnPredicate axis; local emitter output is
    byte-for-byte unchanged; the load-bearing Direct-vs-NodeIdDecodeKeys
    discriminator is implemented and documented; helpers reused
    (resolveColumnForReference, parsePath, JoinPathEmitter, buildInnerSelect
    shape); validator mirrors at both sites.
  • Tests: pipeline tier asserts model-level (both surfaces, single/multi-hop,
    {key:}/{table:}, list In, nodeId-stays-local guard, ConditionJoin
    rejection); execution tier proves real rows incl. the motivating bug and
    absent-arg-returns-all.
  • Build: full reactor green under -Plocal-db.

Carried debt (non-blocking): the new TypeConditionsGeneratorTest cases pin
the EXISTS body with code().toString() contains(...) assertions, matching
that file's pre-existing convention (R375/R79/R50) but contrary to the
"no code-string assertions on generated method bodies" principle. Behavior
is independently proven at the execution + compilation tiers, so the cases
are redundant rather than wrong. Whole-file migration filed as R387
(Backlog).

Approve actions: spec file deleted, changelog entry added (R380 @ 745c0cd),
README regenerated, R387 Backlog item filed.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com
Claude-Session: https://claude.ai/code/session_01Cbz49UaK7pjQ4ap11ptvVW

claude added 30 commits July 1, 2026 16:18
…tions

Independent-session review (reviewer session != implementer session
session_01Xhs2BcPVDn18MRfAngVovm). Verdict: approve.

- Spec -> diff alignment: both filter surfaces fixed (input-object filter
  fields + direct scalar arguments) via the shared RemoteColumnPredicate
  model + TypeConditionsGenerator EXISTS emitter spine; Design A honored
  (EXISTS inside the generated method, call sites unchanged). All v1
  deferrals (ConditionJoin rejection, composite-emitter-only, @splitQuery
  no-op) recorded in the implementation commit as the spec required.
- Architecture: sealed wrapper keeps local-vs-remote off the
  operator/value-arity ColumnPredicate axis; local emitter output is
  byte-for-byte unchanged; the load-bearing Direct-vs-NodeIdDecodeKeys
  discriminator is implemented and documented; helpers reused
  (resolveColumnForReference, parsePath, JoinPathEmitter, buildInnerSelect
  shape); validator mirrors at both sites.
- Tests: pipeline tier asserts model-level (both surfaces, single/multi-hop,
  {key:}/{table:}, list In, nodeId-stays-local guard, ConditionJoin
  rejection); execution tier proves real rows incl. the motivating bug and
  absent-arg-returns-all.
- Build: full reactor green under -Plocal-db.

Carried debt (non-blocking): the new TypeConditionsGeneratorTest cases pin
the EXISTS body with code().toString() contains(...) assertions, matching
that file's pre-existing convention (R375/R79/R50) but contrary to the
"no code-string assertions on generated method bodies" principle. Behavior
is independently proven at the execution + compilation tiers, so the cases
are redundant rather than wrong. Whole-file migration filed as R387
(Backlog).

Approve actions: spec file deleted, changelog entry added (R380 @ 745c0cd),
README regenerated, R387 Backlog item filed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Cbz49UaK7pjQ4ap11ptvVW
…V in DevMojoTest fork)

Independent In Review gate on R385 (docs.search). The slice is mostly sound,
but the build is red: DevMojo.bindServer unconditionally starts the real ONNX
embedder warm, so DevMojoTest's execute()-driven bind-failure test loads the
bge model on a daemon thread inside the maven-plugin surefire fork, which
SIGSEGVs libonnxruntime.so and aborts the build (reproduced twice). The MCP
bind-failure catch arm also leaks the just-started warms (only server.close()
runs, not warm cleanup). Feedback captured in the spec body; status returned
to Ready for the next pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EBUiBFG685scFBerUDsMem
…nery

The faceted-search spec was written against a connection pipeline that has
since been refactored away (ConnectionSynthesis -> ConnectionPromoter,
field-first synthesis) and predates R316's (source, operation, target) model
and R333's data-model framing. Phases 2-4 referenced retired seams.

Rewrite Current State, Desired End State, Key Discoveries, and Phases 2-4
onto the current architecture, choosing the contained route:

- FacetSpec rides GraphitronType.ConnectionType (per-type), not the slimmed
  FieldWrapper.Connection (per-site); new FacetsType / FacetValueType arms.
- ConnectionPromoter grows the facet arm; facet types ride additionalType.
- The connection fetcher carries a facet plan on ConnectionResult and a new
  ConnectionHelper.facets resolver issues the UNION ALL aggregate, exactly
  as totalCount carries (table, condition) and runs its own count today.
- Operation.Facet stays unpopulated behind the ConnectionType quarantine;
  R314 folds the contained emit into general dispatch, as it will for
  Operation.Count. Adds a Contained approach section making this explicit.

Phase 1 (SQL spike), Phase 5 (execution tests), Phase 6 (hierarchical), and
the SQL-strategy / design-decision sections are unchanged in substance.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017WnHmQSh6TihaiKV5NvvEz
Flesh out R99 with an implementation plan, test plan, and user-doc
draft, and record the walk-up-vs-JAR-scanning design decision.

Chosen approach (Option A): when graphitron:dev runs from inside a
single-module reactor, walk up to the parent pom, parse <modules> in
document order, and widen both the classpath scan and the source walk
over the same sibling set so R351/R369 scan/walk parity is preserved.
Rejected Option B (scan dependency JARs) as crossing the scanner's
parse-only boundary and promoting the warned-about scanned-but-unwalked
residue into the common path; consulted principles-architect.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F3ibCAD4z6bQoFMNMkkctP
… unwind

Addresses the two coupled DevMojo defects the In Review gate failed on; the build
was red because DevMojoTest paid a real BgeEmbedder ONNX load that SIGSEGV'd the
surefire fork.

1. Seam for the warms. DevMojo.bindServer no longer constructs DocsRag.embedderWarm()
   / docsWarm() directly; it goes through package-private warm factories defaulting
   to the DocsRag factories. DevMojoTest swaps in ONNX-free fakes (and mojoFor
   defaults to structured-only null warms), so the fast suite never loads the real
   ONNX model. Mirrors the GraphitronMcpServer structured-only / injected-warm seam.

2. Warm cleanup on the bind-failure path. The MCP-bind-failure catch arm previously
   closed only the LSP socket; warm cleanup lived in cleanup() (the normal Ctrl+C
   stop), which the exception path never reaches. A failed bind returns into a
   still-live JVM, so a warm left mid-load kept running on its daemon thread after
   execute() returned (the SIGSEGV's proximate cause). awaitAndCloseWarms() now joins
   each warm to its terminal state and closes the warmed docs store before rethrowing.
   DevMojoTest asserts the failed bind leaves no live warm and freed the docs store,
   paralleling the existing LSP-socket-closed assertion.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TsvurVyFkyHFFtRis6C9pt
…d-failure cleanup)

Records the two gate-blocking DevMojo defects as fixed at bba3251 and moves the
item back to In Review; mvn install -Plocal-db is green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TsvurVyFkyHFFtRis6C9pt
… Phase 2/3, generated facet predicates

Folds in the three Spec-review findings:

1. *FacetValue.value nullability is derived from the annotated filter
   field's element type (same scalar AND same nullability), resolving the
   non-null-vs-nullable contradiction. Non-null element keeps value non-null
   and scrubs its NULL group (IS NOT NULL); nullable element preserves the
   NULL bucket and round-trips. FacetSpec gains a valueNullable flag;
   FacetNaming keys on (scalar, nullability) to avoid type-name collisions.

2. FacetSpec record + ConnectionType.facets() land with Phase 2 in a single
   commit, so the "each phase build-green" invariant holds; Phase 3 owns
   only the rejection/validation logic.

3. Per-facet filter-minus-self predicates are generated as QueryConditions
   fragments (<field>Facet_<g>Condition), not reconstructed inline in the
   fetcher from raw env values. Keeps value binding inside the typed
   adapter boundary (Column value binding convention) and the resolver only
   composes pre-built Condition objects.

Status stays Spec; reviewer for the next Spec -> Ready pass must be a
different session.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CpGU7GXxCKKDwpfkgGJahj
…abel

Spec-review revision (status stays Spec). Two findings from the
Spec -> Ready pass:

1. The sibling-widening adds scan + walk roots over a sibling set, but
   unwalkedScannedModules() (the R369 scan/walk parity WARN) is a fourth
   reader of the reactor set that the dir-based helper cannot feed.
   R369 pins that diagnostic and resolveCompileSourceRoots() to one
   project set "so resolver and diagnostic cannot drift", so the spec
   must state the decision rather than leave it implicit. Added a bullet:
   the WARN stays reactor-scoped by design, justified by standard-layout
   sibling parity holding by construction (target/classes implies a
   co-located src/main/java); the only scanned-but-unwalked sibling case
   is a non-standard <build><sourceDirectory>, already out of scope, and
   is documented residue analogous to R369's published-JAR residue. The
   scan side (completion, @service/@condition resolution, unknown-class
   diagnostics) is unaffected in every case.

2. Re-labelled the primary test from "Pipeline-tier" to "Mojo-tier": it
   simulates a Maven session and asserts classpath/source assembly, the
   surface R351/R369 tested via AbstractRewriteMojoTest/DevMojoTest, not
   the SDL -> TypeSpec pipeline tier rewrite-design-principles defines.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015X8gnp6RRyzLbEj5DJQUDR
Independent-session In Review -> Done review of R385 (MCP docs.search:
build-time .adoc chunking + pre-embedded bundled index, async-loaded
semantic retrieval over the documentation, R118 slice 9).

Approved: spec->diff alignment complete (chunker, build-time generator,
bundle-tuples divergence, dimension guard, deep link, server + DevMojo
warm wiring); the dependency quarantine holds (Base64 payload avoids
widening the RAG dep surface); all named test tiers present with
structured-content assertions (no code-string assertions on generated
bodies). The rework landed both gate-blocking DevMojo defects in the
reviewer's prescribed shape: the package-private warm-factory seam keeps
the real BgeEmbedder ONNX load out of the fast suite, and
awaitAndCloseWarms() joins + closes the warms on the bind-failure unwind,
with parallel DevMojoTest assertions. Full reactor green under -Plocal-db,
no SIGSEGV.

Delete the spec file; record the milestone in changelog.md (landing
b0afcf8/6cb322a/d751110, rework df7525a->ee71c81). README regenerated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011CQv6STcAMjrUZBE3YEiGw
Independent Spec -> Ready review of R13 (faceted search on @asConnection).
Plan is architecturally sound against the rewrite-design-principles, code
anchors verify, test coverage spans the relevant tiers, and the open
decisions left to the implementer are bounded with stated trade-offs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RmCwcRM6ofXU42WXytvvgB
Add the second semantic MCP tool, catalog.search: fuzzy discovery over the
database catalog by table/column names and comments, so an agent can find a
table it can only describe in natural language and hand the schema-qualified
SQL id straight to catalog.describe.

- CatalogDescriptors: pure descriptor composer (raw SQL token + normalized
  words; comment-aware degradation) and snake_case/camelCase/acronym name
  splitter (R118 OQ3), plus the corpus hash computed over the exact strings
  embedded so the hashed and embedded artifacts cannot drift.
- CatalogSearchIndex: warm-managed, self-observing index mirroring R374's
  Cache. Two gates (reference identity, content hash) over the live
  catalogFacts; a changed hash re-embeds on an AsyncWarm daemon, persisting a
  content-hash-keyed Lucene FSDirectory under RagConfig.cacheDir with an
  embedder-identity manifest that closes the cross-model load trap, and reaps
  stale sibling dirs keeping current + one prior.
- RagConfig: dev-environment cache-dir glue, room to grow.
- GraphitronMcpServer: widen the constructor with a RagConfig overload (eager
  warm) and a back-compat overload (temp dir, cold warm, no ONNX); register
  catalog.search returning ranked {id, schema, name, comment?, score} or the
  WarmState degradation while warming/failed.
- DevMojo: supply ${project.build.directory}/graphitron-mcp-rag.
- Tests across the unit / handler / ONNX tiers; getting-started.adoc note.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H4uSAsvUiDiSXinnvthWZC
…vMojo line cites

Independent Spec -> Ready review. Plan is architecturally sound: widens at the
shared reactorProjects()/collectExistingDirs seam to preserve the R351/R369
scan/walk parity invariant, and the Option A vs B rejection is principle-grounded
(parse-only ClasspathScanner boundary, parity residue). Test plan asserts both
parity sides at the correct mojo tier; scope/non-goals are honest. Corrected the
two DevMojo line citations that drifted ~17 lines after R385's DevMojo work landed
(startup line ~153->~170; WARN render DevMojo.java:171->180).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CgDUATqTYaXTL483otUqRQ
…e failure

Discriminator column emitted unqualified in cross-table join ON-clause and
SELECT (ambiguous SQL when a participant's composite FK re-declares the
discriminator column), plus a discriminator-column field carrying @reference
misclassified as a cross-table participant field (fetcher reads a join-only
alias the interface-level projection never produces). Captures the two defects
and the missing execution fixture.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FFykVoanhsujZWYC4kVhPL
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FFykVoanhsujZWYC4kVhPL
The @table(subjekt)+@reference contortion is forced, not chosen: $fields
projects each participant against the shared interface table (param typed to
the participant's own jOOQ table class), so a participant on its own detail
table won't compile. Captures why, narrows the defect-2 validation guard to
base-table-column overlap (navn's @reference stays valid), and flags
first-class discriminated joined-table inheritance as a separate larger item.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FFykVoanhsujZWYC4kVhPL
R388 Spec: three-part fix — (A) qualify the discriminator column to the base
table at all three emission sites in TypeFetcherGenerator (SELECT projection,
LEFT JOIN ON-clause, WHERE IN filter); (B) reject a discriminator/base-column
field carrying @reference at validation, with the predicate computed once in
the classifier and mirrored by the validator; (C) add the load-bearing
execution fixture (composite FK re-declaring the discriminator column) plus a
validation regression test. Reviewed by principles-architect.

R389 (Backlog): first-class discriminated joined-table inheritance, the deeper
gap that removes the need for the @table(base)+@reference workaround.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FFykVoanhsujZWYC4kVhPL
Spec → Ready guard satisfied: reviewer session ≠ last spec committer
(disqualified session_01FFykVoanhsujZWYC4kVhPL). Verified all cited
code/test references are live (TypeFetcherGenerator emission sites,
TypeBuilder.extractCrossTableFields self-join skip, validateTableInterfaceType,
GraphQLQueryTest FilmContent.rating coverage gap). Plan is sound: defect-1
qualification fix correctly identified as having no compile-tier guard
(execution fixture load-bearing), defect-2 validator gate mandatory per
validator-mirrors-classifier. One minor note for the implementer: the
Workstream-B "carry the fact" anti-drift goal is best met with a shared
build-time predicate helper, since the classifier-skip discards the
contradiction field rather than carrying it on the model.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KLL9hsbdAC1pbnv4UzhqkH
…with R316

The 2026-05-20 draft layered tenant routing by widening the sealed
GraphitronContext (getTenantId(env)/getDslContext(T)) and stashing the
routing function under a marker key. Its own Q4 flagged this as a likely
revision target; a 2026-06-26 principles pass confirmed two of the three
findings (thunk method, trans-axis null return) and cleared the third
(byTenant rides the same typed-key mechanism R190 uses for defaultDsl, so
it is not a wire-format leak).

Resolved direction, reconciled with R316's (source, operation, target)
model:
- GraphitronContext stays at R190's three-method shape; no widening.
- New per-field sealed TenantIdSource overlay (sibling to source/operation/
  target, computed only when <tenantColumn> is configured) with a
  structural RequestScoped/SourceScoped scope split so the loader-name
  prefix consumer accepts only RequestScoped|Untenanted at compile time.
- byTenant travels on GraphQLContext like defaultDsl; dispatch reads it
  inline. Five DataLoader sites and HandleMethodBody grouping consume the
  classified axis, not a method.
- Adds a tenantColumnAbsentOnParent rejection for the SourceScoped axis
  alongside the three directive rejections.

Also: fixed the Motivation's getContextArgument signature (R190 dropped the
Class<T> param), re-anchored drifted code sites on symbols, corrected the
R85 cross-reference (now independent, no method widening), and reframed
Open questions (Q4 resolved; Q3 no longer dissolves; added scope-split and
SourceScoped-carrier forks). Regenerated roadmap README.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MqUb5cYzZpsMBNBQK4HPiW
Two review findings that hold against the reworked spec:
- The "Depends on" prose linked single-tenant-execution-input-factory.md,
  which no longer exists (R190 is Done; its file was deleted). De-linked and
  noted that depends-on: [] is correct for a completed dependency, with the
  record now pointed at changelog.md.
- Re-anchored the five DataLoader loader-name cites on verified current-code
  lines: TypeFetcherGenerator ~:5832 (was unnumbered) and
  MultiTablePolymorphicEmitter ~:1113/~:1182 (the second was wrongly :1201).

The reviewer's other findings (Q4 open, GraphitronContext-widening sections
present) were against the pre-rework spec on trunk; the reworked spec on this
branch already resolved Q4 onto TenantIdSource and deleted those sections.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MqUb5cYzZpsMBNBQK4HPiW
…bled schema

A @table type reachable only through a directive-driven @asConnection carrier
field lost its schema-class emission: generated GraphitronSchema.java named a
<Type>Type class that was never written and javac failed (regression seen on
RC20). Two-level shape from the report: a @splitQuery @asConnection @reference
list whose element type exposes a nested @reference list to a third type; the
nested type's record and fetcher emitted but its schema class did not.

Root cause is in ConnectionPromoter.rebuildAssembledForConnections. Once the
carrier rewrite retypes the bare-list carrier to name its synthesised
Connection, the element type is referenced only through the Connection's
nodes / Edge's node type references. SchemaTransformer rebuilds its type map
from the concretely-traversed graph (type references are leaves), so an element
type reachable in the original schema only through that one carrier, together
with its whole transitive @reference subgraph, was pruned. Surfaces either as a
silent drop (missing <Type>Type schema class) or, when a surviving typeRef still
points at the pruned type, an NPE in GraphQLTypeResolvingVisitor. Because the
element type is never traversed, SchemaTransformer also skips a nested carrier's
own @asConnection rewrite, leaving that field a bare list while its fetcher is
connection-shaped (the report's variant 3 mismatch).

Fix: pin each rewritten carrier's element type as a GraphQLSchema.additionalType
before the transform, so the element and its subgraph stay concretely reachable
and every nested carrier rewrite applies. Adds a pipeline-tier regression test
covering both the nested @reference retention and the nested @asConnection
retype.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01X1TJsBx3285cZcFyy7Fep2
Code, regression test, and root-cause writeup already landed on trunk
(5485578). Moving the item straight to In Review (manual edit; the tool
rejects the Backlog -> In Review jump) so an independent session can run the
In Review -> Done workflow-gate review.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01X1TJsBx3285cZcFyy7Fep2
…or bullet

Spec line 172 cited a `@LoadBearingClassifierCheck` / `@DependsOnClassifierCheck`
annotation pairing "following the R190 / R204 precedent" as the classifier/emitter
no-drift mechanism. Neither annotation exists in the rewrite tree, and there is no
R204 roadmap item; this is the false-precedent the "Documentation names only live
tests/code" principle prohibits. R190's actual no-drift mechanism is a single
cached producer (`ContextArgumentClassifier`'s output on `GraphitronSchema.contextArguments`)
read by both validator and emitter, plus the validator-mirror already described in
the same bullet. Rephrased to that real mechanism.

Spec stays in Spec; this is the only blocker found in the Spec -> Ready review.
The final flip needs a reviewer session different from this one (now last committer).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013uvi6DQGzdXQmE8xZ5tBoc
File a Backlog item for a Graphitron facade convenience that collapses the
buildSchema + GraphQL.newGraphQL boilerplate into Graphitron.newGraphQL()
for the no-extra-wiring default case.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YbXsM6xY7egY65SLS4XgcR
Write the spec body for the Graphitron.newGraphQL() convenience: design
(returns GraphQL.Builder, delegates to single-arg buildSchema, federation-safe),
call-site sweep scoped to load-bearing vs cleanup, and structural-only unit
coverage plus execution/federation assertions (no banned body-string matching).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YbXsM6xY7egY65SLS4XgcR
…etention

Independent-session In Review -> Done review of R390. The fix pins each
rewritten carrier's element type as a GraphQLSchema.additionalType before the
connection rebuild transform, so an element reachable only through the
synthesised Connection's node typeRefs (and its transitive subgraph) stays
concretely reachable instead of being pruned by SchemaTransformer. Verified:

- Spec -> diff alignment: delivers exactly the pinning approach the spec named;
  nothing in scope unshipped, nothing out-of-scope landed.
- Architectural soundness: "pinning direct carrier elements suffices" holds for
  deeper nesting (every carrier at every depth is in the rewrite set, so each
  element is pinned), multiple carriers sharing an element (deduped by name via
  putIfAbsent), and structural SDL-declared connections (no typeRef introduced,
  element stays concretely referenced, so not at risk). carrierElementType
  null-degrades cleanly.
- Test coverage: NestedConnectionElementRetentionPipelineTest present, asserts
  nested @reference retention and nested @asConnection retype on schema
  structure; no code-string assertions on generated bodies. Both cases pass.
- Build green: full reactor passes under mvn install -Plocal-db.

Deleted the spec file; recorded the milestone in changelog.md; regenerated the
roadmap README.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mk7pdF1ah1ZvmimY5PYsD5
…tems + a code straggler

R237 retired the @LoadBearingClassifierCheck / @DependsOnClassifierCheck
annotation pair and swept most references, but a few live ones survived:

- R239 (column-field-parent-table-record-component) and R240
  (tablemethod-return-type-token-threading), the two structural-lift follow-ups
  R237 spawned, still described their origin via the retired annotation keys
  ("candidate keyed `...`", "the annotation `...` retires with R237", "rubrics
  no longer push the annotation pattern"). Rephrased to keep the R237 Phase 2
  origin lineage and the technical substance while dropping the dead
  annotation/key framing; R237 has shipped, so the Phase-1/Phase-4 timing
  preconditions are dropped as satisfied. README roll-up regenerated.
- FieldBuilder.requireDmlDataTableMatchesInputTable javadoc opened with
  "Load-bearing classifier check (R75 Phase 1)"; reworded to describe the
  invariant the method actually validates.

The changelog is deliberately untouched: its references are the accurate
historical record of the annotations' use and their R237 retirement.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013uvi6DQGzdXQmE8xZ5tBoc
…reference-on-base-column

Fixes two runtime defects in the discriminated-interface (@table + @discriminate)
fetcher path, both invisible to compile-time checks and uncaught by any test.

Defect 1 (TypeFetcherGenerator): the discriminator column was emitted as a bare
DSL.field(DSL.name(col)) at all three sites (SELECT projection, LEFT JOIN ON-clause,
WHERE filter). When a participant's FK-target detail table re-declares the
discriminator column via a composite FK, that bare reference is ambiguous and
PostgreSQL rejects the query once the join fires. Now qualified to the base table via
a two-part DSL.name(baseTableSqlName, col) — renders "base"."col" and preserves the
Field<Object> the .eq(String)/.in(String...) predicates need (a table-instance
reference would type as Field<?> and fail to compile). The three helpers thread the
base table's SQL name.

Defect 2 (TypeBuilder.extractCrossTableFields): a participant @reference field whose
resolved column already exists on the interface/base table is a contradiction. Detected
once with the catalog in scope: the field is skipped from the cross-table set
(classifier narrowing) and a build diagnostic is registered, surfaced through the
validator's existing drainBuildDiagnostics as an INVALID_SCHEMA author error with
file:line and a detail-column candidate hint. (The spec called for validator-side
emission, but validateTableInterfaceType has no catalog access; the diagnostic-drain is
the faithful realisation of "resolve once, validator reads rather than recomputes".)
A participant-only @reference field stays valid.

Fixture (Workstream C): jti_subject + jti_app_account + jti_person joined-inheritance
tables in init.sql (detail tables re-declare the discriminator via composite FK), the
corresponding corrected-shape SDL in the example schema, execution-tier regression tests
(GraphQLQueryTest.allSubjects_*), and validation pipeline tests
(DiscriminatorReferenceContradictionPipelineTest). Bumped jooq.codegen.schema.version
to force catalog regeneration. mvn install -Plocal-db green end-to-end.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KLL9hsbdAC1pbnv4UzhqkH
Independent Spec -> Ready review. All cited references verified accurate:
GraphitronFacadeGenerator.generate(...), GraphqlEngine.java:16-17,
GraphQLQueryTest:80-81, FederationBuildSmokeTest (_service { sdl } precedent +
the line-62 single-arg-delegates-to-two-arg proof), the facade unit test at
lines 35-39, and the example README pattern. Design mirrors the newExecutionInput
builder-return convention, keeps buildSchema the single schema producer, honors
the code-string-assertion ban, and pins the one silent-failure risk (federation
wrap) with an execution assertion rather than prose. No material findings.

Reviewer (session_013uvi6DQGzdXQmE8xZ5tBoc) != last spec committer
(session_01YbXsM6xY7egY65SLS4XgcR).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013uvi6DQGzdXQmE8xZ5tBoc
Facets are a best-effort aggregate, not a structural guarantee. Relax
the per-facet fields on the Facets object from [XFacetValue!]! to
[XFacetValue!] (nullable list, non-null elements) and document the
failure semantics: a facet query failure or timeout degrades to null
rather than bubbling through GraphQL non-null propagation to abort the
connection or request. Each per-facet field being nullable also keeps
the wire contract stable for a future split into one query per facet
field that can succeed or fail individually.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RmCwcRM6ofXU42WXytvvgB
claude and others added 26 commits July 1, 2026 16:18
…return

Reworked the first implementation pass (1b6971d) onto current trunk, which now
carries R405's shared read-side re-projection helper. R406 consumes that helper
instead of re-extracting it, per this item's "whichever lands first extracts;
the second consumes" contract (R405 landed first).

A DML @mutation(typeName: INSERT|UPDATE) returning a single-table discriminated
interface (@table @discriminate, implementers pinned by @Discriminator, all
sharing one jOOQ table, e.g. Content over content) was silently mis-accepted and
emitted non-compiling code. The write half is a plain single-@table write; the
fix is entirely on the return half.

- Model: add DmlReturnExpression.DiscriminatedSingle/List carrying the read-side
  discrimination data (interfaceName, discriminatorColumn, knownDiscriminatorValues,
  participants). dmlDomainReturnType / dmlTarget map both to the Record/Table shape,
  like Projected*.
- Classify: buildDmlField (the single DML chokepoint) resolves the return's
  look-ahead verdict once; a TableInterfaceType return builds the Discriminated*
  arm instead of Projected*. No new MutationField leaf.
- Validate: dispatchPerformsReFetch recognises the Discriminated* arms as
  re-fetching, keeping the emitter and requiresReFetch in agreement. DELETE and
  Connection floors already fire for the interface case.
- Emit: emitDiscriminated reuses the PK-only RETURNING transaction verbatim and
  re-projects through R405's buildTableInterfaceReprojection (List.of() for its
  alwaysProject param) keyed by a PK-IN condition off the RETURNING keys. Deleted
  the duplicate buildDiscriminatedReprojection. emitKeysTransaction and the
  composite-safe buildPkKeysCondition stay R406-owned (the DML write half R405 has
  no equivalent of), shared only between emitProjected and emitDiscriminated; they
  do not duplicate R405's records-keyed buildPkInCondition.

Tests: classification + regression + DELETE-floor pins in GraphitronSchemaBuilderTest;
INSERT/UPDATE pipeline shape assertions in FetcherPipelineTest; execution proof in
DmlTableInterfaceReturnExecutionTest (per-__typename routing off the live
discriminator, cross-table rating join, same-table description isolation,
unknown-discriminator write/read asymmetry) plus a ContentInput / createContent /
updateContent sakila fixture. Full reactor green under -Plocal-db.

R406 -> In Review.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MiQszkiLd3mJR6VcaxRV8y
…us spike

Per feedback while in Ready (safe in-place refinements):

- Reframe the motivation: the primary driver for owning compilation is that
  the graphitron:dev MCP server should execute GraphQL queries against the
  generated resolvers in-process (no Quarkus/app server), which needs the
  generated code as loaded, runnable .class. Incremental compile is the
  mechanism that keeps that viable at scale; framework reload is demoted to
  a secondary, framework-scoped benefit.
- State that dev startup generates AND compiles the whole tree, so the
  graphitron-exclusive dir holds a complete runnable image before any edit
  (required for MCP execution; also closes the classpath-shadowing gap for
  consumers who exclude generated-sources).
- Stop crying wolf in the compile-diagnostics taxonomy: add the benign,
  self-resolving third source (transient consumer-ABI inconsistency from a
  mid-refactor consumer surfaced via the classpath watcher); default tone is
  no-defect-asserted.
- Resolve the output-ownership open question with a source-level Quarkus
  spike: quarkus:dev (RuntimeUpdatesProcessor, 3.34.5) watches its own source
  roots / classesPath and recompiles generated sources itself; it does not
  consume an external target/graphitron-classes, and front-loading it is a
  no-op-to-shadowing-hazard. Conclusion documented: do not front-load for
  Quarkus (value routed to MCP execution); the co-run consume benefit survives
  only for Spring DevTools and plain java/IDE runs. First-client doc and
  slice 6 updated accordingly.

Status stays Ready.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XFAKeBjm21AmprZLUs92E7
Split/reference batch fetchers correlate the target table to a
VALUES (idx, parent_key…) derived table whose cells are typed from
ColumnRef.columnClass() (the Java type) instead of the column's jOOQ
DataType. A converter-backed key column (e.g. kode_numerisk_domain =
BIGINT + Long⇄String converter) then renders as varchar, and the join
throws "operator does not exist: <domain> = character varying".

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ning in-hand @service-path sites

Second rework pass. Swaps the two in-hand bestGuess-over-binary-fqClassName sites the
In Review -> Ready review flagged, mirroring the query-side fixes already landed, and
adds a witness for each.

- TypeFetcherGenerator.computeMutationServiceRecordReturnType: collapse the class-backed
  arm to serviceMethodCall().javaReturnType() (the mutation twin of computeServiceRecordReturnType),
  and correct the now-true "Identical policy" javadoc. Compile-witnessed by a nested mutation
  @service record payload (NestedFilmReviewPayload / NestedFilmReviewPayloadHolder.Payload) in
  graphitron-sakila-service/-example: mvn install -Plocal-db emits
  DataFetcherResult<Outcome<NestedFilmReviewPayloadHolder.Payload>> and compiles; reverting the
  swap reproduces the Outer$Nested javac break.

- FieldBuilder.resolveErrorChannel: swap bestGuess(fqClassName) -> ClassName.get(payloadCls)
  (payloadCls is already loaded). Correcting the review's premise: after the R244 Outcome flip,
  root @service outcome fields classify to ErrorChannel.Mapped (new Outcome.ErrorList<>), so no
  developer payload class is emitted on the @service path and the payloadClass ClassName is never
  emitted there (reverting the swap leaves sakila-example output byte-identical). resolveErrorChannel's
  PayloadClass arm is reached by a child @service field, so the swap is witnessed at the classification
  tier: ErrorChannelClassificationTest.childServiceRecordField_nestedPayloadBacking_payloadClassIsStructurallyResolved
  asserts (object-equality on the resolved TypeName) the PayloadClass.payloadClass() is the structural
  Outer.Nested, not Outer$Nested. Reverting the swap fails it.

The FetcherEmitter data-field cast sites (propertyOrRecordBinding / inlineSuccessRead) remain R412
(no reflected Class at the site); the error-channel witness is errors-only so it does not depend on them.

Moves R370 to In Review.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XcmnoNvZaeQDmxowznShNp
…face return

Independent-session In Review -> Done review of R406 (support a single-table
discriminated interface as a DML @mutation INSERT/UPDATE return type, landed at
e72eb02). Go decision.

Verified:
- Spec -> diff alignment: all five rework items delivered. buildDiscriminatedReprojection
  is gone; emitDiscriminated consumes R405's shared buildTableInterfaceReprojection
  with List.of() for alwaysProject; the R406-owned emitKeysTransaction / buildPkKeysCondition
  key off the RETURNING keys and are shared cleanly between emitProjected and
  emitDiscriminated, distinct from R405's records-keyed buildPkInCondition.
- Architecture: the new DiscriminatedSingle/List arm (over a per-verb leaf) is
  well-grounded in "lift the fork into the model"; the classify chokepoint resolves
  the interface verdict once; the dispatchPerformsReFetch validator mirror is updated
  in lockstep with OutputField.dmlTarget under the build-time drift guard.
- Tests: unit classification + regression + DELETE-floor pins, pipeline shape
  assertions, and a behavior-focused execution test (per-__typename routing,
  cross-table join, same-table isolation, unknown-discriminator write/read asymmetry).
- Build green: full reactor passes under -Plocal-db. The graphitron-core
  Query.allParties / JoinedTableInheritancePipelineTest red was the flagged stale-DB
  artifact (missing jti_* composite PKs); resolved by re-seeding rewrite_test and a
  clean catalog regen, orthogonal to R406.

Deleted the spec file, added a changelog entry citing e72eb02 and R405 (whose
buildTableInterfaceReprojection R406 consumes), regenerated the roadmap README.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011xZ4ase6WmQEvVBHnip131
A reviewer found the KeyNodeSynthesiser half of the R407 spec rested on a
false premise. KeyNodeSynthesiser.apply does not inject new null-source
federation nodes; it decorates author-written @node object types in place
(registry.remove + registry.add) with a @key directive. Those types are
author-owned with real source locations, and no lint rule fires on the
added @key. An implementer following "return the names of the nodes it
synthesises" literally would union author @node type names into the
exclusion set and suppress legitimate findings, violating acceptance
criterion 2.

Revise the spec so FederationLinkApplier / loadFederationImportedDefinitions
is the sole contributor of injected names throughout (Problem, Decision,
Implementation, Tests, Acceptance). KeyNodeSynthesiser.apply keeps its void
signature; no second injector is threaded into loadAttributedRegistry.
Strengthen the pipeline fixture to make the non-compliant author type a
@node type so it doubles as a regression guard for the exclusion set.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VRy6qDy2yYaemVFSsCbxee
…ter.Nested

Independent-session In Review -> Done review. The implementation delivers the
spec contract: both AccessorRef producers and the four @service-path in-hand
bestGuess-over-binary-fqClassName sites now build ClassNames structurally
(ClassName.get(Class) / captured javaReturnType), so a nested backing class
emits the JLS-legal Outer.Nested rather than the non-compiling Outer$Nested.
The two in-hand sites the prior review flagged (computeMutationServiceRecordReturnType,
resolveErrorChannel) are fixed with witnesses; the no-Class-in-hand emit sites
are correctly deferred to R412.

Delete the spec file, record the milestone in changelog.md (landing a13523e,
4e22ee4), and regenerate the roadmap README. Full reactor green under
mvn -f graphitron-rewrite/pom.xml install -Plocal-db.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YXADrG3nSgSjetK1K65tsy
The excludedTypes name-pattern filter sits at LintEngine.run's skip
points, which only see the engine's AST walk. Classifier advisories
arrive pre-formed on schema.warnings() and never pass through that walk,
so an excluded type would still show its classifier advisory, yet the
user doc promised exclusion "silences the warning everywhere it would
fire." Pick a side in prose: scope excludedTypes to engine findings only
(the flat BuildWarning list has a SourceLocation but no owning-type
handle to glob against; reverse-mapping it is the fragile-anchor trap
option C already rejects), state classifier advisories are suppressible
by rule id only, soften the doc sentence, and add a pipeline test pinning
that an excluded type still shows its classifier advisory.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DfK8XtbazhvCJZgSwpRhkb
…om linting

Independent Spec review. The KeyNodeSynthesiser finding raised in the first
pass was resolved by the author's revision (4eacff0): it now correctly
documents KeyNodeSynthesiser as an in-place decorator (no injected names),
and the pipeline fixture uses an author @node type to guard against folding
decorated names into the exclusion set. FederationLinkApplier provenance is
the sole injected-names contributor; all cited paths/line numbers verified.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019g1ow9ggLM4nRvLyN29Keo
…tion bugs

Two connection/pagination defects found probing Graphitron 10 output against
the utdanningsregisteret consumer schema (siblings to R413):

- R414: split/DataLoader connections build ConnectionResult without
  (table, condition), so ConnectionHelper.totalCount always returns null on
  nested connections though the SDL advertises totalCount: Int.
- R415: ConnectionHelper.pageRequest never clamps first/last >= 0, so a
  negative page size reaches SQL LIMIT and throws a redacted 500.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KoNNBn6Tw6cSoKooNaTXt2
R19's rebase-and-squash approach is not the path R182 takes; R182 unnests
the rewrite in three ordinary commits without rewriting history. Delete the
R19 item file, note the discard in changelog.md, regenerate the roadmap README.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KoNNBn6Tw6cSoKooNaTXt2
Remove the six legacy modules (graphitron-codegen-parent, graphitron-common,
graphitron-example, graphitron-maven-plugin, graphitron-servlet-parent,
graphitron-schema-transform) and the root reactor pom.xml. The rewrite reactor
is standalone (graphitron-rewrite/pom.xml has no parent and no dependency on
any legacy module) and continues to build via -f graphitron-rewrite/pom.xml;
docs/ parents to graphitron-rewrite-parent and is unaffected.

Also delete .github/workflows/maven-build.yml, which ran 'mvn --file pom.xml'
against the legacy root reactor on every push/PR to main and would fail the
required build check the moment the root POM is gone (rewrite-build.yml already
covers the rewrite reactor).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KoNNBn6Tw6cSoKooNaTXt2
git mv every graphitron-rewrite/ entry up to the repo root except docs/
(handled in commit 3): the eleven reactor modules, graphitron-tree-sitter-natives,
scripts/, roadmap/, roadmap-tool/, and the aggregator pom.xml, which becomes the
root POM. graphitron-rewrite-parent is now the sole parent; child modules use the
default ../pom.xml relativePath, which still resolves since parent and children
moved up together.

POM/path fixes required by the move:
- root pom.xml <modules>: ../docs -> docs; two comment paths de-prefixed.
- docs/pom.xml parent relativePath ../graphitron-rewrite/pom.xml -> ../pom.xml;
  render-roadmap-adoc scan dir ../graphitron-rewrite/roadmap -> ../roadmap.
- roadmap-tool/pom.xml check-adoc-tables: a single repo-root scan now covers
  docs/ too, so the second (now out-of-repo) root is dropped.

docs/ still points at graphitron-rewrite/docs/ for the architecture tree; that
move and its reference repoints land in commit 3. The only test red at this
boundary is ClassifiedDocTest (locates code-generation-triggers.adoc, not yet
moved), fixed in commit 3.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KoNNBn6Tw6cSoKooNaTXt2
…tecture/

Reshape the flat graphitron-rewrite/docs/ tree into a Diataxis-shaped
docs/architecture/{explanation,reference,how-to}/ folded into the site module,
and move roadmap-internal workflow.adoc out of the site.

Moves:
- explanation/: rewrite-design-principles, dispatch-axes, typed-rejection
- reference/: code-generation-triggers, argument-resolution, runtime-extension-points
- how-to/: testing, release-natives (was tree-sitter-natives-release)
- README.adoc split into index.adoc (quadrant picker + publishing policy),
  reference/modules.adoc (module table), explanation/pipeline-overview.adoc
  (pipeline narrative); added the three quadrant index pages.
- getting-started.adoc dissolved: its consumer content is already covered by the
  manual (runtime-api reference, custom-scalars, apollo-federation, tenant-scoping,
  dev-loop, tutorial), so only genuinely-new contributor internals move, into the
  new how-to/dev-loop-internals.adoc (5-component breakdown, both mermaid diagrams,
  federation-internals) carrying the #dev-loop-detail and #native-runtime-dependency
  anchors. workflow.adoc leaves the site entirely -> roadmap/workflow.adoc.

Reference repoints:
- Intra-tree quadrant xrefs; ~11 inbound docs/** xrefs (faq, quick-start,
  security, footer nav, index row, and the manual explanation/how-to/reference
  pages) repointed to the new quadrant paths / manual homes; manual->architecture
  refs corrected from ../../../ to ../../ now that architecture is local under docs/.
- roadmap-tool Main.java: README header, quadrant-aware mapAdocTarget (+ workflow
  arm + ARCH_QUADRANT table), and the status-board header.
- docs/pom.xml: architecture/** folded into stage-adoc; stage-architecture + the
  README->index copy hack removed; per-quadrant css + docinfo copy targets added.
- graphitron-mcp docs.source.dir ../../docs -> ../docs (module moved up in commit 2).

Test fixups for moved paths: ClassifiedDocTest and SealedHierarchyDocCoverageTest
doc paths; ManualXrefIntegrityTest drops the obsolete graphitron-rewrite/docs
staging remap (architecture is now first-class local content).

Full reactor green under mvn install -Plocal-db (docs profile renders); the
rendered /architecture/ Diataxis tree and /roadmap/ verified, workflow absent
from the site as intended.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KoNNBn6Tw6cSoKooNaTXt2
Drop the -f graphitron-rewrite/pom.xml flag and graphitron-rewrite/ path
prefixes now that the reactor root is the repo root:

- rewrite-build.yml: init.sql path, mvn verify, the roadmap-tool leaf-coverage
  invocation (scan root graphitron-rewrite -> .), and the two artifact paths
  (roadmap/inference-axis-coverage.adoc); docs-build mvn -pl :graphitron-docs.
- preview-docs.yml: paths filter collapses (graphitron-rewrite/docs/** folds into
  the existing docs/**; roadmap/** and pom.xml de-prefixed) and the docs mvn drops -f.
- maven-publish.yml: init.sql path, versions:set, and deploy drop -f (the RC-aware
  tag regex is already in place, so the release-event path now builds the single
  root reactor rather than the deleted legacy one).
- .gitlab-ci.yml: init.sql path, versions:set, and deploy drop -f.
- tree-sitter-natives-release.yml: NATIVES_MODULE / GRAMMAR_DIR env vars de-prefixed.

LeafCoverageReport: with the scan root now the repo root, the migration-mode
output path changes from root.resolveSibling(docs/...) to root.resolve(docs/...)
(docs is a child of root, no longer a sibling of graphitron-rewrite), and the
regenerate hint drops -f and uses 'leaf-coverage .'.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KoNNBn6Tw6cSoKooNaTXt2
De-prefix graphitron-rewrite/ from paths and drop the -f graphitron-rewrite/pom.xml
flag across the docs and tooling that survived the move, and repoint the retired
docs into their new homes.

- CLAUDE.md: drop the legacy-out-of-scope Scope rule (whole repo is in scope now),
  fix the module list, common commands, doc links (architecture quadrants,
  roadmap/workflow.adoc), and the roadmap-tool commands.
- .claude/web-environment.md: root-pom build commands, testing.adoc link, and drop
  the now-moot standalone-build-verify section.
- .claude/skills/* and .claude/agents: roadmap/, capabilities/, module source paths,
  workflow.adoc -> roadmap/, architecture doc links, and mvn commands.
- .claude/scripts/session-start-web-env.sh: init.sql path.
- README.md: replace dead legacy-module links + legacy Building section with the
  rewrite manual/tutorial links and the single-reactor build.
- docs/README.adoc, docs/manual/**, docs/architecture/** body text: de-prefixed
  paths, mvn commands, and the sakila-example / init.sql references.
- rewrite-design-principles.adoc: rewrite the 'builds independently of legacy'
  section (no legacy tree remains) and retire verify-standalone-build.sh.
- roadmap/workflow.adoc + roadmap/inference-axis-coverage.adoc: paths and the
  leaf-coverage regen command.
- roadmap-tool (LeafCoverageReport, pom description): report-header command,
  migration output path (root.resolve, not resolveSibling), and description.
- Emitted build diagnostics + their paired test assertions: the deferred-rejection
  'see roadmap/<slug>.md' hint (Rejection, GraphitronSchemaValidator, BuildContext,
  FieldBuilder) and the federation-recipe message (-> docs/manual/how-to/apollo-federation.adoc),
  plus diagnostics-glossary.adoc and the javadoc references.
- Delete .mise.toml (legacy example workflow; to be rebuilt for the rewrite later).

Full reactor green under mvn install -Plocal-db (docs profile renders).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KoNNBn6Tw6cSoKooNaTXt2
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KoNNBn6Tw6cSoKooNaTXt2
The R182 unwrap moved the reactor pom to repo root; R407's acceptance
criteria still cited `mvn -f graphitron-rewrite/pom.xml install -Plocal-db`.
Match the canonical post-unwrap form in CLAUDE.md (`mvn install -Plocal-db`).
Tooling-path correction only; the design and all code/line citations remain
correct post-unwrap (verified). Item stays Ready.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019g1ow9ggLM4nRvLyN29Keo
…mojo-configuration.adoc

R182 dissolved getting-started.adoc; the R408 first-client doc block named it
as its home. Repoint to the live docs/manual/reference/mojo-configuration.adoc
plugin-config reference (the spec's own hedged alternative), which already
documents every <configuration> parameter the new <lint> block would join.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BujyXUx4FRC3hSbMnRJTUv
…repo root

Independent-session In Review -> Done review of R182 (spec:
unnest-rewrite-aggregator.md). Every spec deliverable shipped across the
five-commit sequence (657dd71 delete, a505cab unwrap, aad2f61 docs, cbaeb64
CI, 31750bf paths): legacy graphitron-parent reactor and maven-build.yml
gone, rewrite aggregator promoted to root POM with its modules + docs at top
level, docs restructured into Diataxis docs/architecture/, workflow.adoc moved
to roadmap/ and absent from the site, maven-publish.yml de-prefixed with the
RC-aware tag regex, roadmap-tool mapAdocTarget made quadrant-aware, R19
discarded, verify-standalone-build.sh retired, CLAUDE.md scope rule removed.

Full reactor green under mvn install -Plocal-db (2406 tests in graphitron;
docs site renders the /architecture/ Diataxis tree). The graphitron-core red
first seen in the review sandbox (Query.allParties -> UnclassifiedField) was
the known stale-rewrite_test-DB artifact (DB predated the R389 party fixture,
jOOQ skipped codegen); re-seed + clean catalog regen produced a fully green
reactor, orthogonal to the R182 diff.

Delete the spec file, record the milestone in changelog.md, regenerate README.
Also repoint changelog.md's header workflow.adoc link (../docs/workflow.adoc ->
workflow.adoc) missed by the workflow.adoc relocation.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KFwPVAeukggLNLYZjmX5Kc
Independent Spec-review sign-off. Design verified sound against the
build-is-single-evaluator spine and the typed-not-stringly config guard; the
excludedTypes/classifier-advisory scope asymmetry is settled in prose with a
pinning test, and every named code symbol resolves at post-unnest paths. The
only stale reference the R182 unwrap introduced (the dissolved
getting-started.adoc doc home) was repointed to mojo-configuration.adoc in the
prior commit. User confirmed the trivial doc-path edit does not disqualify this
session from the reviewer-rule guard.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BujyXUx4FRC3hSbMnRJTUv
… linting

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019g1ow9ggLM4nRvLyN29Keo
…ting

The R398 lint engine warned on federation @link import definitions
(federation__FieldSet, link__Import, ...) that FederationLinkApplier injects
into the registry. The author never wrote them, cannot rename them (the names
are dictated by the federation spec) and cannot document them (descriptions
are owned by federation-graphql-java-support), so type-names-pascal-case and
types-and-fields-have-descriptions firing on them was pure noise.

Identify the injected definitions by provenance from the injector, not a name
heuristic: FederationLinkApplier.apply now returns the Set of names it injected
(collected in its existing defs.forEach loop) instead of a bare boolean.
AttributedRegistry carries that set as injectedNames() and derives the
federationLink() flag from it (injected anything), collapsing the two facts
into one component. LintEngine.run gains an overload taking the injected-name
set and unions it with the existing BUNDLED_TYPE_NAMES exclusion at the two
skip points it already has; no new skip mechanism, no new rule, no new node
kind. KeyNodeSynthesiser is untouched: it decorates author @node types in
place and injects no new definitions, so folding its names in would wrongly
silence real author violations.

Pipeline test carries a federation @link plus an author "type lowercase @node"
(the exact type KeyNodeSynthesiser decorates): the injected names stay silent
while the author type's pascal-case violation still fires, guarding both halves.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019g1ow9ggLM4nRvLyN29Keo
…n implemented

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019g1ow9ggLM4nRvLyN29Keo
… retirement

main's #499 (null guard for listed enum filters) added integration-test
fixtures and a record under graphitron-example/, the legacy example module.
R182 retired that whole module, but its deletion set predated #499, so these
seven files survived the rebase as orphans referencing a module that no
longer has a pom or build. Remove them so the rebased trunk tree matches the
rewrite's intended final state.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WZA9xDNjKE6WpUK53PGnG7
@alf
alf requested a review from folkef6 July 1, 2026 16:53
@alf alf closed this Jul 1, 2026
@alf

alf commented Jul 1, 2026

Copy link
Copy Markdown
Collaborator Author

Fikser dette fra cli.

@alf
alf deleted the claude/graphitron-rewrite-ff-uc9avo branch July 1, 2026 18:18
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.

3 participants