Skip to content

Fix aipm lint silent for a plugin-shaped dir missing aipm.config.ts - #109

Merged
mike-north merged 3 commits into
mainfrom
fix/lint-diagnostic-config-less-plugin-dir
Aug 27, 2026
Merged

mike-north merged 3 commits into
mainfrom
fix/lint-diagnostic-config-less-plugin-dir

Conversation

@mike-north

@mike-north mike-north commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Summary

#91 made aipm validate (hard envelope-invalid finding) and aipm build (thrown
ConfigLoadError) catch a plugin-shaped directory missing aipm.config.ts. aipm lint stayed
silent for the identical tree, so the three surfaces disagreed on a real defect: a user relying on
lint got a clean bill of health for a directory validate/build correctly flagged.

  • schema/envelope-shape (packages/core/src/lint/rules/legacy-envelope-shape.ts) no longer
    short-circuits with [] on a failed envelope load. It has no fs.existsSync pre-check at all;
    it always calls loadPluginConfig() and derives every diagnostic from the thrown error,
    mirroring runValidate()'s envelope-load catch in pipeline/validate.ts — a ConfigLoadError
    with a ZodError cause expands into per-issue diagnostics, and anything else becomes a single
    hard envelope-invalid carrying err.message verbatim. Agreement with validate is therefore
    structural rather than a duplicated message string, and it covers both a missing
    aipm.config.ts and one that exists but cannot be imported (syntax error, no usable default
    export) — the latter previously left lint silent while validate/build flagged it.
  • packages/core/src/lint/engine.ts's comment on its envelope short-circuit is corrected; it
    claimed the config loader explained an unusable envelope on its own, which was not true for the
    import-failure path.
  • No change to validate/build behavior (unchanged since plugin dir without aipm.config.ts silently drops out of discovery: validate AND build exit 0 green ('Built 0 plugin(s)') #91) or to the envelope-invalid
    schema/envelope-shape mapping in the reconciled docs/specs/lint-engine.md §3.6 migration
    table (Reconcile docs/specs/lint-engine.md with the shipped engine/CLI (spec drifted behind implementation) #88) — the rule id/category/severity were already correct; only the missing-config case
    needed to actually fire it.
  • docs/specs/lint-engine.md §3.1 updated to describe schema/envelope-shape as firing on any
    failure to resolve the envelope — missing, unimportable, or schema-violating — not only a
    malformed one.

Acceptance criteria mapping

  1. "For a plugin-shaped directory missing aipm.config.ts, aipm lint emits a diagnostic
    equivalent in severity and meaning to validate's hard envelope-invalid finding for the same
    tree."
    — covered by
    packages/core/src/lint/engine.test.ts's lint() — plugin-shaped repo-root subdirectory missing aipm.config.ts (#91, #101) > agrees with runValidate(): both report the equivalent envelope-invalid finding for the same tree, which asserts the lint diagnostic's ruleId
    (schema/envelope-shape), category (schema), severity (error), legacyCode
    (envelope-invalid), and message (byte-identical to validate's).

  2. "A test asserts that lint and validate AGREE on this case ... not one silent while the other
    flags it."
    — the same test runs lint() and runValidate() against the identical temp tree
    (the plugin dir without aipm.config.ts silently drops out of discovery: validate AND build exit 0 green ('Built 0 plugin(s)') #91 repro shape: a plugins/* dir with a target manifest but no aipm.config.ts) and
    asserts both surface the equivalent finding. It fails against pre-fix code (lint returns [])
    and passes with the fix.

  3. Follow-on from the same defect class: lint() — plugin whose aipm.config.ts exists but fails to import (#101) asserts the same agreement for a config with a deliberate syntax error, where
    lint previously emitted zero diagnostics; a sibling test pins the schema-violation path to
    its per-issue expansion so the two error shapes stay distinct. Confirmed end-to-end: against a
    plugin with an unparseable aipm.config.ts, aipm lint and aipm validate both exit 1 with
    Failed to import aipm.config.ts: ParseError: Unexpected token; pre-fix, lint exited 0
    silently.

A second test in the first describe block (emits nothing further beyond the envelope-invalid diagnostic for the config-less plugin) confirms the engine's existing short-circuit (continue
after the failed loadPluginConfig call) still holds — no other rule spuriously runs against an
unresolved envelope.

Test plan

  • pnpm --filter @ai-plugin-marketplace/core exec vitest run src/lint/engine.test.ts (new
    agreement tests + existing suite)
  • pnpm run check (typecheck, lint, api-report, full test suite, format, deps, knip) — green
  • pnpm run fix:format run before push

Refs #101

#91 made validate (hard envelope-invalid) and build (thrown ConfigLoadError)
catch a plugin-shaped directory missing aipm.config.ts, but lint stayed
silent for the identical tree. schema/envelope-shape now also fires on a
missing config, emitting the equivalent envelope-invalid diagnostic lint and
validate agree on.

Refs #101

Copilot AI 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.

Pull request overview

Aligns aipm lint with aipm validate/aipm build by ensuring a plugin-shaped directory missing aipm.config.ts is surfaced as an envelope-invalid-backed diagnostic instead of being silently ignored, and documents + tests the agreement.

Changes:

  • Update schema/envelope-shape to emit an envelope-invalid diagnostic when aipm.config.ts is missing.
  • Add regression tests asserting lint() and runValidate() agree on the missing-config plugin-shaped directory case.
  • Update the lint engine spec and add a patch changeset documenting the behavior change.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
packages/core/src/lint/rules/legacy-envelope-shape.ts Emit envelope-invalid diagnostic for missing aipm.config.ts in plugin-shaped dirs.
packages/core/src/lint/engine.test.ts Add agreement regression tests for lint() vs runValidate() on missing-config plugins.
docs/specs/lint-engine.md Document that schema/envelope-shape also fires on missing aipm.config.ts.
.changeset/lint-missing-config-envelope-invalid.md Patch changeset describing the lint behavior fix.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/core/src/lint/rules/legacy-envelope-shape.ts Outdated
The rule pre-checked for a missing aipm.config.ts and returned a hard-coded
copy of the message loadPluginConfig throws for that case, then returned no
diagnostic at all for any non-Zod load failure. A config with a syntax error or
no usable default export therefore still passed aipm lint silently while
validate and build both reported envelope-invalid — the same disagreement the
missing-config fix set out to close.

Drop the existence pre-check and derive every diagnostic from the thrown error,
mirroring runValidate()'s envelope-load catch: a ZodError cause expands into
per-issue diagnostics, anything else becomes a single envelope-invalid carrying
the loader's own message. Agreement with validate is now structural rather than
a duplicated string, and covers missing, unimportable and schema-violating
configs alike.

Also corrects the lint engine's comment on its envelope short-circuit, which
claimed the config loader explains an unusable envelope on its own.
@mike-north
mike-north merged commit 37bb067 into main Aug 27, 2026
2 checks passed
@mike-north
mike-north deleted the fix/lint-diagnostic-config-less-plugin-dir branch August 27, 2026 19:23
@github-actions github-actions Bot mentioned this pull request Aug 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants