Skip to content

Added internal package golden path checks - #29877

Open
ErisDS wants to merge 1 commit into
mainfrom
codex/add-internal-package-checks
Open

Added internal package golden path checks#29877
ErisDS wants to merge 1 commit into
mainfrom
codex/add-internal-package-checks

Conversation

@ErisDS

@ErisDS ErisDS commented Aug 11, 2026

Copy link
Copy Markdown
Member

Summary

  • Makes the internal package golden path enforceable instead of relying on documentation alone.
  • Adds explicit compliant, migration, and exempt lifecycle states, with reasons required for temporary or intentional exceptions.
  • Adds a dependency-free checker with fixtures, wires it into package linting and a path-filtered CI job, and updates the package template and migration skills to maintain the contract.

Testing

  • pnpm lint:packages
  • pnpm --filter @internal/scripts lint
  • pnpm --filter @internal/scripts test
  • pnpm lint:docs
  • Manual scaffolder smoke test: generated a temporary package and validated it with the checker
  • pnpm check — affected lint and unit-test lanes passed; the full run was blocked by unrelated local browser-suite startup failures and an existing Admin archive test timeout

@ErisDS
ErisDS requested a review from EvanHahn as a code owner August 11, 2026 09:42
@nx-cloud

nx-cloud Bot commented Aug 11, 2026

Copy link
Copy Markdown

🤖 Nx Cloud AI Fix

Ensure the fix-ci command is configured to always run in your CI pipeline to get automatic fixes in future runs. For more information, please see https://nx.dev/ci/features/self-healing-ci


View your CI Pipeline Execution ↗ for commit 0ef2652

Command Status Duration Result
nx run ghost:test:ci:integration ✅ Succeeded 3m 1s View ↗
nx run ghost:test:integration ✅ Succeeded 3m 5s View ↗
nx run @tryghost/admin:test:acceptance ✅ Succeeded 6m 13s View ↗
nx run ghost:test:e2e ✅ Succeeded 2m 39s View ↗
nx run ghost:test:legacy ✅ Succeeded 2m 49s View ↗
nx run @tryghost/koenig-lexical:test:acceptance ✅ Succeeded 2m 5s View ↗
nx run ghost-monorepo:lint:boundaries ✅ Succeeded 22s View ↗
nx run-many -t test:unit -p @tryghost/adapter-b... ✅ Succeeded 35s View ↗
Additional runs (8) ✅ Succeeded ... View ↗

💡 Verify your cache is correct by running tasks in a sandbox. Read docs ↗


☁️ Nx Cloud last updated this comment at 2026-08-11 11:26:53 UTC

@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

The change defines ghostPackage.goldenPath states for private packages. It adds validation for compliant packages and reasons for migration or exemption states. It adds package fixtures and tests. Local linting and CI run the validator when package standards change. The required-tests gate includes the validator job.

Possibly related PRs

Suggested reviewers: evanhahn

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: adding enforceable internal package golden path checks.
Description check ✅ Passed The description directly explains the lifecycle states, checker, integrations, documentation updates, and testing for the changeset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/add-internal-package-checks

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (1)
.agents/skills/migrate-internal-package/SKILL.md (1)

66-66: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Name the required manifest field explicitly.

