Skip to content

feat(cli): integration family members are components under their own names - #7674

Merged
josephfarina merged 3 commits into
mainfrom
josephfarina/doc-names-family-members
Oct 18, 2026
Merged

josephfarina merged 3 commits into
mainfrom
josephfarina/doc-names-family-members

Conversation

@josephfarina

@josephfarina josephfarina commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor

User need

A family doc lists several components in components, and the component-family guide already requires the module named by its import to export every full entry. Yet only the doc's own component is reachable: AcmeTab in an AcmeTabs family doc is not in the list, component AcmeTab fails with ERR_UNKNOWN_COMPONENT, search never shows it, and swizzle AcmeTab cannot copy it.

Problem and solution fit

Each full entry a family doc lists in components becomes a component under its own name when the module the doc's import names exports it. It follows #7659's owner rule: a member holds its name only because a doc records it, so it gives way on an exact unscoped lookup to Core and to any doc named after its file, and --package still reaches it.

  • The module: the doc's import, else the subpath its directory publishes, read through the package's exports. A package without exports resolves its bare name through main, then index. When the package directory is known but the import resolves to no file, the doc lists no members; there is no fallback to the same-stem file.
  • The source: the .tsx file in the family doc's folder, or below it, that declares the member: the one the family's own file or the imported module reaches, else the one in that folder that declares the name, as when the import names built output. A bundle (dist/index.mjs) or a file outside the folder is never a member's source; a member only such a file declares is still listed, with no source, so --source and swizzle answer ERR_NO_SOURCE for it. It is valid: only a doc's own component needs its same-stem file.
  • The name: static PascalCase, read from a components field written out or as a shorthand, not in hiddenComponents, not the doc's file name or the export it is recorded under, and not taken: every doc's file name (hidden docs included), a Core name the package replaces, or an earlier claim. An entry is full when it has more than name, including computed fields and spreads, and a components value held by a binding is read.
  • A family doc without its own same-stem source still lists the members its import exports.

component AcmeTab and --props show the member's own entry (description, props, examples) with the family's import, the way a Core sub-component's detail does, including a member that shares the family doc's own name. Every member's parentDoc is the name the family doc opens under (its file name, or the export it is recorded under). Search indexes a member from its own entry. A member never carries the family's replaces. A family doc that fails to load is reported once, not once per member, by integration verify and the contribution inventory. integration add component reads the import the way discovery does: it refuses a name discovery records and plans one it does not.

Current specification

The current record architecture:cli-surface INV24, with the details in spec:AST-039 FR4 (both from #7658, merged as c992783): discovery records each full entry a descriptor lists in components under its own name when the module the descriptor imports exports it, and a name recorded only this way never takes an unscoped lookup that Core, a legacy docs package, or a component named after its source answers.

Public delta and caller burden

  • Before: astryx component AcmeTab exits 1 with ERR_UNKNOWN_COMPONENT. After: it prints AcmeTab's own entry with import: @acme/widgets/tabs, and component AcmeTab --props returns its props.
  • A member named like a Core component (Dialog) or a Core sub-component (ListItem) leaves the bare name to Core on every surface. --package @acme/widgets reaches the member, and search shows it with that command.
  • Authors need nothing new: the guide already asks the import to export every full entry. The component-family guide now states the limits above, including that a full entry the module does not export is not listed and integration verify does not report it. When the import names output the pack lifecycle builds (such as dist), the members are listed once that output exists, and integration verify compares every import family's members as local discovery lists them after the pack, so a clean checkout, a stale build, and an incremental build that leaves the imported file untouched all pass.
  • The authoring guides now cover what this PR and feat(cli): a component doc can name a differently named export of the file beside it #7659 support. Add a component gains a section on documenting a component the package already has: name the doc after its source file (acme-gallery.doc.mjs beside acme-gallery.tsx, kebab case included) and set name to the export. Single component, Resolve the import, Check an integration, Troubleshooting and Versioning, and the ComponentDoc components field, say what integration verify checks about the export (a type-only export does not count), which messages a doc that still names its file produces, how a name Core keeps is reached with --package, and what an app on an older CLI sees.
  • JSON shapes are unchanged. Changeset: patch, [feat].

Design and alternatives

  • foundation/discovery/component-discovery.mjs: familyMembers reads a family doc's full entries, resolves the module, and keeps each member the module exports, with its source from the family folder (folderSourceFor when the import's chain reaches no .tsx file). integrationMemberEntry gives a member's entry, and a doc's own record is decided by its identity, never by a lookup in components.
  • api/component/_adapter.mjs: scopeIntegrationMember scopes detail to the member's entry. When the doc a long-lived process loaded has no entry for a member the files now list, detail fails with ERR_UNKNOWN_COMPONENT instead of answering with the family.
  • api/search/search.mjs: indexes a member from its own entry and decides member or own from the files, so a .doc.ts family under node_modules keeps its members.
  • api/integration/pack-check.mjs and foundation/integrations/contribution-inventory.mjs: load each doc once. integration verify compares each import family's members as listed after the pack.
  • api/integration/add-contribution.mjs: passes the loaded integration so names follow discovery.

