Skip to content

Commit 63b5b72

Browse files
docs(parser): clarify provider facade invariants
The provider facade contract has to be understandable from the Go package itself because future provider migrations will implement against these types, not just the design document. Ambiguous parse error boundaries or source identity fields would let providers diverge in skip-cache, retry, and persisted lookup behavior even if they compile against the same interface. This keeps the runtime surface unchanged while making whole-source errors, partial multi-session outcomes, persisted source identity, and capability/default-method expectations explicit at the interface layer.
1 parent 42708dd commit 63b5b72

3 files changed

Lines changed: 89 additions & 6 deletions

File tree

internal/parser/capabilities.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ const (
1313
)
1414

1515
// Capabilities groups provider source mechanics and parsed-content features.
16+
// Capabilities are declarative: a concrete provider that reports Supported must
17+
// implement the matching behavior rather than relying on ProviderBase defaults.
18+
// Callers may still invoke optional methods and handle their no-op or typed
19+
// unsupported results, but scheduling and validation should trust this
20+
// declaration once a provider has migrated off the legacy adapter.
1621
type Capabilities struct {
1722
Source SourceCapabilities
1823
Content ContentCapabilities

internal/parser/provider.go

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,11 @@ type Provider interface {
7171
FindSource(context.Context, FindSourceRequest) (SourceRef, bool, error)
7272
Fingerprint(context.Context, SourceRef) (SourceFingerprint, error)
7373

74+
// Parse returns a normalized outcome for one logical source. A non-nil
75+
// error is a whole-source failure, including context cancellation; callers
76+
// must ignore the returned ParseOutcome. Partial multi-session success is
77+
// represented by a nil error with successful Results plus SourceErrors for
78+
// isolated per-session failures.
7479
Parse(context.Context, ParseRequest) (ParseOutcome, error)
7580
ParseIncremental(
7681
context.Context,
@@ -139,12 +144,24 @@ func (b ProviderBase) unsupported(feature string) error {
139144

140145
// SourceRef is the engine-visible handle for provider-owned source data.
141146
type SourceRef struct {
142-
Provider AgentType
143-
Key string
144-
DisplayPath string
147+
// Provider identifies the provider that created this source and must match
148+
// the provider instance used for subsequent operations.
149+
Provider AgentType
150+
// Key is stable within the provider across process restarts. It is suitable
151+
// for dedupe and diagnostics, but not necessarily for DB freshness checks.
152+
Key string
153+
// DisplayPath is human-readable and may be a virtual path.
154+
DisplayPath string
155+
// FingerprintKey is the persisted lookup key for skip-cache and parser data
156+
// version checks. Migrated providers should keep it compatible with legacy
157+
// file_path values whenever practical.
145158
FingerprintKey string
146-
ProjectHint string
147-
Opaque any
159+
// ProjectHint is advisory metadata for UI grouping and may be empty.
160+
ProjectHint string
161+
// Opaque is provider-owned in-memory state. The engine must not persist,
162+
// compare, inspect, or log it, and providers must not require it for lookup
163+
// from persisted rows.
164+
Opaque any
148165
}
149166

150167
// WatchPlan describes provider-owned filesystem watch roots.
@@ -196,7 +213,8 @@ type ParseRequest struct {
196213
ForceParse bool
197214
}
198215

199-
// ParseOutcome is the full-parse provider output.
216+
// ParseOutcome is the full-parse provider output. It is meaningful only when
217+
// Provider.Parse returns a nil error.
200218
type ParseOutcome struct {
201219
Results []ParseResultOutcome
202220
ExcludedSessionIDs []string
@@ -215,6 +233,8 @@ type ParseResultOutcome struct {
215233
}
216234

217235
// SourceError reports a per-session parse failure from a multi-session source.
236+
// Providers use the Parse error return instead when a failure cannot be
237+
// isolated to a persisted full session ID.
218238
type SourceError struct {
219239
SourceKey string
220240
DisplayPath string

internal/parser/provider_test.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,64 @@ func TestProviderRegistryMirrorsAgentRegistry(t *testing.T) {
148148
}
149149
}
150150

151+
func TestLegacyProviderCapabilitiesMatchBaseDefaults(t *testing.T) {
152+
provider, ok := NewProvider(AgentCodex, ProviderConfig{
153+
Roots: []string{t.TempDir()},
154+
Machine: "devbox",
155+
})
156+
require.True(t, ok)
157+
require.NotNil(t, provider)
158+
159+
assert.Equal(t, Capabilities{}, provider.Capabilities())
160+
161+
ctx := context.Background()
162+
discovered, err := provider.Discover(ctx)
163+
require.NoError(t, err)
164+
assert.Empty(t, discovered)
165+
166+
plan, err := provider.WatchPlan(ctx)
167+
require.NoError(t, err)
168+
assert.Empty(t, plan.Roots)
169+
170+
changed, err := provider.SourcesForChangedPath(ctx, ChangedPathRequest{
171+
Path: "/tmp/session.jsonl",
172+
EventKind: "write",
173+
WatchRoot: "/tmp",
174+
})
175+
require.NoError(t, err)
176+
assert.Empty(t, changed)
177+
178+
source, found, err := provider.FindSource(ctx, FindSourceRequest{
179+
RawSessionID: "session",
180+
FullSessionID: "codex:session",
181+
StoredFilePath: "/tmp/session.jsonl",
182+
FingerprintKey: "/tmp/session.jsonl",
183+
})
184+
require.NoError(t, err)
185+
assert.False(t, found)
186+
assert.Empty(t, source)
187+
188+
_, err = provider.Fingerprint(ctx, SourceRef{
189+
Provider: AgentCodex,
190+
Key: "session",
191+
DisplayPath: "/tmp/session.jsonl",
192+
FingerprintKey: "/tmp/session.jsonl",
193+
})
194+
require.Error(t, err)
195+
assert.True(t, errors.Is(err, ErrUnsupportedProviderFeature))
196+
197+
incremental, status, err := provider.ParseIncremental(ctx, IncrementalRequest{
198+
Source: SourceRef{Provider: AgentCodex, Key: "session"},
199+
Fingerprint: SourceFingerprint{Key: "/tmp/session.jsonl"},
200+
SessionID: "codex:session",
201+
StartOrdinal: 1,
202+
Machine: "devbox",
203+
})
204+
require.NoError(t, err)
205+
assert.Equal(t, IncrementalUnsupported, status)
206+
assert.Empty(t, incremental)
207+
}
208+
151209
func TestProviderFactoryLookupAndConfigSnapshot(t *testing.T) {
152210
cfg := ProviderConfig{
153211
Roots: []string{"/tmp/one", "/tmp/two"},

0 commit comments

Comments
 (0)