This step says “with a concise reason” but does not identify ghostPackage.reason. The validator reads pkg.manifest.ghostPackage.reason, so state the exact property to prevent migration work from recording the reason under the wrong field.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.agents/skills/migrate-internal-package/SKILL.md at line 66, Update the
migration instruction to explicitly set both ghostPackage.goldenPath to
migration and ghostPackage.reason to the concise reason, matching the manifest
property read by the validator.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@scripts/check-internal-packages.js`:
- Line 248: Update the workspaceNames construction in the internal package
validation flow to include manifest names from every workspace member, including
packages under koenig/, rather than only packages/. Ensure dependencies on
Koenig workspace packages are recognized by the existing workspace:* validation,
and add a fixture covering a package below koenig/.
- Around line 183-203: Validate that exports condition values source, types, and
default are strings before applying the source regex, deriving build paths, or
calling replace in the root export checks. Record malformed values through the
existing aggregated error mechanism and skip dependent validation for invalid
source values, preventing malformed manifests from terminating the checker. Add
fixtures covering non-string values for each condition.
- Around line 281-289: Extend the validation flow around
discoverPackageDirectories() so packages/_template is validated with the same
compliant-package contract as discovered packages, rather than checking only
ghostPackage.goldenPath. Reuse the existing compliant-package validator and
preserve its checks for exports, scripts, dependencies, and configuration; add a
fixture that omits or invalidates one required template field and assert
validation fails.

---

Nitpick comments:
In @.agents/skills/migrate-internal-package/SKILL.md:
- Line 66: Update the migration instruction to explicitly set both
ghostPackage.goldenPath to migration and ghostPackage.reason to the concise
reason, matching the manifest property read by the validator.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: b3250b3b-8a3a-4d50-bdb5-55d0060d3a0a

📥 Commits

Reviewing files that changed from the base of the PR and between de65389 and 64e1be1.

📒 Files selected for processing (17)
  • .agents/skills/convert-internal-package-to-typescript/SKILL.md
  • .agents/skills/migrate-internal-package/SKILL.md
  • .github/workflows/ci.yml
  • package.json
  • packages/README.md
  • packages/_template/package.json
  • packages/adapters/redirects-base/package.json
  • packages/adapters/route-settings-base/package.json
  • packages/admin-api-schema/package.json
  • packages/custom-field-types/package.json
  • packages/i18n/package.json
  • packages/nql-string/package.json
  • packages/parse-email-address/package.json
  • packages/testing/test-data/package.json
  • scripts/check-internal-packages.js
  • scripts/create-package.js
  • scripts/test/check-internal-packages.test.js

Comment thread scripts/check-internal-packages.js Outdated
Comment thread scripts/check-internal-packages.js Outdated
Comment thread scripts/check-internal-packages.js
@codecov

codecov Bot commented Aug 11, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 75.43%. Comparing base (579fc56) to head (0ef2652).

Additional details and impacted files
@@           Coverage Diff           @@
##             main   #29877   +/-   ##
=======================================
  Coverage   75.42%   75.43%           
=======================================
  Files        1606     1606           
  Lines      140676   140676           
  Branches    17426    17435    +9     
=======================================
+ Hits       106108   106117    +9     
+ Misses      33520    33511    -9     
  Partials     1048     1048           
Flag Coverage Δ
e2e-tests 77.58% <ø> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

no ref

Internal package conventions were documented but could drift silently or leave migrations in a permanent halfway state. This adds explicit lifecycle metadata and focused, dependency-free validation so new packages and migrated packages have an actionable path to compliance.
@ErisDS
ErisDS force-pushed the codex/add-internal-package-checks branch from 64e1be1 to 0ef2652 Compare August 11, 2026 11:15
Comment thread scripts/check-internal-packages.js

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
scripts/check-internal-packages.js (1)

62-85: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Keep workspace discovery synchronized with pnpm-workspace.yaml

The hardcoded roots match the current workspace globs. A future workspace glob can bypass the workspace:* check because workspaceNames only includes these hardcoded roots. Derive the roots from pnpm-workspace.yaml, or add a synchronization test.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/check-internal-packages.js` around lines 62 - 85, The
discoverWorkspacePackageDirectories function hardcodes workspace roots that can
diverge from pnpm-workspace.yaml, causing workspace:* packages to be missed.
Update this discovery flow to derive workspace roots from the workspace
configuration, or add a test that fails whenever the hardcoded roots and
pnpm-workspace.yaml globs become inconsistent.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@scripts/check-internal-packages.js`:
- Around line 327-343: In the template manifest handling, narrow the try/catch
around templateManifestPath to only readFile and JSON.parse, then move the
validateCompliantPackage call outside the try block while preserving its
existing arguments and error aggregation. Keep read/parse failures mapped to the
current invalid-JSON message without intercepting validation exceptions.

---

Nitpick comments:
In `@scripts/check-internal-packages.js`:
- Around line 62-85: The discoverWorkspacePackageDirectories function hardcodes
workspace roots that can diverge from pnpm-workspace.yaml, causing workspace:*
packages to be missed. Update this discovery flow to derive workspace roots from
the workspace configuration, or add a test that fails whenever the hardcoded
roots and pnpm-workspace.yaml globs become inconsistent.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 0374f917-5a85-4ef6-980c-d4b29e8d409b

📥 Commits

Reviewing files that changed from the base of the PR and between 64e1be1 and 0ef2652.

📒 Files selected for processing (4)
  • .agents/skills/migrate-internal-package/SKILL.md
  • .agents/skills/migrate-internal-package/references/legacy-integration.md
  • scripts/check-internal-packages.js
  • scripts/test/check-internal-packages.test.js
🚧 Files skipped from review as they are similar to previous changes (1)
  • .agents/skills/migrate-internal-package/SKILL.md

Comment on lines +327 to +343
const templateManifestPath = path.join(packagesDirectory, '_template', 'package.json');
try {
const templateManifestSource = await readFile(templateManifestPath, 'utf8');
const templateManifest = JSON.parse(templateManifestSource
.replaceAll('{{NAME}}', 'template')
.replaceAll('{{DESCRIPTION}}', 'Template package')
.replaceAll('{{DIRECTORY}}', 'packages/template'));
errors.push(...await validateCompliantPackage({
rootDirectory,
packageDirectory: path.dirname(templateManifestPath),
packagePath: 'packages/template',
manifest: templateManifest,
workspaceNames
}));
} catch (error) {
errors.push(`packages/_template/package.json: invalid JSON (${error.message})`);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Narrow the template try block to the read and parse steps.

The try block wraps validateCompliantPackage. Two consequences follow:

  • A missing or unreadable packages/_template/package.json reports invalid JSON (ENOENT: ...), which is inaccurate.
  • If validateCompliantPackage throws, its aggregated errors are lost and replaced with a single misleading message.

Move the validation call outside the try block.

🛠️ Proposed fix
     const templateManifestPath = path.join(packagesDirectory, '_template', 'package.json');
+    let templateManifest;
     try {
         const templateManifestSource = await readFile(templateManifestPath, 'utf8');
-        const templateManifest = JSON.parse(templateManifestSource
+        templateManifest = JSON.parse(templateManifestSource
             .replaceAll('{{NAME}}', 'template')
             .replaceAll('{{DESCRIPTION}}', 'Template package')
             .replaceAll('{{DIRECTORY}}', 'packages/template'));
+    } catch (error) {
+        errors.push(`packages/_template/package.json: unreadable or invalid JSON (${error.message})`);
+    }
+
+    if (templateManifest) {
         errors.push(...await validateCompliantPackage({
             rootDirectory,
             packageDirectory: path.dirname(templateManifestPath),
             packagePath: 'packages/template',
             manifest: templateManifest,
             workspaceNames
         }));
-    } catch (error) {
-        errors.push(`packages/_template/package.json: invalid JSON (${error.message})`);
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const templateManifestPath = path.join(packagesDirectory, '_template', 'package.json');
try {
const templateManifestSource = await readFile(templateManifestPath, 'utf8');
const templateManifest = JSON.parse(templateManifestSource
.replaceAll('{{NAME}}', 'template')
.replaceAll('{{DESCRIPTION}}', 'Template package')
.replaceAll('{{DIRECTORY}}', 'packages/template'));
errors.push(...await validateCompliantPackage({
rootDirectory,
packageDirectory: path.dirname(templateManifestPath),
packagePath: 'packages/template',
manifest: templateManifest,
workspaceNames
}));
} catch (error) {
errors.push(`packages/_template/package.json: invalid JSON (${error.message})`);
}
const templateManifestPath = path.join(packagesDirectory, '_template', 'package.json');
let templateManifest;
try {
const templateManifestSource = await readFile(templateManifestPath, 'utf8');
templateManifest = JSON.parse(templateManifestSource
.replaceAll('{{NAME}}', 'template')
.replaceAll('{{DESCRIPTION}}', 'Template package')
.replaceAll('{{DIRECTORY}}', 'packages/template'));
} catch (error) {
errors.push(`packages/_template/package.json: unreadable or invalid JSON (${error.message})`);
}
if (templateManifest) {
errors.push(...await validateCompliantPackage({
rootDirectory,
packageDirectory: path.dirname(templateManifestPath),
packagePath: 'packages/template',
manifest: templateManifest,
workspaceNames
}));
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/check-internal-packages.js` around lines 327 - 343, In the template
manifest handling, narrow the try/catch around templateManifestPath to only
readFile and JSON.parse, then move the validateCompliantPackage call outside the
try block while preserving its existing arguments and error aggregation. Keep
read/parse failures mapped to the current invalid-JSON message without
intercepting validation exceptions.

@EvanHahn
EvanHahn removed their request for review August 11, 2026 16:33
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.

1 participant