Rejected: making components entries name-only pointers that each need their own doc (forces a doc per member, which the family guide exists to avoid); listing members from the same-stem file when the import cannot be resolved (the list would name components apps cannot import).

Evidence

  • On a real 32-doc integration package with five family docs (measured on the first revision of this change), eight members the import exports become reachable: each lists, opens with its own entry, searches first by its name, and swizzles; integration verify is packable with all 40 components.
  • The cross-surface matrix from feat(cli): a component doc can name a differently named export of the file beside it #7659 ran with the member cases (a member named like a Core component and a Core sub-component, a doc listing its own name, a package without exports, a member declared only in a bundle, a withdrawn family, a binding-held list, a .doc.ts family, a family doc the loader rejects): every check passes, every surface agrees on each member's owner, and nothing is reported twice.

Scope

  • One capability is added: family members are components under their own names.
  • Unrelated fixes, cleanup, and policy changes were removed or split.
  • Consumer docs, focused tests, and migration evidence ship with the feature.
  • Public text and artifacts contain no internal Meta context.

Testing

  • Size: 23 files, 1,688 authored lines, the guide updates included.
  • Every new test fails without its fix:
    • component-discovery.export-names.test.mjs: members from main and none from an unresolvable import; members listed through a shorthand components property; a source in the family folder, never a bundle or the package root, even for a family doc at the package root; a member's source found in the family folder when the import names built output; a member only a bundle, the package root or another folder declares, listed with no source and valid; the members a family without its own source imports; a binding-held list and computed entries; the doc's own name as a member with replaces declared once; hidden-doc and replacement names taken.
    • integration-export-name.test.mjs: the member variant of the Core-name test, search command included; a member that shares its family doc's own name opens as that member, with its own props, and a sibling member's parentDoc opens the family; a member named like a Core sub-component stays unknown to swizzle; a stale loaded family doc fails instead of answering with the family; a .doc.ts family member under the real CLI.
    • add-contribution.component-names.test.mjs: plans a name the family lists but its import does not export, and refuses a member built output exports.
    • pack-check.test.mjs and component-replacement.test.mjs: members checked against the imported module; members read from output the pack lifecycle builds, from a clean checkout, a stale build missing a member, and a stale build still exporting one, each reporting matching local and packed inventories; members built output re-exports from compiled files, from a clean checkout and from an incremental build that leaves the imported file untouched; a member another folder declares, which has no source, passes; a rejected family doc reported once; a family's replaces stays with the family.
  • Static gates pass as in feat(cli): a component doc can name a differently named export of the file beside it #7659. Targeted suites (discovery, component, integration, integrations, search, swizzle, gap-report, doc compiler, theme): 96 files, 1,961 tests pass. Full CLI suite on this head: 6,388 passed, 0 failed; the strict typecheck reports only the two unbuilt @astryxdesign/theme-neutral/built errors.

@vercel

vercel Bot commented Oct 18, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
astryx Ready Ready Preview Oct 18, 2026 9:12pm UTC

Request Review

@astracat-bot

astracat-bot Bot commented Oct 18, 2026 •

Copy link
Copy Markdown

AI review status for this pull request.

Review status Updated
🟢 Reviewed (for maintainers only) Oct 18, 2026, 9:43 PM UTC

@github-actions

github-actions Bot commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor

PR Analysis Report

📚 Storybook Preview

View Storybook for this PR

🧪 Sandbox Preview

View Sandbox for this PR

No new or modified components detected.

Bundle Size Summary

No component packages changed.

Accessibility Audit

Status: No accessibility violations detected.

Visual Regression

40 of 478 shot(s) changed.

