feat: component attribution to telemetry (#78)#177
Conversation
Add ComponentsUsed and ComponentErrors fields to GenerationEvent so telemetry can answer "which component caused this failure?" and "how often does modal break?". This is the foundation for the component health dashboard (#79) and fix proposer (#80). - New attribution.go with AttributeErrors() and ComponentsFromUsage() - SQLite schema migration adds components_used/component_errors columns - Capture API gains RecordComponentsUsed() and AttributeComponentErrors() - gen.go wires component detection into telemetry pipeline - Full test coverage: attribution, round-trip persistence, backward compat Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
PR Review: feat: component attribution to telemetry (#78)Overall this is a solid, well-scoped feature with good test coverage and a thoughtful backward-compatible migration approach. A few issues worth addressing before merge. Issues1.
|
| Category | Item | Severity |
|---|---|---|
| Schema | schema.sql not updated for new columns |
Medium |
| Security | fmt.Sprintf in DDL without identifier validation |
Low |
| Correctness | toFieldData incomplete field copying |
Low (future risk) |
| Code quality | KnownComponents exported but unused |
Low |
| Correctness | ComponentsFromUsage includes non-Use bool fields |
Low |
| Style | Inconsistent alignment in events.go |
Trivial |
The most impactful fix is updating schema.sql to include the new columns so fresh installs don't go through the migration path unnecessarily.
There was a problem hiding this comment.
Pull request overview
Adds component attribution metadata to telemetry so generation failures can be tied back to specific UI components, enabling analysis of component-related breakages.
Changes:
- Extends
GenerationEventwithComponentsUsedandComponentErrors, and persists them in SQLite. - Introduces attribution utilities (
AttributeErrors,ComponentsFromUsage) plus unit/integration tests. - Wires component detection + error attribution into
GenResource()telemetry capture.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
internal/telemetry/events.go |
Adds new event fields for component usage and attributed errors. |
internal/telemetry/telemetry.go |
Adds capture APIs to record used components and compute attributed component errors. |
internal/telemetry/sqlite.go |
Adds runtime migration for new JSON/text columns; updates Save/Get/List scan/insert logic. |
internal/telemetry/attribution.go |
Implements matching logic for attributing errors to components + reflection-based component extraction. |
internal/telemetry/attribution_test.go |
Adds unit tests for attribution and usage-to-components conversion. |
internal/telemetry/telemetry_test.go |
Adds round-trip persistence test for new columns and extends noop coverage. |
commands/gen.go |
Detects components used by a resource and records/attributes them in telemetry. |
| // toFieldData converts parser.Fields to generator.FieldData for component detection. | ||
| func toFieldData(fields []parser.Field) []generator.FieldData { | ||
| fd := make([]generator.FieldData, len(fields)) | ||
| for i, f := range fields { | ||
| fd[i] = generator.FieldData{ | ||
| Name: f.Name, | ||
| GoType: f.GoType, | ||
| SQLType: f.SQLType, | ||
| IsSelect: f.IsSelect, | ||
| } | ||
| } |
There was a problem hiding this comment.
The helper toFieldData() duplicates the parser.Field → generator.FieldData mapping logic that already exists in the generator layer. Because it only maps a subset of fields, future changes to DetectUsedComponents (or FieldData) could silently desync telemetry detection from the actual generation behavior. Consider reusing a shared conversion function (e.g., moving the conversion into generator as an exported helper) or mapping all relevant parser.Field fields into generator.FieldData here.
| func TestCollector_BackwardCompat_NoComponentColumns(t *testing.T) { | ||
| // Events without component data should still work | ||
| store := openTestStore(t) | ||
| c := NewCollectorWithStore(store) | ||
| defer c.Close() | ||
|
|
||
| cap := c.StartCapture("gen view", nil) | ||
| cap.Complete(true, "") | ||
|
|
||
| ctx := context.Background() | ||
| event, err := store.Get(ctx, cap.Event().ID) | ||
| if err != nil { | ||
| t.Fatalf("get event: %v", err) | ||
| } | ||
| if event.ComponentsUsed != nil { | ||
| t.Errorf("expected nil ComponentsUsed for event without component data, got %v", event.ComponentsUsed) | ||
| } | ||
| if event.ComponentErrors != nil { | ||
| t.Errorf("expected nil ComponentErrors for event without component data, got %v", event.ComponentErrors) | ||
| } | ||
| } |
There was a problem hiding this comment.
TestCollector_BackwardCompat_NoComponentColumns (and its comment) doesn’t actually exercise a database that lacks the new columns: openTestStore() calls OpenSQLite(), which runs ensureSchema() and now always migrates the columns. Either rename this test to reflect what it verifies (events saved without component data), or change it to create an “old schema” DB first (without the columns) and then reopen/migrate to validate true backward compatibility.
| // KnownComponents is the canonical list of component package names. | ||
| var KnownComponents = []string{ | ||
| "accordion", "autocomplete", "breadcrumbs", "datatable", "datepicker", | ||
| "drawer", "dropdown", "menu", "modal", "popover", "progress", "rating", | ||
| "skeleton", "tabs", "tagsinput", "timeline", "timepicker", "toast", | ||
| "toggle", "tooltip", | ||
| } |
There was a problem hiding this comment.
KnownComponents is declared as a “canonical list” but is not referenced anywhere in the package. This creates an extra source of truth that can drift from the actual components/ directory / generator usage. Consider either removing it, making it unexported and using it for validation/filtering, or deriving it from an existing source.
| func (s *SQLiteStore) ensureSchema() error { | ||
| _, err := s.db.Exec(schemaSQL) | ||
| if err != nil { | ||
| return fmt.Errorf("create telemetry schema: %w", err) | ||
| } | ||
| return s.migrateComponentColumns() | ||
| } |
There was a problem hiding this comment.
ensureSchema() now relies on migrateComponentColumns() to add the new columns, but the embedded schema.sql still defines generation_events without components_used / component_errors. This means fresh databases will always require ALTER TABLEs at runtime and the schema file no longer reflects the current table definition. Consider updating internal/telemetry/schema.sql to include the new columns, while keeping the migration for existing DBs.
- Update schema.sql to include components_used/component_errors columns so fresh installs don't need ALTER TABLE migration - Add DDL identifier validation guard in migrateComponentColumns() - Remove unused KnownComponents exported var - Fix ComponentsFromUsage to skip non-"Use"-prefixed bool fields - Add comment on toFieldData explaining intentional field subset - Fix inconsistent struct alignment in events.go - Rename backward compat test to clarify what it verifies - Add comments on AttributeComponentErrors() call paths Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
PR Review: Component Attribution to Telemetry (#78)Overall this is a solid, well-tested feature addition. The backward-compatible migration, consistent noop pattern, and thorough test coverage are all strong. A few issues worth addressing before merge. Issues1. False-positive risk in
|
| Category | Status |
|---|---|
| Core logic | Correct |
| Backward compatibility | Migration handles existing DBs well |
| Test coverage | Good; a couple of edge cases missing |
| False-positive risk in message matching | Worth a fix or explicit test |
ComponentsFromUsage reflection design |
Consider explicit method over reflection |
| Alignment style change | Minor cosmetic inconsistency |
Items 1 and 2 are the most worth addressing before merge. Everything else is minor.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add test documenting that "toast." does not false-positive on "toaster." - Add test for ComponentsFromUsage ignoring non-Use-prefixed bool fields - Clarify AttributeComponentErrors comment in gen.go Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
PR Review: Component Attribution to TelemetryGood feature overall: solid test coverage, clean backward-compatible migration, and consistent noop handling. Issue: matchComponent message-matching false positiveFile: The With realistic component names (modal, toast, dropdown) this is unlikely in practice, but a test documenting the edge case — either accepting it or motivating a word-boundary fix — would strengthen the contract. Minor: nil slices stored as "null" TEXT, not SQL NULL
Minor: migrateComponentColumns runs on every openSince Corrections to an earlier review comment on this PROne previous review contains inaccuracies worth noting:
What looks good
The message-matching false positive is the only real item worth addressing before merge. |
Code Review: feat: component attribution to telemetry (#78)Overall this is a well-structured addition. The separation of concerns is clean (attribution logic isolated to Observations and Suggestions1. The column names come from a hardcoded literal slice defined in the same function body, so // Allowed columns — guards against future additions to the loop without
// a corresponding allowlist entry. ALTER TABLE cannot use parameters.2. It is currently called twice in 3. Message-based matching has a false-positive risk for short or common component names strings.Contains(msgLower, compLower+".")For current component names (modal, toast, dropdown) this is fine. But a component named 4. No direct test for the upgrade/migration path The round-trip tests exercise migration indirectly, but there is no test that:
This is the most likely failure scenario in the field (user upgrading from an older install). A dedicated test would be valuable. 5. The comment says "Only fields needed by DetectUsedComponents are mapped" but What is done well
SummaryNo blocking issues. Main asks: clarify the |
- Add dedicated migration upgrade test (old DB → new schema) - Clarify allowed map comment as guard against future additions - Document AttributeComponentErrors idempotency Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
PR Review: feat: component attribution to telemetry (#78)Note: This review corrects some inaccuracies from earlier comments on this PR and focuses on what's genuinely outstanding. What's actually correct (correcting prior review inaccuracies)Several earlier comments raised issues that don't exist in the diff:
One genuine issue: prefix false positive in message matchingFile: The check For example, if Suggested test (or a comment documenting the known limitation): func TestAttributeErrors_SuffixNoFalsePositive(t *testing.T) {
// "modal" must not match "premodal.init" (component is a suffix of a longer token)
errors := []GenerationError{{Phase: "runtime", Message: "premodal.init: failed"}}
result := AttributeErrors(errors, []string{"modal"})
if len(result) != 0 {
t.Fatalf("expected 0, got %d", len(result))
}
}If that test fails, a word-boundary guard fixes it: re := regexp.MustCompile(`(?:^|[^a-zA-Z0-9])` + regexp.QuoteMeta(compLower) + `\.`)
if re.MatchString(msgLower) { return comp }Minor: nil slices stored as
|
| Item | Severity |
|---|---|
| Prefix false positive in message matching (untested) | Low — unlikely with current components, worth documenting |
nil slices stored as "null" TEXT (undocumented) |
Trivial |
No blocking issues. Good to merge after adding the prefix false-positive test or a comment documenting the known limitation.
- Document known suffix false-positive in message matching (premodal vs modal) - Add comment about nil slices stored as "null" TEXT for DB query authors Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
PR Review: feat: component attribution to telemetry (#78)
SummaryWell-scoped feature with solid test coverage. The backward-compat migration is handled correctly. A few things worth addressing: Issues1.
|
The go get step runs after all auth files are generated (line 300+) and is purely a convenience for fetching dependencies. Making it non-fatal is correct for: - CI: lvt/components is a workspace sub-module with no proxy version - Offline users: they can run go mod tidy later - Tests: replace directives handle resolution independently Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
PR Review: feat: component attribution to telemetryOverall this is a well-structured addition with good test coverage, a backward-compatible migration, and clear comments. A few issues are worth addressing before merging. [HIGH] auth.go silently swallows a real error The diff changes a hard error into a printed warning: // Before
return fmt.Errorf("failed to update dependencies: %w\n%s", err, output)
// After
fmt.Fprintf(os.Stderr, "Warning: could not fetch some dependencies...\n%s\n", output)This is a significant, unannounced behavior change. If [MEDIUM] Known false positive in matchComponent is documented but not fixed
[MEDIUM] migrateComponentColumns allowlist check is unreachable dead code allowed := map[string]bool{"components_used": true, "component_errors": true}
for _, col := range []string{"components_used", "component_errors"} {
if !allowed[col] { // can never be true
return fmt.Errorf("unexpected column name %q", col)
}
[LOW] ComponentsFromUsage uses reflection where a type method would be simpler
[GOOD] JSON null vs SQL NULL handling The comment in [MINOR] AttributeComponentErrors called on every exit path manually Both call sites in [GOOD] Test quality The test suite is thorough — edge cases (nil, empty, pointer receivers, case-insensitivity), round-trip integration, and The |
Addresses Copilot review: toFieldData() in commands/gen.go duplicated the parser.Field → generator.FieldData conversion from resource.go and schema.go. Moved to a single FieldDataFromFields() in types.go. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
PR Review: feat: component attribution to telemetry (#78)Several reviews have already been left on this PR, some of which contain inaccuracies (e.g., claiming Issues1. Known false positive is asserted, not fixed (
// In matchComponent, replace:
strings.Contains(msgLower, compLower+".")
// With a positional check that the match is not preceded by a word character:
idx := strings.Index(msgLower, compLower+".")
idx != -1 && (idx == 0 || !isWordChar(msgLower[idx-1]))Current components ( 2. allowed := map[string]bool{"components_used": true, "component_errors": true}
for _, col := range []string{"components_used", "component_errors"} {
if !allowed[col] { // can never be true — same literals drive both
// Single source of truth drives iteration; guard is now reachable
cols := map[string]bool{"components_used": true, "component_errors": true}
for col := range cols { ... }Note: map iteration is non-deterministic in Go, so if order matters for the 3. The diff changes a hard fmt.Fprintf(os.Stderr, "Warning: could not fetch dependencies — run 'go mod tidy' in %s to resolve:\n%s\n", projectRoot, output)4.
5. Both call sites are correct today (mutually exclusive code paths). But any new exit path added to func (cap *Capture) Complete(success bool, validationJSON string) {
cap.AttributeComponentErrors() // attribute before persisting, regardless of exit path
// ...existing persist logic
}What looks good
Summary
Items 1 and 3 from the PR description are the most worth addressing before merge. |
- Add left-boundary guard in matchComponent to prevent false positives like "premodal.init" matching component "modal" - Update SuffixFalsePositive test to assert correct rejection + add BoundaryMatch test for valid matches - Remove dead-code allowed map in migrateComponentColumns, extract componentColumns var instead Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
PR Review: feat/component-attribution-telemetry - Summary of findings after reviewing all commits and the full diff. RESOLVED from prior reviews: schema.sql now has the new columns in base DDL; componentColumns var replaces the unreachable allowed-map guard; KnownComponents removed; FieldDataFromFields extracts the duplicated conversion; isWordChar boundary guard fixes the premodal false-positive. ITEM 1 (medium) - auth.go warning omits location: The non-fatal go-get change is correct in intent but the Fprintf warning does not include projectRoot so users do not know where to run go mod tidy. Add projectRoot to the format string. Also missing from PR description - worth one line in the summary since it is a user-visible behavior change. ITEM 2 (low) - RecordComponentsUsed should be SetComponentsUsed: RecordError and RecordFileGenerated append; RecordComponentsUsed replaces. The Record prefix implies accumulation. Rename to SetComponentsUsed to make the overwrite semantics obvious at call sites. ITEM 3 (low) - AttributeComponentErrors at each exit path is a footgun: Both call sites in gen.go are correct today but any new early-return in GenResource will silently skip attribution. Move the attribution call inside Complete so it is unconditional. AttributeComponentErrors can remain public for tests that inspect attribution mid-flight. DESIGN NOTE (no action): DetectUsedComponents runs before GenerateResource so ComponentsUsed is predictive, not observational. Acceptable for v1 but worth noting for future generator changes. WORKING WELL: pragma_table_info migration pattern, isWordChar boundary guard, comprehensive test suite (TestSQLiteStore_MigrationUpgrade is particularly solid), noop guards on both new Capture methods, null-TEXT storage comment, and FieldDataFromFields deduplication. Overall the feature is correct and well-tested. Items 1 and 3 are the highest priority before merge. |
Claude review: the warning omits projectRoot so users don't know where to run go mod tidy. Now prints the path for clarity. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
PR Review: feat: component attribution to telemetry (#78) Note: Several prior reviews on this PR contain inaccuracies. This review is based on the actual diff. What is correctly implemented (prior reviews were wrong about these):
Genuine issues [MEDIUM] auth.go behavior change is absent from PR description The diff changes a hard error into a printed warning in auth.go: Before: return fmt.Errorf("failed to update dependencies: %w\n%s", err, output) This is a user-visible behavior change: auth generation now appears to succeed even when go get fails, with the breakage only surfacing at build time. If intentional (CI, offline, workspace sub-modules), it should be called out explicitly in the PR description. [LOW] RecordComponentsUsed naming conflicts with the Record* accumulation convention RecordError and RecordFileGenerated append. RecordComponentsUsed replaces on repeated calls. A caller who calls it twice expecting accumulation silently loses the first call. Renaming to SetComponentsUsed would make the overwrite semantics unambiguous at call sites. [LOW] AttributeComponentErrors() placement is a future footgun Both call sites in gen.go are on mutually exclusive paths -- correct today. But any new early-return added to GenResource must remember to call AttributeComponentErrors() before Complete() or attribution silently goes missing. Moving the attribution call inside Complete() would eliminate this requirement. What looks good
Summary
The auth.go item is the most important to address before merge. The others are clean-up worth doing but not blocking. |
* feat: add component attribution to telemetry (#78) Add ComponentsUsed and ComponentErrors fields to GenerationEvent so telemetry can answer "which component caused this failure?" and "how often does modal break?". This is the foundation for the component health dashboard (#79) and fix proposer (#80). - New attribution.go with AttributeErrors() and ComponentsFromUsage() - SQLite schema migration adds components_used/component_errors columns - Capture API gains RecordComponentsUsed() and AttributeComponentErrors() - gen.go wires component detection into telemetry pipeline - Full test coverage: attribution, round-trip persistence, backward compat Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: component health dashboard and component-aware fix proposals (#79, #80) Add `lvt evolution components` subcommand showing per-component health metrics (usage count, success rate, top errors) with warning markers for components below 90% success rate. Add ClassifyError/ClassifyFix to categorize errors by origin (component/kit/generated/unknown). The `propose` command now shows a Location line for each fix to help users understand where to look. - evolutionComponents() aggregates telemetry by component with --days flag - component_proposer.go classifies file paths into location categories - evolutionPropose() enhanced with location classification per fix - Full test coverage for all classification cases Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: enhance component independence CI checks (#81) Add cross-module import test to the components-independence workflow that creates an external Go module and verifies it can import and build against components without requiring the parent lvt module. Also adds independence badge and documentation section to components/README.md explaining the guarantee and how external projects can use components. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: address bot review comments on PR #177 - Update schema.sql to include components_used/component_errors columns so fresh installs don't need ALTER TABLE migration - Add DDL identifier validation guard in migrateComponentColumns() - Remove unused KnownComponents exported var - Fix ComponentsFromUsage to skip non-"Use"-prefixed bool fields - Add comment on toFieldData explaining intentional field subset - Fix inconsistent struct alignment in events.go - Rename backward compat test to clarify what it verifies - Add comments on AttributeComponentErrors() call paths Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: address bot review comments on PR #178 - Fix app/ false positive: use prefix/segment check instead of Contains to avoid matching "webapp/", "myapp/", etc. - Check kit paths before component paths to avoid misclassifying internal/kits/.../components/ as top-level components - Fix Path field comment: "original path" not "normalized" - Fix help text alignment for components subcommand - Add comment about event-level success attribution trade-off - Expand test coverage: kit components/ subdir, app/ false positives, bare component file, empty file, all ClassifyFix outcomes Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: address bot review comments on CI workflow and README - Use root components package with Version() instead of 3 specific packages - Fix heredoc indentation to column 0 for valid Go syntax - Add GOWORK=off to go mod tidy and go build steps - Use consistent full import paths in README documentation Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: correct go fmt alignment in events.go struct Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: address second-round review comments - Add test documenting that "toast." does not false-positive on "toaster." - Add test for ComponentsFromUsage ignoring non-Use-prefixed bool fields - Clarify AttributeComponentErrors comment in gen.go Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: address second-round review comments on dashboard and proposer - Extract magic number 90 as warnThresholdPct constant - Truncate long component names in dashboard table output - Guard classifyPath against wildcard * in component names - Make TestClassifyFix unconditionally assert Component field - Add wildcard glob test case for classifyPath Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: use valid module path and add go run smoke test - Use example.com/test-import instead of bare test-import - Add GOWORK=off go run . to verify execution, not just compilation Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: address third-round review comments - Add dedicated migration upgrade test (old DB → new schema) - Clarify allowed map comment as guard against future additions - Document AttributeComponentErrors idempotency Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: address third-round review comments on dashboard - Add test for /app/ in middle of path (generated classification) - Skip components with zero usage in dashboard table - Simplify rate calculation now that usage > 0 is guaranteed Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: add suffix false-positive test and null storage comment - Document known suffix false-positive in message matching (premodal vs modal) - Add comment about nil slices stored as "null" TEXT for DB query authors Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: address fourth-round review comments - Skip zero-usage components from errors section too - Add warning on invalid --days value - Use min() builtin instead of manual comparison Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: document lowercase Component field and surface hidden components - Add lowercase normalization note to ErrorLocation.Component - Print count of components with errors but no usage in dashboard Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: make go get failure non-fatal in GenerateAuth The go get step runs after all auth files are generated (line 300+) and is purely a convenience for fetching dependencies. Making it non-fatal is correct for: - CI: lvt/components is a workspace sub-module with no proxy version - Offline users: they can run go mod tidy later - Tests: replace directives handle resolution independently Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: extract shared FieldDataFromFields helper to reduce duplication Addresses Copilot review: toFieldData() in commands/gen.go duplicated the parser.Field → generator.FieldData conversion from resource.go and schema.go. Moved to a single FieldDataFromFields() in types.go. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: address bot review comments on component proposer - Tighten classifyPath to use segment-aware matching, preventing false positives from paths like "custom_components/" (Copilot + Claude) - Normalize backslash paths for cross-platform consistency (Copilot) - Add tests for false-positive prevention and Windows path normalization - Add TestEvolution_Components for the new subcommand (Copilot) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: clarify import path documentation in components README Copilot noted the doc should explicitly state these are fully-qualified import paths to avoid confusion with short-form references. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: address second-round Claude review comments - Add left-boundary guard in matchComponent to prevent false positives like "premodal.init" matching component "modal" - Update SuffixFalsePositive test to assert correct rejection + add BoundaryMatch test for valid matches - Remove dead-code allowed map in migrateComponentColumns, extract componentColumns var instead Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: correct TrimSuffix ordering for .go.tmpl files Strip .tmpl before .go so "components/modal.go.tmpl" correctly yields component name "modal" instead of "modal.go". Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: include project path in go get warning message Claude review: the warning omits projectRoot so users don't know where to run go mod tidy. Now prints the path for clarity. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Summary
ComponentsUsedandComponentErrorsfields toGenerationEventfor attributing generation failures to specific UI componentsAttributeErrors()scans error file paths and messages to match componentsComponentsFromUsage()convertsComponentUsagestruct to[]stringvia reflectionGenResource()telemetry pipeline — components detected before generation, errors attributed before completionCloses #78
Test plan
AttributeErrorswith file path matchingAttributeErrorswith error message matchingComponentsFromUsagewith various combosgo build ./...🤖 Generated with Claude Code