Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions docs/execplans/codegraph-parity.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,16 @@ Implementation, validation, draft publication, and release are separate states.

## Progress

- 2026-09-24: Resumed the paused S1.06b1 type relations and hierarchy layer
on `feat/codegraph/type-hierarchy`, based on `main`. PostgreSQL now counts
distinct direct subtypes, and the internal neighbor lookahead allows 401 rows
for the 400-row descendant walk. The integration test's capture translation
was corrected: the artifact keeps the store's repository ID, and store evidence
is compared by fact. The `Base` edge column expectation is 29, which matches
`core.ts`. The accepted CD02 capture, the library `Base`/`Service` hierarchy,
the synthetic direction controls and the count/scope/cancellation/bound
checks pass. Service-level only: no REST, MCP or browser exposure. B2 dead
code and the rest of S1.06 remain open.
- 2026-09-14: The partial S1.07 discovery transport milestone exposes bounded
v2 discovery, exploration, file inventory, and versioned capabilities over
bearer-only REST and MCP while preserving existing context/impact/trace
Expand Down Expand Up @@ -610,6 +620,10 @@ The rebased sessions layer also passes the exact two-call restoration comparison

## Remaining gaps

- S1.06b1 type hierarchy is implemented at the service level only. Level
ordering uses byte order where the pinned source uses locale comparison, and
a subtype with both `extends` and `implements` counts as `extends` rather than
by the first edge read. Transport exposure belongs to S1.07/S1.09.
- Representative reference captures are mapped to inventory task IDs;
remaining conformance variants stay
planned with their owning stages, comparison contracts and upstream tests.
Expand Down Expand Up @@ -649,6 +663,7 @@ The rebased sessions layer also passes the exact two-call restoration comparison
| S1.06a1 file dependencies | `feat/codegraph/s1-06a1-file-dependencies` | Implemented, independently reviewed and signed; depends on PR #78 | Draft [PR #79](https://github.com/balcsida/graphnest/pull/79); native stack #66, position 15 |
| S1.06a2 graph aggregates | `feat/codegraph/s1-06a2-graph-aggregates` | Implemented, independently reviewed and signed (`85dee2e`); depends on PR #79 | Draft [PR #81](https://github.com/balcsida/graphnest/pull/81); native stack #66, position 16; CI and CodeQL passed |
| S1.06a3 entity impact | `feat/codegraph/s1-06a3-entity-impact` | Implemented, independently approved and signed (`931e7d9`); depends on PR #81 | Draft [PR #82](https://github.com/balcsida/graphnest/pull/82); native stack #66, position 17; CI and CodeQL passed |
| S1.06b1 type relations and hierarchy | `feat/codegraph/type-hierarchy` | Implemented; focused unit, service and PostgreSQL checks pass; based on `main` | [PR #119](https://github.com/balcsida/graphnest/pull/119) |

The first one-branch submission created a draft PR without a remote stack.
Submitting the second real dependent layer created native stack #66
Expand Down
14 changes: 14 additions & 0 deletions docs/graph-analysis.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,3 +139,17 @@ PostgreSQL applies repository, upload, commit, and schema constraints to both en
Every A3 response reports analysis state. `freshness=current` means current relative to the selected indexed commit. `complete=true` means the bounded query finished; `partial` and its boundaries independently report omitted graph results. `coverage=not_assessed` states that these operations do not establish producer or source-analysis coverage, and `unresolved` exposes the selected generation's unresolved-reference count.

Impact processes dependency levels and closes same-depth containment before advancing. This intentionally differs from the pinned source's depth-first traversal, which finalizes a node's first depth and can omit descendants when a later containment path reaches that node more cheaply. Accepted producer captures remain unchanged; GraphNest reports the shortest retained dependency depth and truthful within-hop reachability.

## Type relations and hierarchy

`graphquery.Service` adds two generation-scoped operations, `TypeRelations` and `TypeHierarchy`; `graphservice.Service` authorizes them and rechecks the selected commit like the other analysis operations. They are service-level only; REST, MCP, and browser exposure remain transport work.

Type relations return recorded outgoing `type_of`/`returns` targets, incoming `type_of` users, incoming `returns` returners, outgoing `references` whose target is a type kind, and recorded `overrides`. Each group keeps every original edge occurrence rather than collapsing repeated evidence. `type_knowledge=unknown` means the producer recorded no outgoing type facts for the entity; it is not a claim that the entity is untyped. The pinned portable producer emitted no `type_of` or `returns` edges for the accepted fixtures, so they report `unknown`.

Type hierarchy walks `extends` and `implements` for class, interface, struct, trait, protocol, enum, type alias, and union entities. Ancestors are complete to depth 8; descendants are breadth-first to depth 6 and at most 400 materialized rows, of which the viewer shows 24 ancestors and 240 descendants while reporting `total`, `shown`, and `truncated`. Each level lists `extends` before `implements`, then name, path, and line, as the pinned source does. A type tied to one supertype by both relations appears once, as `extends`. Cycles and duplicate occurrences are visited once per walk. When rows or depth stop the walk, `bounded`, `partial`, the boundary, and each parent's `hidden_subtypes` say so instead of presenting the last row as a leaf. Synthesized Go implicit implementations keep `synthesized`, `via`, `registered_at`, and their heuristic provenance.

`direct_subtypes` and `direct_implementers` count distinct direct subtypes in PostgreSQL, independent of the row bound, so they stay true when the list is truncated. A subtype with both relations counts as `extends`; the pinned source counts it by whichever edge it reads first. `polymorphic` is set at eight direct implementers.

Derived overrides match the focus's method, function, property, and field members by name against the nearest of up to 12 ancestors' members. They are always `signature_uncertain`, because overloads and signatures are not compared, and are reported separately from recorded `overrides` edges. Names sort by byte order; the pinned source uses locale comparison, which can order mixed-case names differently.

Permanent conformance uses the accepted real-producer capture in `test/fixtures/codegraph/type-hierarchy-facts.json` (37 nodes, 53 edges, 3 files, 5 unresolved references) with its four source files, whose hashes the integration test verifies, plus the pinned library fixture's `Base`/`Service` hierarchy. The capture was produced by the pinned CodeGraph at `b9ca4b7981116909900368cc1686a1074cd4d4c1` by indexing those sources twice and comparing both passes. Synthetic topologies cover bounds, cycles, direction, and recorded type relations; they are not producer output.
81 changes: 81 additions & 0 deletions internal/graphprotocol/type_hierarchy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package graphprotocol

const (
TypeKnowledgeRecorded = "recorded"
TypeKnowledgeUnknown = "unknown"
)

type TypeRelationsRequest struct {
Scope Scope `json:"scope"`
Occurrence string `json:"occurrence"`
}

// RelatedEntities groups repeated edge occurrences without losing evidence.
type RelatedEntities struct {
Entity Entity `json:"entity"`
Relation string `json:"relation"`
Edges []Evidence `json:"edges"`
}

type TypeRelationsResponse struct {
Status string `json:"status"`
TypeKnowledge string `json:"type_knowledge"`
Types []RelatedEntities `json:"types,omitempty"`
Users []RelatedEntities `json:"users,omitempty"`
Returners []RelatedEntities `json:"returners,omitempty"`
ReferencedTypes []RelatedEntities `json:"referenced_types,omitempty"`
RecordedOverrides []RelatedEntities `json:"recorded_overrides,omitempty"`
Analysis *AnalysisState `json:"analysis,omitempty"`
Generations []Generation `json:"generations"`
Boundaries []Boundary `json:"boundaries,omitempty"`
Partial bool `json:"partial"`
}

type TypeHierarchyRequest struct {
Scope Scope `json:"scope"`
Occurrence string `json:"occurrence"`
}

type HierarchyEntry struct {
Entity Entity `json:"entity"`
Depth int `json:"depth"`
ParentID string `json:"parent_id"`
Relation string `json:"relation"`
Edge Evidence `json:"edge"`
Synthesized bool `json:"synthesized"`
Via string `json:"via,omitempty"`
RegisteredAt string `json:"registered_at,omitempty"`
HiddenSubtypes int `json:"hidden_subtypes"`
}

// HierarchyRows keeps every bounded query row while stating the viewer cap.
type HierarchyRows struct {
Items []HierarchyEntry `json:"items"`
Total int `json:"total"`
Shown int `json:"shown"`
Truncated bool `json:"truncated"`
}

type DerivedOverride struct {
Member Entity `json:"member"`
BaseMember Entity `json:"base_member"`
BaseType Entity `json:"base_type"`
Relation string `json:"relation"`
SignatureUncertain bool `json:"signature_uncertain"`
}

type TypeHierarchyResponse struct {
Status string `json:"status"`
Focus Entity `json:"focus"`
Ancestors HierarchyRows `json:"ancestors"`
Descendants HierarchyRows `json:"descendants"`
DirectSubtypes int `json:"direct_subtypes"`
DirectImplementers int `json:"direct_implementers"`
Bounded bool `json:"bounded"`
Polymorphic bool `json:"polymorphic"`
DerivedOverrides []DerivedOverride `json:"derived_overrides,omitempty"`
Analysis *AnalysisState `json:"analysis,omitempty"`
Generations []Generation `json:"generations"`
Boundaries []Boundary `json:"boundaries,omitempty"`
Partial bool `json:"partial"`
}
Loading
Loading