Repository navigation
feat(cli): integration check runs every source check for a package's build, with --strict - #7665
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
AI review status for this pull request.
|
PR Analysis Report
|
There was a problem hiding this comment.
This needs a maintainer decision before it can be approved. integration check, --strict, the promise about what may newly fail it, and CommandDoc.keywords rest on AST-039 FR14 and cli-surface INV32/DEC-4, which exist only in draft #7658, so a maintainer needs to approve those requirements on main or point to the current record that covers them. The component and template link fix follows the current rule that links resolve by doc identity. Whatever the decision, please address these:
- The help, guide and changeset promise that a patch release never makes a passing package fail, but a patch that adds a Core component, template or built-in topic can add a new conflict, so please limit the promise to new checks and new failure codes.
integration-check-failures.jsonis missingpackage_not_foundandmissing_component_replacement_target, which the command emits, and its code scanner cannot see codes written in those forms.- As AST-042 FR7 requires, please classify the
[package]selector against AST-053 E1–E5, and then either adopt the batch contract or name the condition it fails. integrationCheck.doc.mjsshould state the defaults ofoptions.strictandoptions.cwd.- At about 2,100 authored lines, please land the link fix as its own PR.
[Automated review]
| fn: 'integrationCheck', | ||
| args: [ | ||
| { | ||
| name: 'package', |
There was a problem hiding this comment.
AST-042 FR7 asks a new subcommand with an exact selector position to classify that position against AST-053 FR11 E1–E5. [package] takes one exact installed package name, is read-only, and is the final positional. Could the PR either adopt the batch contract before the first release, or name the condition it fails so a CLI code owner can approve the exclusion?
| flag: '--strict', | ||
| param: 'options.strict', | ||
| description: | ||
| 'Also exit 1 on any warning and on any check that did not run. What fails it changes only in a minor release, named in the release notes; a patch never makes a passing package fail.', |
There was a problem hiding this comment.
This promise can't hold as written. Whether a package passes depends on names Astryx ships: Core templates come from the CLI's assets/templates, built-in topics from its assets/docs, and Core components from the installed Core. A component named Button passes the default run and fails --strict with component_name_conflict, and a topic named like a CLI topic fails even the default run. New components and templates ship in patch releases, so a patch can make a passing package fail. Consider limiting the promise to new checks and new failure codes, and saying that a newly added Core or CLI name can raise a conflict on upgrade.
| "missing_root", | ||
| "missing_template_replacement_target", | ||
| "multiple_manifests", | ||
| "no_package", |
There was a problem hiding this comment.
Two codes the command emits are missing from this list. integration check @acme/not-installed fails with package_not_found (from validate-integration.mjs), and a component doc with replaces: 'NotACoreComponent' fails --strict with missing_component_replacement_target (from component-replacement.mjs, kept by addErrors).
There was a problem hiding this comment.
Fixed. Both codes are in integration-check-failures.json, and test/integration-check-failures.test.mjs › "lists every code a failure can carry" fails if a code any imported module raises is missing from the list, these two included (at 2a2fbfb).
| * snake-case codes. | ||
| * @param {string} text | ||
| */ | ||
| function codesIn(text) { |
There was a problem hiding this comment.
codesIn misses a code in the second branch of a ternary passed to error(...) (exists ? 'invalid_package_json' : 'package_not_found'), and a code passed to a local report(declaration, 'code', ...) that reaches issues through addErrors. Adding both shapes to the self-test below would keep the ratchet honest.
There was a problem hiding this comment.
Fixed. codesIn reads both branches of a conditional code, and a code property typed as a union of codes, which is how the local reporter that feeds addErrors types its code. The self-test test/integration-check-failures.test.mjs › "reads the codes a module raises, under every name" covers both shapes (at 2a2fbfb).
| 'Directory to resolve the local package / node_modules from.', | ||
| }, | ||
| { | ||
| name: 'options.strict', |
There was a problem hiding this comment.
AST-042 FR2 asks reference docs to state each option's default. Could options.strict get default: 'false', as integrationAdd.doc.mjs does for dryRun, and options.cwd state that it defaults to the current directory?
There was a problem hiding this comment.
Fixed. integrationCheck.doc.mjs states default: 'false' for options.strict and default: 'process.cwd()' for options.cwd, and api/integration/check/check.test.mjs › "states each option’s default in its reference doc" pins both (at 2a2fbfb).
| * configured. A replacement keeps the position of the topic it replaced, so | ||
| * "the first topic" stays stable for a reader that opens it by default. | ||
| */ | ||
| /** |
There was a problem hiding this comment.
These typedefs sit between the DocsCatalog class comment above and export class DocsCatalog, so the class loses its JSDoc. Moving them above that comment keeps it attached.
e0fc93c to
82607b0
Compare
82607b0 to
ff073aa
Compare
There was a problem hiding this comment.
This needs a maintainer decision before it can be approved. integration check, --strict, its compatibility promise and CommandDoc.keywords rest on AST-039 FR14 and cli-surface INV32/DEC-4, which exist only in draft #7658, so a maintainer needs to approve those requirements on main, including which additions may newly fail --strict in a patch, or point to the current record that covers them. Whatever the decision, please fix two counting issues:
- A package-level issue, such as an unknown manifest key or a missing root, is counted once per check and listed once per check under
--strict, so one problem reads as four; count each issue once in the totals and infailures, with a test that asserts exact totals. - Run outside any package, the components, templates and docs checks report a missing manifest as skipped work, and
--strictadds threemissing_manifestfailures; read the no-package state from validate once.
[Automated review]
| ...summarizeCheck(response), | ||
| response, | ||
| })); | ||
| const errors = checks.reduce((sum, check) => sum + check.errors, 0); |
There was a problem hiding this comment.
These totals add up each check's own counts. But the components, templates and docs checks each start from validate's issue list (authoring-checks.mjs lines 99, 236 and 315), so a package-level issue is counted four times. One unknown manifest key plus one template conflict prints 0 errors, 5 warnings, and one missing root prints 4 errors. Under --strict, failures also repeats the same issue once per check.
Counting each distinct issue once in the totals and in failures, while keeping the per-check rows as each subcommand exits, would fix this. The API test's toBeGreaterThanOrEqual(2) and its warningsAndSkips helper repeat the duplication, so a test that asserts exact counts would pin the fix.
| } | ||
| } | ||
| const skipped = []; | ||
| const noPackage = data.issues.some(issue => issue.code === 'no_package'); |
There was a problem hiding this comment.
Only validate's response carries no_package. With no package.json, the components, templates and docs responses have no issues and validated: false, so each one adds a missing_manifest skip ("No astryx.integration.* found next to package.json"), and under --strict a missing_manifest failure. The exit code is right, but skipped, failures and the text summary ("3 checks with skipped work") all name the wrong cause. Reading the no-package state once from validate's response would fix it.
ff073aa to
1c16fd9
Compare
There was a problem hiding this comment.
This still needs a maintainer decision before it can be approved: --strict, its compatibility promise, the rule that only this command may fail on warnings, and CommandDoc.keywords rest on AST-039 FR14 and cli-surface INV32/DEC-4, which exist only in draft #7658, so a maintainer needs to approve those requirements on main, including which additions may newly fail --strict in a patch release, or point to the current record that covers them. The two counting issues from the last review are fixed. Whatever the decision, please move integrationCheck and its test into a leaf such as api/integration/check/, since cli-surface INV20 puts each operation of a multi-operation API subject in <leaf>/<leaf>.mjs. A CLI code owner also needs to approve the new subcommand (AST-042 FR4).
[Automated review]
| * @param {IntegrationCheckOptions} [options] | ||
| * @returns {Promise<IntegrationCheckCommandResponse>} | ||
| */ | ||
| export async function integrationCheck(options = {}) { |
There was a problem hiding this comment.
cli-surface INV20 puts each operation of a subject with more than one operation in a leaf, <leaf>/<leaf>.mjs. The integration subject's flat modules are listed in AST-042 as a gap of modules that predate INV20, and operations added elsewhere since then are leaves (api/theme/eject/eject.mjs, api/layout/check/check.mjs). Could this operation and its test move to a leaf such as api/integration/check/check.mjs, keeping the FunctionDoc and typedefs at the subject level?
There was a problem hiding this comment.
Done. integrationCheck and its test live in the leaf api/integration/check/ (check.mjs, check.test.mjs); the FunctionDoc and typedefs stay at the subject level (integrationCheck.doc.mjs, integration-check.type.mjs), and check:cli-structure passes (at 2a2fbfb).
| * @property {string} [cwd] Directory to resolve the local package or | ||
| * node_modules from. |
There was a problem hiding this comment.
Nothing resolves from node_modules now that the package argument is gone. Consider matching the FunctionDoc: "The integration package folder to check. Defaults to the current directory."
1c16fd9 to
8107a38
Compare
There was a problem hiding this comment.
This needs a maintainer decision before it can be approved: --strict, its compatibility promise, the rule that only this command may fail on warnings, and CommandDoc.keywords rest on AST-039 FR14 and cli-surface INV32/DEC-4, which exist only in draft #7658, so a maintainer needs to approve those requirements on main, including which additions may newly fail --strict in a patch release (AST-017 FR54 places that rule in cli-surface), or point to the current record that covers them. Whatever the decision, please fix two things:
- The totals and
failurescollapse repeated findings within one check: a guide section that links the same missing doc twice showswarnings: 2on the docs row but "1 warning" in the summary and one--strictfailure, so please dedupe only the validate issues the other checks repeat and add a test for this case. - The
integration.checkentry inresponse-types.doc.mjs, and so the generated README row, leaves outunchecked.
A CLI code owner also needs to approve the new subcommand (AST-042 FR4).
[Automated review]
| const warnings = []; | ||
| for (const issue of data.issues) { | ||
| if (issue.severity === 'warning') { | ||
| warnings.push(shared(asIssue(issue, issue.code))); |
There was a problem hiding this comment.
This marks every warning issue of every check as shared, not only the validate issues that the components, templates and docs checks start from. combineChecks then skips any shared issue whose JSON it has already seen (line 324), so two check-specific findings with the same code and message count once. A guide section that links the same missing doc twice shows two invalid_doc_graph warnings and warnings: 2 on the docs row, but the summary says "1 warning" and --strict lists one failure. Error issues go through the same first-seen filter (lines 306–310).
Could the shared set be limited to issues that match validate's own list (consumed as a multiset), with a test for two identical check-specific findings?
There was a problem hiding this comment.
Fixed at 2a2fbfb. Only the issues the other checks repeat from validate count once, consumed per check as from a multiset; every other finding counts on its own, repeats within one check included. api/integration/check/check.test.mjs › "counts each finding a check repeats within itself, and consumes only validate’s own issues as repeats" pins two identical docs findings and a validate issue repeated by every check.
| { | ||
| value: 'integration.check', | ||
| description: | ||
| 'Every source check of an integration package in one result: validated (false when no integration manifest was found, so nothing was checked), the package name and version, strict, and checks, one entry per check (validate, components, templates, docs), each with check, errors, warnings, skipped, failed, and response, the envelope that check returns on its own. The totals are errors, warnings, and skipped. With --strict, failures lists each warning and each piece of skipped work again as an error, in the issue format the checks use; it is empty without --strict. failed decides the exit code.', |
There was a problem hiding this comment.
This entry names every other integration.check field but not unchecked, which the type, the FunctionDoc and the text summary carry. Could it name unchecked too, and the README row be regenerated, so the projections stay aligned as AST-017 FR13 and DEC-4 ask?
There was a problem hiding this comment.
Fixed at 2a2fbfb: the integration.check row names unchecked, and the README row is regenerated from it.
8107a38 to
2a2fbfb
Compare
There was a problem hiding this comment.
This needs a maintainer decision before it can be approved. --strict, its compatibility promise, the rule that only this command may fail on warnings, and CommandDoc.keywords rest on AST-039 FR14 and cli-surface INV32/DEC-4, which exist only in draft #7658, so a maintainer needs to approve those requirements on main or point to the current record that covers them. That decision should also settle whether a patch fix that makes a check find more of an existing warning may newly fail --strict, and how a package can keep a Core name overlap that the CLI calls an optional rename. The earlier counting and documentation fixes check out, and no other code changes are needed now; a CLI code owner still needs to approve the new subcommand (AST-042 FR4), and the planned merge order with the sibling PRs still applies.
[Automated review]
2a2fbfb to
ebf2d10
Compare
There was a problem hiding this comment.
This needs one maintainer decision before it can be approved. With cli-surface INV32 and INV35 now current on main, the command, --strict, its release promise and the failure list match the spec, but no current record covers the new optional CommandDoc.keywords field on the published authoring type, which the ci search requirement relies on, so a maintainer needs to approve that field or identify the record that governs CommandDoc's fields. No other code changes are needed; a CLI code owner still needs to approve the new subcommand (AST-042 FR4), and the planned merge after the sibling PRs and #7668, with its rebase, still applies.
[Automated review]
ebf2d10 to
ac04937
Compare
There was a problem hiding this comment.
This looks ready to approve: with the CommandDoc.keywords field removed, every change matches cli-surface INV32 and INV35 on main, and no defects turned up. Before it merges, a CLI code owner still needs to approve the new subcommand (AST-042 FR4), and it should land only after #7681, #7663, #7676, #7684, #7667, #7664 and #7673, with the planned rebase of the failure list, and not before #7668. That rebased revision will need its own review.
[Automated review]
…build, with --strict `astryx integration check` takes no package argument: it runs `validate`, `components`, `templates`, and `docs` against the integration package in the current folder, prints each result as that check prints it, then a summary, and exits 1 when any of them would exit 1 on its own. `--strict` adds no check: it lists each warning, and each check or comparison that did not run, again as an error in the checks' own issue format (`failures`, naming the component and prop a finding is about), and exits 1, so a package can gate its build on its docs staying in sync: `"typecheck": "tsc --noEmit && astryx integration check --strict"`. JSON: a new `integration.check` envelope carries each check's own envelope unchanged. The totals count an issue every check starts from once and every other finding on its own, and `unchecked` counts what the checks could not compare. The `doctor integration` subcommands, their exit codes, and their JSON do not change. What fails it is a contract for the builds that run it. A repository test lists every check, counted field, code, and comparison that can fail it, and another keeps `integration check` the only command that offers `--strict` or fails on a warning. Its docs say to run it as a `ci` step, so `astryx search ci` finds the command first.
…at it needs The quick start's package.json step now recommends `"typecheck": "tsc --noEmit && astryx integration check --strict"`, and the quick start and the checks guide say the script needs `typescript` and a `tsconfig.json`: without a config, `tsc --noEmit` prints its help and exits 1.
…ails strict on prop types it could not judge
Rebased onto the merged props and doc-type checks. The list of what can
fail `integration check --strict` now names their fields (`propDrift` on
components, `docTypes` on validate), the code each skip carries
(`prop_drift_skipped`, `doc_types_skipped`), and their finding codes
(`not_in_code`, `not_in_doc`, `required_mismatch`, `type_mismatch`,
`missing_field`, `unknown_field`, `wrong_type`).
A props comparison that ran but judged no prop type, because the
project's TypeScript is older than 4.8, is skipped work: the default run
lists it ("prop types not judged: ..."), and `--strict` fails on it with
`prop_types_skipped`, as it does on any comparison that did not run. The
command's doc says so, and a test covers both runs.
ac04937 to
aa44556
Compare
Merge last, after #7681, #7663, #7676, #7684, #7667, #7664 and #7673, and only after rebasing to add their fields and codes; merging it first breaks main.
User need
An integration package should be able to keep its docs, types and links in sync on every build, the same way it keeps its code type-checked. Today that takes four commands (
doctor integration validate,components,templatesanddocs), and none of them fails on a warning, so drift a check reports still passes CI. A package that wants a gate has to chain them and parse their output.Problem and solution fit
astryx integration checkis the CI check for a package's own build. It takes no package argument, and checks the integration package in the folder it runs in, where its own build runs it:validate,components,templatesanddocsagainst one package, prints each result exactly as that check prints it, then a summary per check (errors, warnings, skipped work), and exits 1 exactly when one of the four would exit 1 on its own.--strictadds no check. It reads the same results, lists each warning and each check or comparison that did not run (a package with noastryx.integration.*, or a comparison skipped because the project has no TypeScript) again as an error in the checks' own issue format, and exits 1. An item a comparison lists as unchecked does not fail it."typecheck": "tsc --noEmit && astryx integration check --strict". Runintegration verifybefore publishing, as today:checkcovers the source on every build,verifythe packed package.What fails it is a contract for the builds that run it, so this PR also adds:
packages/cli/test/integration-check-failures.test.mjswithintegration-check-failures.json: every check, every counted result field, every code a failure can carry (read from the code of every module the command imports), and every comparison with its skip code. Adding any of them fails the test until the list changes, so a new way to fail a build always shows up in review.packages/cli/test/cli-strict-guard.test.mjs:integration checkis the only command that offers--strictand the only one whose exit code depends on a warning, read from the live CLI manifest (cli-surface INV32 and DEC-4 in spec(AST-039, cli-surface): integration docs are found by their documented names and checked in one command #7658).The command is findable through the fields
CommandDocalready has: its summary says to run it in continuous integration or a typecheck script, and its description says to run it as acistep. Soastryx search ci,continuous integration,typecheck integrationandintegration checkfind it first (pinned byapi/search/search.integration-check.test.mjs).A doc link to a component, page, or block warns today that it names no doc, so
--strictwould fail every package that links its own components. #7668 fixes those links; merge it first, or in the same release.Current specification
Implements
architecture:cli-surfaceINV35, "One command checks an integration in CI" (AST-039 FR14, which now points to it; DEC-5), and INV32 / DEC-4, that only this command may fail on warnings. INV35's evidence row names the check, integration-check, integration-check-failures and search.integration-check tests. As a new subcommand it also needs a CLI code owner's approval under AST-042 FR4; CODEOWNERS already requested both.Public delta and caller burden
astryx integration check [--strict], with no package argument. Apps check an installed integration by name with thedoctor integrationsubcommands, as today. JSON: a newintegration.checkenvelope,{validated, name, version, strict, checks[], errors, warnings, skipped[], unchecked, failures[], failed}. Eachchecks[]entry is{check, errors, warnings, skipped, failed, response}, whereresponseis the check's own envelope, unchanged.failures[]is empty without--strict; with it, each entry is{check, severity: 'error', code, message, component?, prop?, fix?, file?, line?}.failures[]: an issue keeps its own code, a finding its own kind; conflicts carrycomponent_name_conflictortemplate_id_conflict, a package with no manifestmissing_manifest, and a skipped comparison its key in snake case plus_skipped.doctor integrationsubcommand, its exit codes and its JSON stay exactly as they are.astryx integration check --strictin an Acme package whose page template takes a Core template's id (the default run prints the same, without theFailing under --strictblock, and exits 0):Design and alternatives
doctor integration. The group documents that with no subcommand it prints help and exits 0; running checks there would change a released behavior.--strictmeans one thing on one command, and the guard test keeps it that way.--strictreports exactly what the default run reports, with only the severity changed, so a build never sees a check it can't run without--strict(pinned byapi/integration/check/check.test.mjs).doctor integrationsubcommand fail on warnings (the rule would spread to every command).Evidence
clients/cli/commands/integration-check.test.mjs(order, a blank line between checks, summary, the--strictblock, JSON, no manifest counted once, no package.json named in the closing line, help),api/integration/check/check.test.mjs(each check counted as its own subcommand exits; exact totals with an issue every check reports; two findings with one message counted twice, each naming its component; what the checks could not compare; a missing root counted once; no package.json read from validate alone; strict failures equal the default run's warnings and skips), the two ratchet/guard tests above, and the search test.Batch selection (AST-053)
integration checktakes no package argument. It checks the integration package in the current folder, which is where the package's own build runs it. With no selector position, AST-042 FR7 and AST-053's batch rule don't apply. An installed integration is checked by name withdoctor integration validate <package>and its siblings, as today.Since the first automated review
[package]argument is gone. The command checks the package in the current folder, and passing a name is an error (see Batch selection).package_not_foundandmissing_component_replacement_target. Its scanner now reads both branches of a conditional code, and acodeproperty typed as a union of codes. The self-test covers both cases.integrationCheck()states the defaults ofoptions.strictandoptions.cwd.integrationChecklives in its own leaf,api/integration/check/(cli-surface INV20), with its test beside it.failures. The components, templates and docs checks start from validate's package-level issues, such as an unknown manifest key or a missing root, so one problem used to read as four. Each check's own row still counts as its subcommand exits.missing_manifest, not four.After an independent audit
A reviewer who didn't write the code drove the real CLI over 53 package shapes, on this head and on all five PRs merged together: the command exits 1 exactly when one of the four checks would, each check's section is byte-identical to its subcommand's output, and
--strictlists exactly the default run's warnings and skipped work. Fixed here, each with a test that failed first:failuresmerged distinct findings that shared a message: two components in one family doc that both leavelabelunmarked counted as one. Only an issue every check starts from (validate's package-level issues, a missing manifest) counts once now; every other finding counts on its own, and a failure names itscomponentandprop.(no package.json).1 skipped), as JSON does.[ok] … Every check passed.printed when a comparison compared nothing. JSON addsdata.unchecked, the items the checks could not compare (they never fail it), and the closing line names them.After the next review
failures. Now only the issues the other checks repeat from validate count once, consumed as from a multiset, and every other finding counts on its own, repeats within one check included. A test pins two identical findings in one check, and a validate issue the other checks repeat.integration.checkrow in the response types, and the README row made from it, nameunchecked.options.strictandoptions.cwd(AST-042 FR2).Authoring docs
"typecheck": "tsc --noEmit && astryx integration check --strict", as the checks guide does.typescriptand atsconfig.json. In a package with neither, as the quick start leaves it,tsc --noEmitprints its help and exits 1.Rebased
After the review of
CommandDoc.keywordsCommandDoc.keywordsfield is gone: a new published authoring field needs its own record, and the command doesn't need one. Its summary and description say to run it in CI, as acistep, or in a typecheck script, and the CI example's label says so too.cias a keyword, soastryx search ciranks this command first instead of tying with the guide. The guide is still found second for CI queries ("run checks in ci") and first for its own phrases.ci,continuous integration,typecheck integrationandintegration check. It dropscheck my integration, which now finds theastryx integrationoverview first, the page that listscheck.Merge order
The order is required: #7681, #7663, #7676, #7684, #7667, #7664 and #7673 first, and #7668 before this PR or with it. Then this branch rebases on main and adds what #7663, #7676, #7667, #7664 and #7673 add to the lists in
integration-check-failures.json: the fieldspropDriftanddocTypes, the skip codesprop_drift_skippedanddoc_types_skipped, and the codesmissing_field,not_in_code,not_in_doc,required_mismatch,type_mismatch,unknown_fieldandwrong_type. Until then the lists hold this branch's 41 codes. Merged in any other order, main breaks: the list test fails as soon as one side lands without the other.#7681, #7663, #7676, #7684, #7667, #7664 and #7673 ship in the same release as this command. A finding that joins
--strictafter the command ships needs a minor.Overlap with open PRs
assets/docs/tree/checks.doc.mjs, the guide's command table and CI section, where it drops thenpxprefix and rewrites the chained command this PR replaces; keep this PR's rows and section, without the prefix.astryx componentprints #7623, fix(cli): init writes agent docs every agent reads, at the project root, never in the home folder #7497, spec(AST-039, cli-surface): integration docs are found by their documented names and checked in one command #7658, feat(cli): a component doc can name a differently named export of the file beside it #7659, fix(cli): integration verify reads exports with the reader discovery uses #7660, feat(docsite): put the integration guide's pages under CLI Integrations in the sidebar #7661, feat(cli): integration family members are components under their own names #7674, or the other PRs in this set.Scope
Testing
On main 91cfb53 with this branch: copyright, sync-exports, the published
./apitype check,readme:check, the four CLI typechecks (strict, json-api, authoring-contract, template-docs),check:changesets,check:cli-structure,check:repo, eslint on the changed files, prettier on the new files, and the fullpnpm vitest run --project nodesuite: 10,325 tests pass. The 20 failures are in the npm pack, packed real-world package, theme resolution and CSS graph tests, which fail the same way on current main on the same machine (they need a package registry it doesn't reach). With all nine PRs merged into main, the fourdoctor integrationsubcommands were run in text and JSON on 64 package shapes, against main: templates output is byte-identical everywhere;validateandcomponentsonly add their new section and JSON field;docsdiffers only where the doc-links PR fixes a link warning.integration checkexits 1 exactly when one of the four would, each of its sections is byte-identical to that subcommand's output, and onlyintegration check's three list tests fail until its planned rebase.