Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
107 commits
Select commit Hold shift + click to select a range
713809b
graph: carry a re-parsed file's call edges as provisional
zzet Oct 31, 2026
b12c996
indexer: report whether a file is tracked without a stat
zzet Oct 31, 2026
9014285
mcp: report read handlers that can reach a reindex
zzet Oct 31, 2026
127a8ad
Merge commit '595ad6db26b0ce1d01fdfa01c15edf364184a4eb' into integrat…
zzet Nov 2, 2026
b3977e6
Complete bounded projected reads and selected-view retirement
zzet Nov 2, 2026
a6189d2
Merge commit '36c4e06787d6696050a830af0b0097fa01f6e781' into integrat…
zzet Nov 2, 2026
8e3ebdd
Merge commit 'cd320ad8f' into integration/projected-reads-complete
zzet Nov 2, 2026
55867d7
Merge branch 'integration/edit-choke-point-complete' into integration…
zzet Nov 2, 2026
faee9a7
Share search projection ownership with response decoration
zzet Nov 2, 2026
dbcfe31
Merge branch 'integration/edit-choke-point-complete' into integration…
zzet Nov 2, 2026
4f90cf3
Merge branch 'integration/edit-choke-point-complete' into integration…
zzet Nov 2, 2026
8d12f91
Merge branch 'integration/edit-choke-point-complete' into integration…
zzet Nov 2, 2026
0700485
Merge branch 'integration/edit-choke-point-complete' into integration…
zzet Nov 2, 2026
b44e3a8
Merge branch 'integration/edit-choke-point-complete' into integration…
zzet Nov 2, 2026
1734767
Merge branch 'integration/edit-choke-point-complete' into integration…
zzet Nov 2, 2026
4aa2e84
Merge branch 'integration/edit-choke-point-complete' into integration…
zzet Nov 2, 2026
c398fae
test(mcp): order retirement replacement after the actual current entry
zzet Nov 2, 2026
e4b2e03
test(mcp): require refusal when retirement selection is superseded
zzet Nov 2, 2026
ef0e5b7
Merge branch 'integration/edit-choke-point-complete' into integration…
zzet Nov 2, 2026
3ebf2a2
Merge branch 'integration/edit-choke-point-complete' into integration…
zzet Nov 2, 2026
a867547
Merge branch 'integration/edit-choke-point-complete' into integration…
zzet Nov 2, 2026
b1c2140
Merge branch 'integration/edit-choke-point-complete' into integration…
zzet Nov 2, 2026
514cc22
test(mcp): require current summary for a new untracked source file
zzet Nov 2, 2026
50db259
Merge qualified edit dependencies without changing projected reads
zzet Nov 2, 2026
264e5da
Merge commit '2882dfd4b7a43c37844468d27df1f23559440ecb' into integrat…
zzet Nov 2, 2026
efdd21c
test(mcp): require pending file labels during source storms
zzet Nov 2, 2026
6735a5c
Merge branch 'integration/edit-choke-point-complete' into integration…
zzet Nov 2, 2026
7351a5f
fix(mcp): project admitted untracked files in selected checkout
zzet Nov 2, 2026
f42217e
Merge commit '6735a5ce1b658d4575533969251f6b42a4aac215' into fix/proj…
zzet Nov 2, 2026
ce26409
Merge commit 'f42217e8c5d1462b4a2dc0dbdb0b3792921fefae' into fix/labe…
zzet Nov 2, 2026
7640c39
test(indexer): pin path-scoped queued storm observation
zzet Nov 2, 2026
5479622
feat(indexer): expose path-scoped queued storm hints
zzet Nov 2, 2026
fcffcc1
fix(mcp): defer file projections during queued source storms
zzet Nov 2, 2026
dda31cb
test(indexer): reject superseded queued storm hints
zzet Nov 2, 2026
f65a9cd
test(mcp): require pending summary when projection budget expires
zzet Nov 2, 2026
d1a7045
feat(mcp): prepare scoped store-busy facts for read responses
zzet Nov 2, 2026
8d4fd63
Merge commit 'd1a70450a118075dea1864f637f8df75654641f3' into test/pro…
zzet Nov 2, 2026
54c68d5
test(mcp): cover projected source identity and read frontend contracts
zzet Nov 2, 2026
099ec1e
fix(mcp): return qualified pending graph after projection timeout
zzet Nov 2, 2026
7c85042
style(indexer): format path-scoped storm observation donor
zzet Nov 2, 2026
4715c33
Merge commit '099ec1edbf586e25f306df65143ae301013e5cb8' into test/pro…
zzet Nov 2, 2026
0b850ea
Merge commit '7c85042d50bfe0cf843e2b92e858cf8c25361e5e' into test/pro…
zzet Nov 2, 2026
2a0d06e
fix(mcp): keep projected read sources and identities coherent
zzet Nov 2, 2026
a7dbfeb
test(mcp): require one nonwaiting admission for new external projections
zzet Nov 2, 2026
500ff62
test(mcp): inspect the existing value-owned mutation ledger
zzet Nov 2, 2026
84e6983
fix(mcp): preserve the source retry budget and original facts
zzet Nov 2, 2026
132cd3e
Merge branch 'test/projected-read-frontend-contract' into fix/admit-r…
zzet Nov 2, 2026
1f1b641
fix(mcp): keep projected file rows when store budget expires
zzet Nov 2, 2026
cdfb61a
fix(mcp): bound summary store reads and preserve pending partials
zzet Nov 2, 2026
0946996
fix(mcp): admit newly published read projections without awaiting gra…
zzet Nov 2, 2026
adbd371
fix(mcp): fence deferred compression and whole-call source retries
zzet Nov 2, 2026
cd1c19d
test(mcp): report actual mixed retry invocation count before refusal …
zzet Nov 2, 2026
79693f6
Merge commit '02dec864cae35b1097ce3234d8f9bc648d1d67c0' into fix/admi…
zzet Nov 2, 2026
0b70624
Merge branch 'fix/source-measurement-clock-precision' into fix/admit-…
zzet Nov 2, 2026
0b39266
Merge branch 'fix/source-measurement-clock-precision' into fix/admit-…
zzet Nov 2, 2026
3fb5264
fix(mcp): own source replay allowance at the outer retry boundary
zzet Nov 2, 2026
c67f9cc
Merge branch 'fix/source-measurement-clock-precision' into fix/admit-…
zzet Nov 2, 2026
60c85a6
Merge branch 'fix/source-measurement-clock-precision' into fix/admit-…
zzet Nov 2, 2026
bc78ffe
test(mcp): use the actual disk verdict in the external-write control
zzet Nov 2, 2026
872f9cf
Merge branch 'fix/source-measurement-clock-precision' into fix/admit-…
zzet Nov 2, 2026
5351e86
Merge branch 'fix/source-measurement-clock-precision' into fix/admit-…
zzet Nov 2, 2026
6dca6a4
test(mcp): reproduce observed source-event projection poisoning
zzet Nov 2, 2026
e363e0c
fix(mcp): revalidate observed source events at read projection public…
zzet Nov 2, 2026
f7cb084
fix(mcp): refuse a projection superseded during selected-view proof
zzet Nov 2, 2026
84a7166
Merge branch 'fix/source-measurement-clock-precision' into fix/admit-…
zzet Nov 2, 2026
0171d4d
test(mcp): join cancelled projection work without a discarded assignment
zzet Nov 2, 2026
4864f5e
test(mcp): expose cached storm reads and preselection source drift
zzet Nov 2, 2026
6db6683
fix(mcp): reuse cached storm reads and retry typed preselection drift
zzet Nov 2, 2026
9ab4708
Merge branch 'fix/source-measurement-clock-precision' into fix/admit-…
zzet Nov 2, 2026
0dc184c
Merge branch 'fix/source-measurement-clock-precision' into fix/admit-…
zzet Nov 2, 2026
4d23e52
Merge commit '61d9157c49401f6f2cab87c93b093f5c251a47e6' into integrat…
zzet Nov 2, 2026
440f088
Merge commit '52399c2c29de8ad02aed18ca3b28ca22683c21c3' into integrat…
zzet Nov 2, 2026
2c3d389
Merge landed parent history without changing qualified sources
zzet Nov 2, 2026
46133f0
fix(mcp): preserve healthy compression with checked selected source r…
zzet Nov 2, 2026
cade568
test(mcp): admit physical owner in compression supersession controls
zzet Nov 2, 2026
5c83a01
style(mcp): remove redundant compression assignment and simplify test…
zzet Nov 2, 2026
330ad9a
test(mcp): expose shared generation zero compression ABA
zzet Nov 2, 2026
474c3d4
test(mcp): pin the selected generation source field and actual node ABA
zzet Nov 2, 2026
b082899
fix(mcp): witness shared generation zero during compression binding
zzet Nov 2, 2026
767a952
Merge current main parser source into projected reads
zzet Nov 2, 2026
18f95b6
test(mcp): prepare canonical promotion late-read interleaving controls
zzet Nov 2, 2026
193f70a
fix(mcp): retry source reads after checked projection retirement
zzet Nov 2, 2026
2c0bc53
Merge current main shutdown fix into projected reads
zzet Nov 2, 2026
cc09a80
test(mcp): cover canonical promotion during summary and editing context
zzet Nov 2, 2026
6211ba4
fix: retry checked canonical retirement in file metadata reads
zzet Nov 2, 2026
dcf581e
test(mcp): trace registered reads across preselection retirement
zzet Nov 2, 2026
1238bb8
test(mcp): use actual daemon promotion before registered frames
zzet Nov 2, 2026
ae0eae2
test(mcp): bind universal and transport session identities together
zzet Nov 2, 2026
12ea57d
Merge qualified causal fixture foundation into projected reads
zzet Nov 2, 2026
dc37be9
test(mcp): race same-session reads over one suspect ACK owner
zzet Nov 2, 2026
aa31d03
fix(mcp): replay audited file reads after early projection CAS loss
zzet Nov 2, 2026
d4a7778
test(mcp): check remaining readers after a same-owner COW loss
zzet Nov 2, 2026
ad8588d
fix(mcp): retry full metadata CAS selection before response effects
zzet Nov 2, 2026
2a88f65
Merge qualified current CI foundation into edited-file read CAS source
zzet Nov 2, 2026
11e622c
Merge current qualified dependencies into C publication source
zzet Nov 2, 2026
4a2dfeb
test: exercise native concurrent read population
zzet Nov 2, 2026
71812b5
Merge qualified current parser and foundation for read refusal control
zzet Nov 2, 2026
7bca656
test: isolate post-borrow same-byte read COW refusal
zzet Nov 2, 2026
7fa55d1
fix: retry checked same-version read COW with physical fencing
zzet Nov 2, 2026
f26cd4c
test: preserve retirement proof across an unchanged losing read
zzet Nov 2, 2026
16bdefe
fix: keep unchanged read supersession separate from invalidation
zzet Nov 2, 2026
57e7cc1
Merge current qualified C publication dependencies
zzet Nov 2, 2026
3e6a994
Merge pure-c-retirement with qualified unchanged issue source
zzet Nov 2, 2026
238db3b
Merge pure-c-current-main with qualified unchanged issue source
zzet Nov 2, 2026
afebbf0
fix(mcp): retain bounded canonical rows after projection expiry
zzet Nov 2, 2026
1d6e131
test(mcp): join canonical read callbacks on the test owner
zzet Nov 2, 2026
13e726c
test(mcp): isolate SQL read interleavings and caller deadlines
zzet Nov 2, 2026
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
18 changes: 9 additions & 9 deletions cmd/gortex/wire_contract_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,16 +123,16 @@ func wireContractGolden(name string) string {
// ProjectID, were added.
return "a600bd906c9e09ffa0828427f5d6622acd5fe244798a61d5712c151053be5dac"
case "graph.Edge":
// Bumped when NameOnly was added — the marker on a synthesized
// name-only candidate row (a call site that named the symbol but
// never bound to it, projected onto it by find_usages /
// get_callers under min_tier:"text_matched"). Set only on the
// in-memory projection, so a persisted edge always carries it
// false; not part of the edge identity / dedup key.
// (Previously bumped when Alias — the renamed name carried by a
// per-binding import or re-export edge — then Via, ReturnUsage,
// Bumped when Provisional was added — the marker on a stored call
// edge carried onto an overlay that re-parsed its file before
// relations were rebuilt. Set only on the in-memory overlay, so a
// persisted edge always carries it false; not part of the edge
// identity / dedup key.
// (Previously bumped when NameOnly — the marker on a synthesized
// name-only candidate row projected by find_usages / get_callers
// under min_tier:"text_matched" — then Alias, Via, ReturnUsage,
// Context, and Tier, were added.)
return "d27d737c6c164243e2d55b4ca265a46d658e9617546f20306e9357e17aa46603"
return "fb8425eff2fe4f2b17d665fd182a48b6f5f5b832c90dc750ca4f933b639cee2c"
default:
panic(fmt.Sprintf("no golden fingerprint for %s", name))
}
Expand Down
5 changes: 3 additions & 2 deletions internal/graph/delta_writer_payload.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ func deltaEdgeRender(e *Edge) string {
c.Via = ""
c.Alias = ""
c.NameOnly = false
c.Provisional = false
return fmt.Sprintf("%+v", c)
}

Expand Down Expand Up @@ -145,10 +146,10 @@ func deltaEdgeContentEqual(a, b *Edge) bool {
}

// deltaEdgeFieldsCompared is the number of Edge fields deltaEdgeContentEqual
// accounts for (the ten it compares, Meta, and the five that are not
// accounts for (the ten it compares, Meta, and the six that are not
// persisted). An Edge with another field falls back to the rendered
// comparison until the comparison learns it.
const deltaEdgeFieldsCompared = 16
const deltaEdgeFieldsCompared = 17

var deltaEdgeFields = reflect.TypeOf(Edge{}).NumField()

Expand Down
7 changes: 7 additions & 0 deletions internal/graph/edge.go
Original file line number Diff line number Diff line change
Expand Up @@ -621,6 +621,13 @@ type Edge struct {
// only on the in-memory projection under min_tier:"text_matched";
// never persisted, never part of the edge identity / dedup key.
NameOnly bool `json:"name_only,omitempty"`
// Provisional marks a stored relation carried onto an overlay that
// re-parsed its file before relations were rebuilt: the new content
// still references the same target from the same source, so the edge
// is served at the reference's new line until the reindex confirms
// it. Set only on the in-memory overlay; never persisted, never part
// of the edge identity / dedup key.
Provisional bool `json:"provisional,omitempty"`
// Meta is intentionally excluded from JSON. It holds internal
// instrumentation (semantic_source, provider hints, etc.) that agents
// don't consume but that adds measurable bytes to every edge in
Expand Down
2 changes: 1 addition & 1 deletion internal/graph/file_editing_context.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import "sort"
//
// Every read is a batched Reader call, so a reader wrapper that narrows
// adjacency gets the same fixed round-trip count with its own edge semantics.
func FileEditingContextOf(r Reader, filePath string, kinds []NodeKind) *FileEditingContextResult {
func FileEditingContextOf(r FileEditingContextRows, filePath string, kinds []NodeKind) *FileEditingContextResult {
if filePath == "" {
return nil
}
Expand Down
162 changes: 162 additions & 0 deletions internal/graph/file_editing_context_context.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
package graph

import (
"context"
"errors"
)

var ErrFileEditingContextUnsupported = errors.New("cancellable editing context unsupported")

// FileEditingContextRows is the full-field input to the editing-context bundle.
// It deliberately exposes no mutation, scan, transaction or unrelated graph API.
type FileEditingContextRows interface {
GetFileNodes(string) []*Node
GetNode(string) *Node
GetOutEdges(string) []*Edge
GetNodesByIDs([]string) map[string]*Node
GetOutEdgesByNodeIDs([]string) map[string][]*Edge
GetInEdgesByNodeIDs([]string) map[string][]*Edge
}

// FileEditingContextReadScope lends a reader only for the synchronous bundle
// callback. The callback may use only the five reads in FileEditingContextOf
// (and GetNode for overlay endpoint visibility). It must not retain the reader.
// Implementations reject cancellation, partial rows and changed revisions after
// the callback; a callback result is usable only when this method returns nil.
// This narrow scope is not a general Reader transaction API.
type FileEditingContextReadScope interface {
WithFileEditingContextReader(context.Context, func(context.Context, FileEditingContextRows) error) error
}

type FileEditingContextLayerScope interface {
WithFileEditingContextLayer(context.Context, func(context.Context, OverlayLayerReader) error) error
}

func WithFileEditingContextReader(ctx context.Context, r Reader, fn func(context.Context, FileEditingContextRows) error) error {
if ctx == nil {
return ErrFileEditingContextUnsupported
}
if err := ctx.Err(); err != nil {
return err
}
scoped, ok := r.(FileEditingContextReadScope)
if !ok {
return ErrFileEditingContextUnsupported
}
return scoped.WithFileEditingContextReader(ctx, fn)
}

func (v *OverlaidView) WithFileEditingContextReader(ctx context.Context, fn func(context.Context, FileEditingContextRows) error) error {
if ctx == nil {
return ErrFileEditingContextUnsupported
}
if err := ctx.Err(); err != nil {
return err
}
withLayer := func(ctx context.Context, base FileEditingContextRows) error {
if v.layer == nil {
return fn(ctx, NewOverlaidViewWithLayer(editingContextReaderOf(base), nil))
}
layer, ok := v.layer.(FileEditingContextLayerScope)
if !ok {
return ErrFileEditingContextUnsupported
}
return layer.WithFileEditingContextLayer(ctx, func(ctx context.Context, l OverlayLayerReader) error {
return fn(ctx, &editingContextView{NewOverlaidViewWithLayer(editingContextReaderOf(base), l)})
})
}
if v.base == nil {
return withLayer(ctx, nil)
}
return WithFileEditingContextReader(ctx, v.base, withLayer)
}

func (g *Graph) WithFileEditingContextReader(ctx context.Context, fn func(context.Context, FileEditingContextRows) error) error {
if ctx == nil {
return ErrFileEditingContextUnsupported
}
if err := ctx.Err(); err != nil {
return err
}
revision := g.MutationRevision()
if err := fn(ctx, g); err != nil {
return err
}
if err := ctx.Err(); err != nil {
return err
}
if revision != g.MutationRevision() {
return ErrContractProjectionStale
}
return nil
}
func (l *OverlayLayer) WithFileEditingContextLayer(ctx context.Context, fn func(context.Context, OverlayLayerReader) error) error {
if ctx == nil {
return ErrFileEditingContextUnsupported
}
if err := ctx.Err(); err != nil {
return err
}
if err := fn(ctx, l); err != nil {
return err
}
return ctx.Err()
}

// The ephemeral composition only invokes the six bundle reads. A nil embedded
// Reader makes any accidental expansion fail rather than reach a live backend.
type editingContextReader struct {
Reader
FileEditingContextRows
}

func editingContextReaderOf(rows FileEditingContextRows) Reader {
if rows == nil {
return nil
}
return &editingContextReader{FileEditingContextRows: rows}
}
func (r *editingContextReader) GetFileNodes(path string) []*Node {
return r.FileEditingContextRows.GetFileNodes(path)
}
func (r *editingContextReader) GetNode(id string) *Node { return r.FileEditingContextRows.GetNode(id) }
func (r *editingContextReader) GetOutEdges(id string) []*Edge {
return r.FileEditingContextRows.GetOutEdges(id)
}
func (r *editingContextReader) GetNodesByIDs(ids []string) map[string]*Node {
return r.FileEditingContextRows.GetNodesByIDs(ids)
}
func (r *editingContextReader) GetOutEdgesByNodeIDs(ids []string) map[string][]*Edge {
return r.FileEditingContextRows.GetOutEdgesByNodeIDs(ids)
}
func (r *editingContextReader) GetInEdgesByNodeIDs(ids []string) map[string][]*Edge {
return r.FileEditingContextRows.GetInEdgesByNodeIDs(ids)
}

// Keep durable incoming reads batched without advertising the unrelated
// OverlayLayerProjectionReader scans on the narrow borrowed layer.
type editingContextLayerIncoming interface {
FileEditingContextInEdgesByNodeIDs([]string) map[string][]*Edge
}
type editingContextView struct{ *OverlaidView }

func (v *editingContextView) GetInEdgesByNodeIDs(ids []string) map[string][]*Edge {
layer, ok := v.layer.(editingContextLayerIncoming)
if !ok {
return v.OverlaidView.GetInEdgesByNodeIDs(ids)
}
out := make(map[string][]*Edge, len(ids))
if v.base != nil {
for id, edges := range v.base.GetInEdgesByNodeIDs(ids) {
for _, edge := range edges {
if v.baseEdgeVisible(edge) {
out[id] = append(out[id], edge)
}
}
}
}
for id, edges := range layer.FileEditingContextInEdgesByNodeIDs(ids) {
out[id] = append(out[id], edges...)
}
return out
}
43 changes: 43 additions & 0 deletions internal/graph/file_editing_context_context_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package graph

import (
"context"
"testing"

"github.com/stretchr/testify/require"
)

// The old contextual node capability must not be mistaken for a safe bundle
// layer: OverlaidView's legacy batch refetch still calls layer.NodeByID.
type editingContextUnsafeLayer struct{ OverlayLayerReader }

func (l *editingContextUnsafeLayer) NodeByID(string) *Node { panic("contextless physical node lookup") }
func (l *editingContextUnsafeLayer) GetNodesByIDsContext(context.Context, []string) (map[string]*Node, error) {
return nil, nil
}

func TestEditingContextScopeRejectsContextualLookingLegacyLayer(t *testing.T) {
layer := NewOverlayLayer()
layer.MarkFile("a.go", false)
view := NewOverlaidViewWithLayer(New(), &editingContextUnsafeLayer{layer})
called := false
err := WithFileEditingContextReader(t.Context(), view, func(context.Context, FileEditingContextRows) error { called = true; return nil })
require.ErrorIs(t, err, ErrFileEditingContextUnsupported)
require.False(t, called)
}

func TestEditingContextScopeMemoryOwnershipParity(t *testing.T) {
base := New()
base.AddNode(&Node{ID: "a.go::f", Kind: KindFunction, FilePath: "a.go", Meta: map[string]any{"signature": "base"}})
base.AddNode(&Node{ID: "b.go::g", Kind: KindFunction, FilePath: "b.go", Meta: map[string]any{"full": "neighbor"}})
base.AddEdge(&Edge{From: "b.go::g", To: "a.go::f", Kind: EdgeCalls, FilePath: "b.go"})
layer := NewOverlayLayer()
layer.MarkFile("a.go", false)
layer.AddNode("a.go", &Node{ID: "a.go::f", Kind: KindFunction, FilePath: "a.go", Meta: map[string]any{"signature": "selected"}})
view := NewOverlaidView(base, layer)
want := FileEditingContextOf(view, "a.go", []NodeKind{KindFunction})
require.NoError(t, WithFileEditingContextReader(t.Context(), view, func(_ context.Context, rows FileEditingContextRows) error {
require.Equal(t, want, FileEditingContextOf(rows, "a.go", []NodeKind{KindFunction}))
return nil
}))
}
89 changes: 89 additions & 0 deletions internal/graph/overlay.go
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,95 @@ func (l *OverlayLayer) RebuildInEdges() {
}
}

// CarryBaseEdges returns provisional copies of the call edges base recorded in
// file that layerEdges, the file's re-parse, still make. A layer that covers a
// file hides every base edge recorded there, while the re-parse holds its calls
// as unresolved references until relations are rebuilt, so an edited function
// would otherwise lose its callees and drop out of its callees' callers. A base
// call is carried when the re-parse has an unresolved call from the same
// source to the target's name; the copy takes that call's line. Repeated calls
// pair up in line order, and a call the re-parse no longer makes is dropped.
func CarryBaseEdges(base Reader, file string, layerEdges []*Edge) []*Edge {
type site struct{ from, name string }
refs := make(map[site][]*Edge)
for _, e := range layerEdges {
if e == nil || e.Kind != EdgeCalls || !IsUnresolvedTarget(e.To) || IsFnValuePlaceholder(e.To) {
continue
}
key := site{e.From, unresolvedCallName(e.To)}
refs[key] = append(refs[key], e)
}
if base == nil || len(refs) == 0 {
return nil
}
for _, at := range refs {
sortEdgesByLine(at)
}
var ids []string
for _, n := range base.GetFileNodes(file) {
ids = append(ids, n.ID)
}
var recorded []*Edge
var targets []string
for _, edges := range base.GetOutEdgesByNodeIDs(ids) {
for _, e := range edges {
if e != nil && e.Kind == EdgeCalls && e.FilePath == file && !IsUnresolvedTarget(e.To) {
recorded = append(recorded, e)
targets = append(targets, e.To)
}
}
}
sortEdgesByLine(recorded)
names := base.GetNodesByIDs(targets)
used := make(map[site]int, len(refs))
var carried []*Edge
for _, e := range recorded {
target := names[e.To]
if target == nil {
continue
}
key := site{e.From, target.Name}
at := refs[key]
if used[key] >= len(at) {
continue
}
c := *e
c.Line = at[used[key]].Line
c.Provisional = true
used[key]++
carried = append(carried, &c)
}
return carried
}

// unresolvedCallName is the bare callee name of an unresolved call target:
// `unresolved::Name`, `unresolved::*.name` and qualified forms all name their
// last segment.
func unresolvedCallName(id string) string {
name := UnresolvedName(id)
if i := strings.LastIndex(name, "::"); i >= 0 {
name = name[i+2:]
}
if i := strings.LastIndexByte(name, '.'); i >= 0 {
name = name[i+1:]
}
return name
}

// sortEdgesByLine orders edges by source, line and target.
func sortEdgesByLine(edges []*Edge) {
sort.Slice(edges, func(i, j int) bool {
a, b := edges[i], edges[j]
if a.From != b.From {
return a.From < b.From
}
if a.Line != b.Line {
return a.Line < b.Line
}
return a.To < b.To
})
}

// OverlaidView composes an immutable base Reader with a per-session
// overlay layer. Every read path consults the layer first for paths
// the overlay covers; falls through to base otherwise. The base is
Expand Down
Loading
Loading