Skip to content

Commit 9562f84

Browse files
feat: send previousDomains on full refresh to stabilize domain names (#111)
* feat: send previousDomains on full refresh to stabilize domain names When Generate runs with --force and a prior shards.json cache exists, extract domain names + subdomain counts and pass them as the previousDomains query param. The API (v0.12.0) seeds the LLM prompt to reuse those names where the same groupings still apply. Tested on Directus (17,877 nodes) against production: - Run 1 (fresh): ArtificialIntelligence, DataModel, CoreServices, ServerInfrastucture, CliCommands, DirectusApp - Run 2 (seeded): 83% name reuse (5/6 identical, 1 typo corrected by LLM: ServerInfrastucture → ServerInfrastructure) Closes #110 * fix: goimports alignment
1 parent af77745 commit 9562f84

File tree

4 files changed

+36
-6
lines changed

4 files changed

+36
-6
lines changed

internal/analyze/handler.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ func GetGraph(ctx context.Context, cfg *config.Config, dir string, force bool) (
7373

7474
client := api.New(cfg)
7575
spin = ui.Start("Uploading and analyzing repository…")
76-
ir, err := client.AnalyzeShards(ctx, zipPath, "analyze-"+hash[:16])
76+
ir, err := client.AnalyzeShards(ctx, zipPath, "analyze-"+hash[:16], nil)
7777
spin.Stop()
7878
if err != nil {
7979
return nil, hash, err

internal/api/client.go

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"io"
99
"mime/multipart"
1010
"net/http"
11+
"net/url"
1112
"os"
1213
"path/filepath"
1314
"time"
@@ -115,11 +116,26 @@ func (c *Client) pollLoop(ctx context.Context, post func() (*JobResponse, error)
115116
return job, nil
116117
}
117118

119+
// PreviousDomain holds domain name + subdomain count for seeding the LLM prompt.
120+
type PreviousDomain struct {
121+
Name string `json:"name"`
122+
SubdomainCount int `json:"subdomainCount"`
123+
}
124+
118125
// AnalyzeShards uploads a repository ZIP and runs the full analysis pipeline,
119126
// returning the complete ShardIR response with full Node/Relationship data
120127
// required for sidecar rendering (IDs, labels, properties preserved).
121-
func (c *Client) AnalyzeShards(ctx context.Context, zipPath, idempotencyKey string) (*ShardIR, error) {
122-
job, err := c.pollUntilComplete(ctx, zipPath, idempotencyKey)
128+
// If previousDomains is non-nil, passes them as a query param to seed domain names.
129+
func (c *Client) AnalyzeShards(ctx context.Context, zipPath, idempotencyKey string, previousDomains []PreviousDomain) (*ShardIR, error) {
130+
endpoint := analyzeEndpoint
131+
if len(previousDomains) > 0 {
132+
pd, err := json.Marshal(previousDomains)
133+
if err == nil {
134+
endpoint += "?previousDomains=" + url.QueryEscape(string(pd))
135+
}
136+
}
137+
post := func() (*JobResponse, error) { return c.postZipTo(ctx, zipPath, idempotencyKey, endpoint) }
138+
job, err := c.pollLoop(ctx, post)
123139
if err != nil {
124140
return nil, err
125141
}

internal/shards/daemon.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ func (d *Daemon) fullGenerate(ctx context.Context) error {
213213
}
214214
defer os.Remove(zipPath)
215215

216-
ir, err := d.client.AnalyzeShards(ctx, zipPath, idemKey)
216+
ir, err := d.client.AnalyzeShards(ctx, zipPath, idemKey, nil)
217217
if err != nil {
218218
return err
219219
}
@@ -251,7 +251,7 @@ func (d *Daemon) incrementalUpdate(ctx context.Context, changedFiles []string) {
251251
}
252252
defer os.Remove(zipPath)
253253

254-
ir, err := d.client.AnalyzeShards(ctx, zipPath, "incremental-"+idemKey[:8])
254+
ir, err := d.client.AnalyzeShards(ctx, zipPath, "incremental-"+idemKey[:8], nil)
255255
if err != nil {
256256
d.logf("Incremental API error: %v", err)
257257
return

internal/shards/handler.go

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,11 +93,25 @@ func Generate(ctx context.Context, cfg *config.Config, dir string, opts Generate
9393
}
9494
defer os.Remove(zipPath)
9595

96+
// Read previous domains from cache for LLM seeding (stabilizes names across refreshes)
97+
var prevDomains []api.PreviousDomain
98+
if data, readErr := os.ReadFile(cacheFile); readErr == nil {
99+
var prev api.ShardIR
100+
if json.Unmarshal(data, &prev) == nil && len(prev.Domains) > 0 {
101+
for _, d := range prev.Domains {
102+
prevDomains = append(prevDomains, api.PreviousDomain{
103+
Name: d.Name,
104+
SubdomainCount: len(d.Subdomains),
105+
})
106+
}
107+
}
108+
}
109+
96110
client := api.New(cfg)
97111
idemKey := newUUID()
98112

99113
spin = ui.Start("Uploading and analyzing repository…")
100-
ir, err := client.AnalyzeShards(ctx, zipPath, "shards-"+idemKey[:8])
114+
ir, err := client.AnalyzeShards(ctx, zipPath, "shards-"+idemKey[:8], prevDomains)
101115
spin.Stop()
102116
if err != nil {
103117
return err

0 commit comments

Comments
 (0)