From ecfaeabf2a92e26c6a521d5fac404a0fff6263b6 Mon Sep 17 00:00:00 2001 From: Lukasz Kasprzak Date: Wed, 16 Sep 2026 01:34:45 +0200 Subject: milestone 1 review: claims span the run, explain's chain is opt-in and its own, overrides keyed by clean path, splice and enum guards --- internal/engine/match.go | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) (limited to 'internal/engine/match.go') diff --git a/internal/engine/match.go b/internal/engine/match.go index 591f686..59cea42 100644 --- a/internal/engine/match.go +++ b/internal/engine/match.go @@ -251,9 +251,12 @@ type Explanation struct { Excluded string // the first exclude that matches, which sets the file aside; "" when none does Rules []RuleTrace NoDelete string // why a delete from the matching rules would be skipped (spec §5.5); "" when it would not - // Chain is what the matching rules would do to the file: the same steps - // the directory's plan builds for it, placeholders expanded and - // conflicts resolved (GUI design §1.3). + // Chain is what the matching rules would do to this file alone: + // placeholders expanded and conflicts resolved against the disk, but + // not against the other files of a plan, which can still take a name + // this chain shows (the plan itself is where those are resolved). It is + // nil unless ExplainWithChain asked for it, and nil for a file the scan + // would skip or an exclude sets aside, which no rule acts on. Chain []plan.Step } @@ -263,6 +266,18 @@ type Explanation struct { // match if the file were looked at; a rule reached after an earlier // matching (stop) is recorded as Stopped, with no trace. func (e *Engine) Explain(ctx context.Context, path string) (*Explanation, error) { + return e.explain(ctx, path, false) +} + +// ExplainWithChain is Explain with Explanation.Chain filled in: the steps +// this file alone would get. Building them resolves conflicts against the +// disk, which can read files (a copy whose target holds the same bytes), so +// the command line's explain does not ask for it (plan 13 review F1). +func (e *Engine) ExplainWithChain(ctx context.Context, path string) (*Explanation, error) { + return e.explain(ctx, path, true) +} + +func (e *Engine) explain(ctx context.Context, path string, withChain bool) (*Explanation, error) { abs, err := filepath.Abs(path) if err != nil { return nil, err @@ -358,7 +373,7 @@ func (e *Engine) Explain(ctx context.Context, path string) (*Explanation, error) } var chain []plan.Step - if len(matched) > 0 { + if withChain && skip == "" && excluded == "" && len(matched) > 0 { in := []plan.Input{{File: sf, Rules: planRules(matched), NoDelete: noDel}} if built := plan.Build(d.Root, in, now, plan.OS{}, plan.NewClaims()); len(built) == 1 { chain = built[0].Steps -- cgit v1.3