A change here is a question, not a failure: check whether the after is the
picture you intended. Record that review on the PR. Baseline maintenance is an
explicit dispatch of CI; this report never rewrites the baseline or adds a release gate.

component story theme mode pixels
Selector Indicator Space Bottom Sheet Narrow End RTL neutral light 754,077
Selector Indicator Space Bottom Sheet Wide Start neutral light 740,188
Chat Full AI Chat probe light 230,823
Chat Full AI Chat probe dark 229,805
RichTextEditor Markdown parity: side by side probe dark 94,866
RichTextEditor Markdown parity: side by side probe light 89,762
Collapsible Dividers probe dark 66,445
Collapsible Dividers probe light 66,445
Chat Default neutral dark 36,304
Chat Default neutral light 35,767
Chat Empty State probe light 23,531
Chat Empty State probe dark 22,622
ChatAutoScroll Scroll Behavior Comparison neutral dark 15,378
ChatAutoScroll Scroll Behavior Comparison neutral light 14,107
Chat With Attachments probe light 13,406
Chat With Attachments probe dark 11,232
ProgressBar With Target Mark probe dark 7,895
ProgressBar With Target Mark probe light 7,895
Markdown Default neutral dark 7,573
Markdown Default neutral light 7,566

and 20 more.


Generated by PR Enrichment workflow | Storybook | Sandbox | View full report

@astracat-bot astracat-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approval is on hold until a maintainer settles the spec for this capability. No approved record on main makes family members components under their own names, and the member rule exists only in draft spec PR #7658 (spec:AST-039 FR4 and an addition to architecture:cli-surface INV24). A maintainer needs to approve that rule, identify another approved record that covers it, or decline it. Two fixes are needed either way:

  • When a family doc's own name is one of its members, component <that member> and --props return the whole family doc (every member's props and the family's replaces) instead of that member's own entry.
  • A family doc that writes components as a shorthand property (export default {..., components}) lists no members, because the quick components: text check requires a colon.

[Automated review]

Comment thread packages/cli/api/component/_adapter.mjs Outdated
);
}
const sub = scopeSubComponent(docs, dirName, coreDir);
if (!sub) return docs;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When the family doc's own name is this member (for example Chip.doc.mjs with name: 'AcmeChip' beside a Chip.tsx that also exports Chip), scopeSubComponent declines to scope, and this line returns the whole family doc. component AcmeChip then shows the family's replaces, and --props returns every member's props. Building the scoped doc from integrationMemberEntry(docs, record) here would keep a member scoped to its own entry.

const NAME_FIELD_RE = /(?:^|\n) {0,2}['"]?name['"]?\s*:\s*['"]([^'"\n]+)['"]/g;
// A `components:` field anywhere in the file: the quick check for a family doc,
// before anything parses it. A false match only costs the parse.
const MEMBERS_FIELD_RE = /\bcomponents['"]?\s*:/;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This check misses a shorthand property (export default {..., components}), so such a family doc lists no members even though staticExportObject resolves the binding. Matching \bcomponents\b here would cover it.

@josephfarina
josephfarina force-pushed the josephfarina/doc-names-family-members branch from 38fcb61 to f84ce11 Compare October 18, 2026 00:52
@josephfarina

Copy link
Copy Markdown
Contributor Author

Addressed the automated review in this push:

  • A member that shares its family doc's own name: detail and --props now scope a member from its own entry, rather than through Core's sub-component scoping, which declines when the names match. component AcmeChip for Chip.doc.mjs naming AcmeChip now shows that member's entry and props, not the whole family doc. Tested.
  • A shorthand components property: the quick check now matches components with or without a colon, so export default {..., components} lists its members. Tested.
  • Both tests fail without their fix. Size against feat(cli): a component doc can name a differently named export of the file beside it #7659: 1,194 authored lines.

@astracat-bot astracat-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approval is on hold until a maintainer settles the spec for this capability: no approved record on main makes family members components under their own names, and the member rule exists only in draft spec PR #7658 (spec:AST-039 FR4 and an addition to architecture:cli-surface INV24). A maintainer needs to approve that rule on main, identify another approved record that covers it, or decline it. The two fixes from the earlier review hold up on this head, but one small fix is still needed either way:

  • When a family doc keeps its file name while its name is one of its members (such as Chip.doc.mjs naming AcmeChip), a sibling member's parentDoc names AcmeChip, which opens that member instead of the family doc.

[Automated review]

Comment thread packages/cli/api/component/_adapter.mjs Outdated
Comment on lines +638 to +641
parentDoc:
docs.name === dirName && record.docPath
? docStem(record.docPath)
: docs.name,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When the family doc keeps its file name while its name is one of its members (for example Chip.doc.mjs with name: 'AcmeChip' beside a Chip.tsx that exports Chip, AcmeChip and AcmeChipIcon), this gives AcmeChipIcon a parentDoc of AcmeChip. component AcmeChip then opens that member rather than the family doc, while AcmeChip itself gets Chip. Naming the family by the name discovery records the doc under (its stem, or the export its name documents when it is recorded under that export) would give every member the same parent, one that opens the family doc.

@josephfarina
josephfarina force-pushed the josephfarina/doc-names-another-export branch from db4b024 to e75b79f Compare October 18, 2026 01:52
@josephfarina
josephfarina force-pushed the josephfarina/doc-names-family-members branch from 96f5bed to 01cc412 Compare October 18, 2026 01:52
@josephfarina

Copy link
Copy Markdown
Contributor Author

Addressed the automated review in 01cc412: every member's parentDoc is now the name the family doc opens under. That is its file name, or the export it is recorded under. A sibling of a member that shares the doc's own name therefore points at the family (component AcmeChipIcon reports parentDoc: "Overlays" in the test fixture). The assertion fails without the fix. Size against #7659: 1,225 authored lines.

@josephfarina
josephfarina force-pushed the josephfarina/doc-names-another-export branch from 61969eb to 7db5b0f Compare October 18, 2026 04:47
@josephfarina
josephfarina force-pushed the josephfarina/doc-names-family-members branch from 05eca4d to 4e51e99 Compare October 18, 2026 04:47
@josephfarina

Copy link
Copy Markdown
Contributor Author

Addressed in 4e51e99. For a family whose import file the pack lifecycle wrote, verify now compares that family's members as local discovery lists them after the pack, instead of excusing packed-only names. A stale build that still exports a member the new build drops no longer fails with identity_not_packed, and one that lacks a member the new build adds no longer fails with packed_identity_unexpected. Identity changes a lifecycle makes to any other doc are still caught. The pack-check case now runs from a clean checkout, a stale build missing a member, and a stale build still exporting one. The last fails without the fix.

@astracat-bot astracat-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approval is on hold until a maintainer settles the spec for this capability: no approved record on main makes family members components under their own names, and the member rule exists only in draft spec PR #7658 (spec:AST-039 FR4 and an addition to architecture:cli-surface INV24). A maintainer needs to approve that rule on main, identify another approved record that covers it, or decline it. The stale-build integration verify fix holds up, and one small fix is still needed either way:

  • For a family whose import the pack lifecycle builds, a passing integration verify --json compares the members listed after the pack but still reports contributions.local from before it, so the local and packed component lists disagree (for example ["AcmeTabs"] against ["AcmeTab", "AcmeTabs"] from a clean checkout); please report the compared list and assert that the two inventories match in the lifecycle pack-check case.

[Automated review]

}
issues.push(
...compareIdentities(
{...localIdentities, components: localComponents},

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This compares the members local discovery lists after the pack, but the result still returns contributions.local from before it (localIdentities, line 1500). From a clean checkout with a prepack-built dist, a passing run reports local.components as ["AcmeTabs"] against packed.components as ["AcmeTab", "AcmeTabs"], and when the tarball genuinely loses AcmeTab, the identity_not_packed issue names a member the local list omits. Returning {...localIdentities, components: localComponents} as contributions.local, and asserting that contributions.packed equals contributions.local in the lifecycle pack-check case, would keep the report consistent with what verify compared.

@josephfarina
josephfarina force-pushed the josephfarina/doc-names-family-members branch from 4e51e99 to bdb8bff Compare October 18, 2026 05:22
@josephfarina

Copy link
Copy Markdown
Contributor Author

Addressed in bdb8bff: the receipt now reports the local inventory that verify compared, so for a family whose import the pack lifecycle builds, contributions.local lists the members found after the pack. The lifecycle pack-check case asserts that the local and packed component lists match for each starting point, and all three fail without the fix.

@astracat-bot astracat-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approval is on hold until a maintainer settles the spec for this capability: no approved record on main makes family members components under their own names, and the member rule exists only in draft spec PR #7658 (spec:AST-039 FR4 and an addition to architecture:cli-surface INV24). A maintainer needs to approve that rule on main, identify another approved record that covers it, or decline it. The integration verify receipt fix holds up, and one small fix is still needed either way:

  • For a family doc at an integration's package root (components: '.'), a member that only the built bundle declares is listed with dist/index.mjs as its source, so --source prints the bundle and swizzle copies dist/, although the new guide says such a member is not listed.

[Automated review]

const exported = moduleExportSource(module, name);
if (exported == null) return [];
const sourcePath = [moduleExportSource(familySource, name), exported].find(
file => file != null && isWithin(folder, file),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When the family doc sits at the package root (an integration with components: '.'), folder is the package directory, so a member only the bundle declares gets dist/index.mjs as its source: it is listed, component <Member> --source prints the bundle, and swizzle copies index.mjs and index.mjs.map. The new guide says such a member is not listed. Keeping a bundle out of this search when the family folder contains it, with a discovery case for a root-level family doc, would match the guide; otherwise the guide should say that a bundle inside the family folder counts.

@josephfarina
josephfarina force-pushed the josephfarina/doc-names-family-members branch from bdb8bff to 216b867 Compare October 18, 2026 06:04
@josephfarina

Copy link
Copy Markdown
Contributor Author

Addressed in 216b867: a member's source must now be a .tsx file in the family's folder, the same rule a doc's own source follows. A bundle that only dist/index.mjs declares is never a member's source, even when the family doc sits at the package root (components: '.'). The member is not listed, as the guide says, so --source and swizzle never reach the bundle. The new test for a family at the package root fails without the fix. The guide now says "the .tsx file that declares it".

@astracat-bot astracat-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approval is on hold until a maintainer settles the spec for this capability: no approved record on main says that each full entry a family doc lists in components is a component under its own name, and that rule exists only in draft spec PR #7658 (spec:AST-039 FR4 and an addition to architecture:cli-surface INV24). A maintainer needs to approve that rule on main, identify another approved record that covers it, or decline it, and the decision should also cover how integration verify compares members of a family whose import the pack lifecycle builds. The bundle-source fix in this push holds up, and this review found nothing else to change.

[Automated review]

…names

Each full entry a family doc lists in `components` is a component under its
own name when the module the doc's import names exports it: the doc's
`import`, else the subpath its directory publishes, read through the package's
`exports`, or its `main` when it has none. An import the package cannot resolve
lists no members. The member's source is the file that declares it, reached
through the family's own file or the imported module, and it must sit in the
family doc's folder; a bundle or a package's root file is no member's source,
and a family doc without its own source lists none. Static PascalCase names,
not hidden, not the doc's stem or the export it is recorded under, and not a
name already taken (a file name, hidden docs included, or a Core name the
package replaces). A `components:` value held by a binding, and an entry with
computed fields, count.

Members follow the owner rule like export names. Component detail and --props
scope to the member's entry with the family's import, and fail rather than
answer with the family when the doc a long-lived process loaded has no entry
for it. Search indexes a member from its own entry, deciding member or own
from the files, not from whether its doc loads. A member never carries the
family's replaces; a family doc that fails to load is reported once (verify
and the contribution inventory load it once). `integration add component`
refuses a name discovery records and plans one it does not.
…and family members

Add a component gains a section for documenting a component the package
already has: name the doc after its source file, such as acme-gallery.doc.mjs
beside acme-gallery.tsx, and set name to the export apps import. The single
component, import, checks, troubleshooting and versioning guides, and the
ComponentDoc components field, now say what discovery and integration verify do
with a doc that names another export of its file and with family members, what
an app on an older CLI sees, and how a name Core or another owner keeps is
reached with --package.
@josephfarina
josephfarina force-pushed the josephfarina/doc-names-family-members branch from 216b867 to 86179ee Compare October 18, 2026 20:05
@josephfarina
josephfarina changed the base branch from josephfarina/doc-names-another-export to main October 18, 2026 20:05

@astracat-bot astracat-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes requested: the member rule now has current spec support, but discovery silently drops some members that the doc's import exports, which the spec says must be listed. When import names compiled or bundled output (for example a dist/list/index.js that re-exports ./row.js), a member declared in its own .tsx beside the family doc is never found unless the family's own file re-exports it, and a member re-exported from another folder is dropped too. In both cases integration verify still passes, and integration add component offers to create a second doc. Please look for the member's declaring .tsx in the family folder when the import's chain does not reach one, record or report the rest instead of dropping them (or get the spec amended if that condition is intended), add a test with compiled dist output, and align the family guide, the ComponentDoc text and the Changeset.

[Automated review]

Comment on lines +1080 to +1081
const sourcePath = [moduleExportSource(familySource, name), exported].find(
file => file != null && file.endsWith('.tsx') && isWithin(folder, file),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A member that the import exports is recorded only when one of these two routes reaches a .tsx inside the family folder. When import names compiled or bundled output, for example a dist/list/index.js that re-exports ./row.js, neither route reaches src/list/row.tsx. AcmeListRow is then silently not listed, integration verify passes, and integration add component AcmeListRow plans a second doc. INV24 in docs/architecture/cli-surface.md records every full entry the imported module exports. To match it, look for the .tsx in the family folder that exports the member when the chain reaches none, and report an exported entry that has no such file instead of dropping it. A test with compiled dist output would cover this.

},
{
type: 'prose',
text: "A member's source is the `.tsx` file that declares it, reached through the family's own file or the module `import` names, and it must sit in the family doc's folder or below it. A member is not listed when only a bundle or a file outside that folder declares it, when a doc's file or a Core name your package replaces already has its name, or when the family doc has no source file of its own. A member that shares a name with Core opens with `--package`.",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AcmeListRow, declared in src/list/row.tsx inside the family folder, is still not listed when import names compiled output and the family's own file does not re-export it. This sentence, and the dist sentence above, therefore promise more than discovery does. Please align them with the discovery fix, or say plainly that with built output the family's own .tsx must declare or re-export each member.

@josephfarina

josephfarina commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor Author

Fixed in 2d979e3:

  • Discovery now records every full entry the module the family doc imports exports, as architecture:cli-surface INV24 says. A member's source is a .tsx file in the family's folder: the one the import's chain reaches, else the one there that declares the name, so a family whose import names compiled dist output finds row.tsx. A member only a bundle or a file outside the folder declares is listed with no source (--source and swizzle answer ERR_NO_SOURCE), and it's valid: only a doc's own component needs its same-stem file, so validate and verify don't report it. A family doc without its own source lists the members its import exports.
  • integration verify compares every import family's members as local discovery lists them after the pack, not only families whose imported file changed. An incremental build that rewrites only a re-exported file no longer reports the new member as packed_identity_unexpected. The new pack-check cases cover compiled dist output from a clean checkout and from that incremental build, plus a sourceless member that passes.
  • integration add component refuses a member built output exports (new test).
  • The family guide and the changeset say this; the ComponentDoc components text already states INV24's rule.

Each new test fails without its fix.

architecture:cli-surface INV24 records each full entry a family doc lists when
the module its import names exports it. A member whose import reaches no .tsx
file, as when it names built output, now takes its source from the .tsx file in
the family's folder that declares it; a member only a bundle or a file outside
that folder declares is listed with no source, and is valid: only a doc's own
component needs its same-stem file. A family doc without its own source lists
the members its import exports. integration verify compares every import
family's members as local discovery lists them after the pack, so an
incremental build that leaves the imported file untouched no longer reports the
new member as unexpected.

@astracat-bot astracat-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is ready to merge: family members now resolve under their own names on every CLI surface, as architecture:cli-surface INV24 describes, and the earlier gap where members behind compiled output or from another folder were silently dropped is fixed. Exact lookups that Core, legacy docs packages and file-named docs answer are unchanged, and --package reaches a member that shares their name. No further changes are needed.

[Automated review]

@josephfarina
josephfarina merged commit 91cfb53 into main Oct 18, 2026
50 checks passed
josephfarina added a commit that referenced this pull request Oct 18, 2026
…ion-guides-cleanup

ComponentDoc.name takes #7659's sentence about the export apps import in place of the file-name rule. The versioning list keeps this branch's published-version bullets and adds #7674's family-member bullet. hiddenComponents now says what #7674's discovery does in an integration: it hides full entries in the doc's own `components`, and a sub-component with its own doc still uses `hidden`.
@github-actions
github-actions Bot deleted the josephfarina/doc-names-family-members branch October 19, 2026 06:30

This branch was successfully deployed

1 active deployment
Preview — 2d979e36 Deployed Oct 18, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Meta Open Source bot.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant