Skip to content

Gate the Directus extension bundle on format, lint and build (Phase 0) - #245

Open
Jan0707 wants to merge 4 commits into
mainfrom
directus-extension-phase-0-gates
Open

Gate the Directus extension bundle on format, lint and build (Phase 0)#245
Jan0707 wants to merge 4 commits into
mainfrom
directus-extension-phase-0-gates

Conversation

@Jan0707

@Jan0707 Jan0707 commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Phase 0 of docs/directus-extension-tooling-plan.md, added in this PR. No dependency versions change — the only dependency touched is a new one, eslint-plugin-vue, on the same footing as nuxt-app's Phase 0 adding vue-tsc and @playwright/test.

The bundle's CI job ran npm ci, ESLint and Jest. It did not check formatting, did not typecheck, and never confirmed the artefact Directus loads still compiles. This adds the two gates that need no source changes, plus the config corrections behind them.

Review guide — read commit 3, skip commit 2

Commit Contents Files
1 Prettier config, corrected before the reformat runs under it 2
2 Mechanical prettier . --write output. Nothing to review. 63
3 The actual change: gates, config, docs 11
4 Plan restructure + ADR 0003 (docs only, added after review — see below) 2

All three are green in isolation, verified by checking each out and running the gates that exist at that commit.

What this gates

CI's bundle job becomes format → lint → test → build:

  • prettier:check, not prettier — the latter writes, so it would pass by mutating.
  • A build step. directus-extension build has its own Rollup/esbuild pipeline that neither ESLint nor Jest exercises, so a change that broke the loadable bundle could merge green.
  • node-version-file: reading a new .nvmrc instead of a hardcoded 22, so CI, the Docker image and local development have one file to change rather than three. Local dev had already drifted to 24.19.0.
  • shared-code/** added to the paths filter — the bundle imports from there, so those changes were skipping the gate entirely.

Hermetic image build: both npm install calls in Dockerfile.directus become npm ci, so the image can no longer resolve versions the lockfile does not record. Verified both lockfiles are in sync first (npm ci --dry-run exits 0 in directus-cms and in the bundle), since otherwise this would land a broken image build.

Three things worth a second look

This tree is not blocked by the Directus licence question. A CI comment claimed it was. Every @directus/* package the bundle uses is MIT (extensions-sdk, errors, sdk — checked at both current and latest); only the directus server package is non-OSI, and it lives in directus-cms/package.json. The real reason to stay on Node 22 is Dockerfile.directus: Node 24 brings npm 11, which gates the install scripts sharp, sqlite3, isolated-vm and oracledb all need. That is now a recorded blocker for the deferred Node 24 move, not a vague caution.

eslint-config-prettier was a dependency that had never been applied. Adding eslint-plugin-vue to cover the one unlinted source file produced 2 errors and 20 warnings — the warnings all formatting rules fighting Prettier (vue/html-indent wants 2-space, .prettierrc says 4). Applying eslint-config-prettier last takes the 20 to 0. It was harmless while the config was TypeScript-only and enabled no stylistic rules, and load-bearing the moment such a plugin arrives. The 2 real errors were unused watch parameters, removed here; the gate was confirmed to fire by injecting an unused variable.

host: "^10.10.0" is correct and deliberately unchanged. The plan initially flagged it as stale against the 11.17.4 server. It is not: extensions-sdk exports LAST_BREAKING_RELEASE = '10.10.0' and directus-extension create scaffolds host as exactly that. The field declares the extensions API contract version, not the server version, and Directus never checks it against the running server (z.string(), no semver comparison). Changing it to ^11.0.0 would narrow compatibility for nothing.

Verifying the 63-file reformat

Lint, test and build are blind to a formatter by construction, and 17 of 26 entries have no tests, so the sweep was verified against the artefact Directus actually loads — build before, build after.

Import reordering is the one way this can genuinely break something, so it was checked first: the only load-time side-effect imports are import 'dotenv/config' in the two Algolia CLI scripts, the plugin keeps them in the same slot, and the only process.env reads in those files sit below the whole import block.

  • app.js — all 43 string literals identical; identifier-normalised, exactly one structural difference, the unused watch parameters removed in commit 3.
  • api.js — same 18 module specifiers in the same order; 10,554 of 10,583 literals byte-identical. The 29 that differ are entities lazy-init blobs varying only in Rollup's internal module variable names, a knock-on of a different module emission order.

Static analysis could not push api.js past "almost certainly equivalent", so the decisive check was importing both builds in Node and comparing the registry handed to Directus: deep-equal — 23 hooks in the same order, 2 endpoints, 0 operations.

Blind spot, stated plainly: that compares the registry's shape, not the behaviour of the 23 handlers, which cannot be invoked without a Directus host.

Verification

prettier:check, lint, test (205/205) and build all green. npm audit unchanged at 19 (1 critical, 7 high) — deliberately untouched here. The critical (sanitize-html) is a patch bump and ships as its own carve-out; the rest is Phase 4.

Added after the first review pass: the plan's phase order was wrong

Commit 4 is docs-only and changes no code in this PR, but it changes what comes next, so it is worth reading.

The plan put test coverage in Phase 5, after the dependency upgrades — inherited from the nuxt-app plan's shape without re-deriving it. Measured: of the 16 files the planned bumps touch, 3 have a test covering them, and algolia-index (largest module, zero tests) is hit by four separate bumps. The old Phase 3 even required a manual step, "verify the Algolia indexer specifically … a broken indexer fails silently" — a hand-verification instruction inside an upgrade phase is an admission the automated check should have come first.

New order: 3 contract tests → 4 security and minors → 5 E2E harness → 6 majors → 7 Renovate. Tier 3 also moved ahead of the majors, because it is the only thing that can validate @directus/extensions-sdk 18 against the frozen 11.17.4 host.

_ADRs/0003-three-tier-extension-testing.md records the three tiers, an audit of all 11 outbound integrations (6 already redirectable via env, 5 hardcoded), and the harness rules — fail-closed stub, and no secrets in the environment at all rather than fake-but-plausible ones, so a missed redirect dies on a connection error instead of reaching the production Slack.

Not in this PR

Typechecking. tsc cannot currently run on this tree at all — it dies on TS5110 before checking anything, hiding 124 real errors across 32 files. That is Phase 1.

🤖 Generated with Claude Code

https://claude.ai/code/session_01BMa3aosYRWyivC4DtPbSNr

Jan0707 and others added 3 commits August 5, 2026 21:39
Two corrections to the formatter's own configuration, kept ahead of the
reformat so that sweep runs under the final config rather than a config
that changes underneath it.

`jsxBracketSameLine` was removed in Prettier 3 and printed a deprecation
warning on every single run. Verified it changed no output: exactly the
same 64 files are unformatted before and after removing it, so the
reformat in the next commit is byte-identical either way. The config now
matches nuxt-app/.prettierrc exactly, minus the Tailwind plugin.

Added a .prettierignore for `.claude`. `prettier . --write` walks the
whole tree and was rewriting contributors' untracked
`.claude/settings.local.json` — local tool state that nobody reviews.
Verified with a control: a deliberately unformatted file inside
`.claude/` is not flagged, while the same content outside it is.
`node_modules` and `dist` are deliberately not repeated in that file;
Prettier reads `.gitignore` as well, and the bundle's already covers
both.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BMa3aosYRWyivC4DtPbSNr
Mechanical `prettier . --write` output, no hand edits. Formatting was
never enforced in this tree, so 64 files had drifted from the committed
.prettierrc — one of them the untracked local settings file excluded in
the previous commit, leaving 63 here. The gate that stops this
recurring arrives in the next commit.

Beyond whitespace, this strips semicolons (`semi: false`) and sorts
imports via @ianvs/prettier-plugin-sort-imports, so the diff is not
whitespace-only.

Import reordering is the one way a sweep like this can genuinely break
something, so it was checked first: the only load-time side-effect
imports are `import 'dotenv/config'` in the two Algolia CLI scripts, the
plugin keeps them in the same slot (after third-party, before local),
and the only process.env reads in those files sit below the entire
import block.

Verified against the artefact Directus actually loads, since lint, test
and build are all blind to a formatter by construction and 17 of 26
entries have no tests at all. Built dist/ before and after:

  - app.js: all 43 string literals identical; after normalising every
    identifier, exactly one structural difference, which is the unused
    watch parameters removed in the next commit.
  - api.js: same 18 module specifiers in the same order; 10,554 of
    10,583 literals byte-identical. The 29 that differ are `entities`
    lazy-init blobs varying only in Rollup's internal module variable
    names, a knock-on of modules being emitted in a different order.

Static analysis could not push api.js past "almost certainly
equivalent", so the decisive check was to import both builds in Node and
compare the registry handed to Directus: deep-equal, 23 hooks in the
same order, 2 endpoints, 0 operations. That compares the registry's
shape, not the behaviour of the 23 handlers, which cannot be invoked
without a Directus host.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BMa3aosYRWyivC4DtPbSNr
The bundle's CI job ran npm ci, ESLint and Jest. It did not check
formatting, did not typecheck, and never confirmed the artefact Directus
loads still compiles. This adds the two gates that need no source
changes, plus the config corrections behind them. Phase 0 of
docs/directus-extension-tooling-plan.md; no dependency versions change.

CI (bundle job now: format, lint, test, build)

  - `prettier:check`, not `prettier` — the latter writes, so it would
    pass by mutating.
  - A build step. `directus-extension build` has its own Rollup/esbuild
    pipeline that neither ESLint nor Jest exercises, so a change that
    broke the loadable bundle could merge green.
  - `node-version-file:` reading a new .nvmrc instead of a hardcoded 22,
    so CI, the Docker image and local development have one file to
    change rather than three. Local dev had already drifted to 24.19.0.
  - `shared-code/**` added to the paths filter. The bundle imports from
    there, so those changes were skipping the gate entirely.

Corrected the comment claiming this tree is frozen by the Directus
licence block. It is not: every @directus/* package the bundle uses is
MIT, and only the `directus` server package is blocked. The real reason
to stay on 22 is Dockerfile.directus — Node 24 brings npm 11, which
gates the install scripts this tree's native dependencies need.

Hermetic image build

Both `npm install` calls in Dockerfile.directus become `npm ci`, so the
image can no longer resolve versions the lockfile does not record.
Verified both lockfiles are in sync first (`npm ci --dry-run` exits 0 in
directus-cms and in the bundle), since otherwise this would land a
broken image build.

ESLint now covers the one Vue SFC

`files: ['**/*.ts']` had left presentation-publishable.vue as the only
unlinted source file. Adding eslint-plugin-vue surfaced 2 errors and 20
warnings, the warnings all being formatting rules fighting Prettier —
because eslint-config-prettier was already a dependency but the config
had never applied it. Harmless while the config was TypeScript-only and
enabled no stylistic rules; load-bearing the moment such a plugin
arrives. Applying it last takes the 20 to 0.

That left two genuine errors, unused watch callback parameters, removed
here. The gate was confirmed to actually fire by injecting an unused
variable and watching ESLint fail.

Also removed a dead ignore entry for `**/podcast-transcription/**`; the
directory is `podcast-transcript`, so it had never matched anything.

Docs

TESTING.md claimed exactly one function was tested; there are 15 files
and 205 assertions across 9 of 26 entries. AGENTS.md said formatting was
enforced in nuxt-app only, and pointed at nuxt-app's Prettier config as
if it were the only one.

Verified: prettier:check, lint, test (205/205) and build all green;
npm audit unchanged at 19, which Phase 3 addresses.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BMa3aosYRWyivC4DtPbSNr
Copilot AI lite review requested due to automatic review settings August 5, 2026 19:42
@vercel

vercel Bot commented Aug 5, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
programmierbar-website Ready Ready Preview Aug 5, 2026 8:23pm

Request Review

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

Pull request overview

This PR implements “Phase 0” gating for the Directus extension bundle so CI verifies code style and that the bundle still compiles, aligning the bundle with the repo’s existing “format-first” approach and reducing the risk of shipping an unbuildable Directus artefact.

Changes:

  • Updates CI for the extension bundle to run prettier:check → lint → test → build, and ensures the gate triggers when shared-code/** changes.
  • Adds/updates tooling config for the bundle: introduces .nvmrc-based Node selection, adds Vue SFC linting via eslint-plugin-vue, and wires eslint-config-prettier to prevent Prettier/ESLint rule conflicts.
  • Makes Docker builds more deterministic by switching Directus image installs from npm install to npm ci, and documents the intended Node version coupling.

Reviewed changes

Copilot reviewed 73 out of 75 changed files in this pull request and generated no comments.

Show a summary per file
File Description
Dockerfile.directus Switches to npm ci for hermetic installs; documents Node version alignment with CI.
.github/workflows/run_tests.yml Adds formatting + build gates for the bundle, uses .nvmrc, and includes shared-code/** in path filters.
AGENTS.md Documents the bundle’s full CI gate order alongside existing repo guidance.
directus-cms/extensions/directus-extension-programmierbar-bundle/TESTING.md Updates testing docs to reflect the full CI gate and Jest/CJS constraints.
directus-cms/extensions/directus-extension-programmierbar-bundle/.nvmrc Introduces a single Node-version source for CI/local alignment (bundle).
directus-cms/extensions/directus-extension-programmierbar-bundle/.prettierrc Aligns Prettier config (removes deprecated option).
directus-cms/extensions/directus-extension-programmierbar-bundle/.prettierignore Prevents Prettier from touching local .claude state in the bundle tree.
directus-cms/extensions/directus-extension-programmierbar-bundle/eslint.config.js Adds Vue SFC linting + applies eslint-config-prettier last to avoid formatter conflicts.
directus-cms/extensions/directus-extension-programmierbar-bundle/jest.config.ts Formatting-only adjustments to Jest configuration file.
directus-cms/extensions/directus-extension-programmierbar-bundle/package.json Adds prettier:check, adds eslint-plugin-vue, declares Node engines baseline.
directus-cms/extensions/directus-extension-programmierbar-bundle/package-lock.json Locks new eslint-plugin-vue (and transitive) additions.
directus-cms/extensions/directus-extension-programmierbar-bundle/src/publishable/presentation-publishable.vue Removes unused watcher parameters to satisfy Vue linting.
directus-cms/extensions/directus-extension-programmierbar-bundle/src/ticket-wallet/index.ts Import ordering/formatting consistency.
directus-cms/extensions/directus-extension-programmierbar-bundle/src/ticket-profile-completion/index.ts Formatting/import ordering; no behavior change intended.
directus-cms/extensions/directus-extension-programmierbar-bundle/src/ticket-order-processing/index.ts Formatting/import ordering; no behavior change intended.
directus-cms/extensions/directus-extension-programmierbar-bundle/src/speaker-token/index.ts Formatting/import ordering; no behavior change intended.
directus-cms/extensions/directus-extension-programmierbar-bundle/src/speaker-portal-notifications/index.ts Formatting and minor layout changes for readability/lint.
directus-cms/extensions/directus-extension-programmierbar-bundle/src/social-media-publish/index.ts Formatting and line-wrapping for lint/Prettier compliance.
directus-cms/extensions/directus-extension-programmierbar-bundle/src/screenshot/index.ts Formatting of action registration for lint/Prettier compliance.
directus-cms/extensions/directus-extension-programmierbar-bundle/src/process-guard/index.ts Formatting of Slack notification call chain.
directus-cms/extensions/directus-extension-programmierbar-bundle/src/post-to-discord/index.ts Import ordering/formatting consistency.
directus-cms/extensions/directus-extension-programmierbar-bundle/src/content-approval/index.ts Formatting of action handler registration and expressions.
directus-cms/extensions/directus-extension-programmierbar-bundle/src/conference/index.ts Formatting cleanup for endpoint implementation.
directus-cms/extensions/directus-extension-programmierbar-bundle/src/deploy-website/index.ts Formatting cleanup for hook registration and log statements.
directus-cms/extensions/directus-extension-programmierbar-bundle/src/create-profile/index.ts Formatting cleanup and minor type formatting for lint/Prettier compliance.
directus-cms/extensions/directus-extension-programmierbar-bundle/src/set-slug/index.ts Formatting cleanup; removes stray semicolons/blank lines.
directus-cms/extensions/directus-extension-programmierbar-bundle/src/set-slug/util/getPayloadWithSlug.ts Formatting cleanup; ensures consistent object commas/ASI safety.
directus-cms/extensions/directus-extension-programmierbar-bundle/src/podcast-transcript/index.ts Formatting cleanup and consistent hook/schedule registration layout.
directus-cms/extensions/directus-extension-programmierbar-bundle/src/podcast-transcript/generateTranscriptItem.ts Formatting cleanup; minor object literal layout adjustments.
directus-cms/extensions/directus-extension-programmierbar-bundle/src/podcast-transcript/processTranscriptItem.ts Formatting cleanup; minor object literal layout adjustments.
directus-cms/extensions/directus-extension-programmierbar-bundle/src/member-matching/index.ts Import ordering/formatting consistency.
directus-cms/extensions/directus-extension-programmierbar-bundle/src/member-matching/matchMembers.ts Formatting cleanup, especially for long regex literals and log lines.
directus-cms/extensions/directus-extension-programmierbar-bundle/src/asset-generation/index.ts Formatting cleanup for action registrations and async error handling blocks.
directus-cms/extensions/directus-extension-programmierbar-bundle/src/asset-generation/generateAssets.ts Formatting cleanup and line wrapping for long calls.
directus-cms/extensions/directus-extension-programmierbar-bundle/src/shared/email-service.ts Formatting cleanup for exported function signature.
directus-cms/extensions/directus-extension-programmierbar-bundle/src/shared/gemini.ts Formatting cleanup for inline predicate.
directus-cms/extensions/directus-extension-programmierbar-bundle/src/shared/invoice-generator.ts Formatting cleanup and line wrapping for PDFKit chains and signatures.
directus-cms/extensions/directus-extension-programmierbar-bundle/src/shared/isPublishable.ts Formatting cleanup; introduces explicit ASI-safe semicolons for IIFE logging.
directus-cms/extensions/directus-extension-programmierbar-bundle/src/shared/wallet-pass-generator.ts Formatting cleanup for exported function signature.
directus-cms/extensions/directus-extension-programmierbar-bundle/src/algolia-index/index.ts Formatting cleanup and improved structure for helper functions/actions.
directus-cms/extensions/directus-extension-programmierbar-bundle/src/algolia-index/util/pagination.ts Formatting cleanup for async generators and helper functions.
directus-cms/extensions/directus-extension-programmierbar-bundle/src/algolia-index/util/sanitizer.ts Formatting cleanup and consistent object literal style.
directus-cms/extensions/directus-extension-programmierbar-bundle/src/algolia-index/handlers/ItemHandler.ts Formatting cleanup for interface/abstract base class.
directus-cms/extensions/directus-extension-programmierbar-bundle/src/algolia-index/handlers/index.ts Formatting cleanup and quote/style normalization.
directus-cms/extensions/directus-extension-programmierbar-bundle/src/algolia-index/handlers/MeetupHandler.ts Formatting cleanup; improves readability of payload-fitting logic.
directus-cms/extensions/directus-extension-programmierbar-bundle/src/algolia-index/handlers/PodcastHandler.ts Formatting cleanup for returned payload array structure.
directus-cms/extensions/directus-extension-programmierbar-bundle/src/algolia-index/handlers/PickOfTheDayHandler.ts Formatting cleanup for returned payload array structure.
directus-cms/extensions/directus-extension-programmierbar-bundle/src/algolia-index/handlers/SpeakerHandler.ts Formatting cleanup for indexFields and payload structure.
directus-cms/extensions/directus-extension-programmierbar-bundle/src/algolia-index/handlers/TranscriptHandler.ts Formatting cleanup; simplifies some expressions and normalizes style.
directus-cms/extensions/directus-extension-programmierbar-bundle/src/algolia-index/cli/rebuild-index.ts Formatting cleanup for CLI structure and logging.
directus-cms/extensions/directus-extension-programmierbar-bundle/src/algolia-index/cli/repair-index.ts Formatting cleanup for CLI structure and logging.
directus-cms/extensions/directus-extension-programmierbar-bundle/src/buzzsprout/index.ts Formatting cleanup; wraps long warning log and normalizes semicolons.
directus-cms/extensions/directus-extension-programmierbar-bundle/src/buzzsprout/handlers/buzzsprout.ts Formatting cleanup; normalizes axios config and error logging style.
directus-cms/extensions/directus-extension-programmierbar-bundle/src/buzzsprout/handlers/handlePodcastAction.ts Formatting cleanup; normalizes condition grouping and error string quotes.
directus-cms/extensions/directus-extension-programmierbar-bundle/src/buzzsprout/handlers/handlePickOfTheDayAction.ts Formatting cleanup; normalizes imports.
directus-cms/extensions/directus-extension-programmierbar-bundle/src/buzzsprout/handlers/handleTagAction.ts Formatting cleanup; normalizes imports.
directus-cms/extensions/directus-extension-programmierbar-bundle/src/buzzsprout/handlers/podcastData.ts Formatting cleanup; normalizes initialization style.
directus-cms/extensions/directus-extension-programmierbar-bundle/src/cascade-publish/index.ts Formatting cleanup for Slack message assembly.
directus-cms/extensions/directus-extension-programmierbar-bundle/src/create-news/index.ts Formatting cleanup for long log/error statements.
directus-cms/extensions/directus-extension-programmierbar-bundle/src/fetch-open-graph/tests/index.test.ts Formatting cleanup and import ordering for Jest tests.
directus-cms/extensions/directus-extension-programmierbar-bundle/src/fetch-open-graph/util/tests/openGraph.test.ts Formatting cleanup for long test call expressions.
directus-cms/extensions/directus-extension-programmierbar-bundle/src/fetch-open-graph/util/tests/urlSafety.test.ts Formatting cleanup for long expect chains.
directus-cms/extensions/directus-extension-programmierbar-bundle/src/cascade-publish/tests/index.test.ts Formatting cleanup and import ordering for Jest tests.
directus-cms/extensions/directus-extension-programmierbar-bundle/src/create-news/tests/index.test.ts Formatting cleanup and import ordering for Jest tests.
directus-cms/extensions/directus-extension-programmierbar-bundle/src/create-news/util/tests/newsTarget.test.ts Formatting cleanup for test data layout.
directus-cms/extensions/directus-extension-programmierbar-bundle/src/member-matching/tests/matchMembers.test.ts Formatting cleanup for imports.
directus-cms/extensions/directus-extension-programmierbar-bundle/src/schedule-publication/tests/index.test.ts Import ordering/formatting consistency for Jest tests.
directus-cms/extensions/directus-extension-programmierbar-bundle/src/set-slug/tests/README.md Formatting cleanup for markdown list indentation.
directus-cms/extensions/directus-extension-programmierbar-bundle/src/set-slug/tests/getPayloadWithSlug.test.ts Formatting cleanup and import ordering for Jest tests.
directus-cms/extensions/directus-extension-programmierbar-bundle/src/shared/tests/isPublishable.test.ts Formatting cleanup and import ordering for Jest tests.
directus-cms/extensions/directus-extension-programmierbar-bundle/src/shared/tests/podcasts_fields.json JSON formatting normalization.
directus-cms/extensions/directus-extension-programmierbar-bundle/src/shared/tests/safeHook.test.ts Import ordering/formatting consistency for Jest tests.
directus-cms/extensions/directus-extension-programmierbar-bundle/src/shared/tests/settings.test.ts Formatting cleanup for long expect chains.
directus-cms/extensions/directus-extension-programmierbar-bundle/src/shared/tests/test-wallet-passes.ts Formatting cleanup for fetch calls and type assertions.
Files not reviewed (1)
  • directus-cms/extensions/directus-extension-programmierbar-bundle/package-lock.json: Generated file

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

The plan put coverage in Phase 5, after the dependency upgrades. That was
wrong. It inherited the nuxt-app plan's shape, where coverage sat in a
follow-up backlog, without re-deriving it for a tree whose upgrades and
untested modules overlap almost exactly.

Measured: of the 16 files the planned bumps touch, 3 have a test covering
them. algolia-index — largest module in the bundle, zero tests — is hit
by four separate bumps: the sanitize-html critical, algoliasearch,
@directus/sdk and meow.

The old Phase 3 contained the tell. It required a manual step, "verify
the Algolia indexer specifically … a broken indexer fails silently". A
hand-verification instruction inside an upgrade phase is an admission
that the automated check should have come first. That step is gone,
replaced by Phase 3 item 1.

New order: 3 contract tests, 4 security and minors, 5 E2E harness,
6 majors, 7 Renovate.

Tier 3 also moves ahead of the majors, for the same reason rather than
for symmetry: the E2E harness is the only thing that can validate
@directus/extensions-sdk 18 against the frozen 11.17.4 host, which is
Phase 6's riskiest item and one the plan already says not to merge
unverified.

Phase 3 is now ordered by which upgrade each entry protects rather than
by LOC. That mostly agrees with the old table, but promotes
shared/postSlackMessage to second — 26 lines, and the
failure-notification path @slack/web-api 7→8 breaks — and pulls
shared/invoice-generator in for pdfkit. Neither appeared before, because
shared/ is not a bundle "entry".

The sanitize-html critical is carved out and does not wait: holding a
security patch behind a multi-PR test phase is the wrong trade. It ships
with unit tests for sanitizer.ts in the same PR, including an assertion
for the advisory's actual vector — content inside <xmp> must not pass
through unescaped — so it is a regression test, not just coverage.

ADR 0003 records the three tiers, the audit of all 11 outbound
integrations (6 already redirectable by env, 5 hardcoded), and the two
harness rules: a fail-closed stub, and no secrets in the environment at
all rather than fake-but-plausible values, so a missed redirect dies on a
connection error instead of reaching the production Slack.

It also records the cost that matters most: Tier 2 fakes the shape of the
Directus hook context, so a Directus upgrade that changes that shape lets
the fakes drift and pass while production breaks. That is what Tier 3 is
insurance against, and why it cannot be dropped despite being small.

ADR 0003 complements ADR 0001 rather than superseding it — the
util/-extraction guidance there is Tier 1 and still stands. Only ADR
0001's module-format half gets superseded, so Phase 2's Vitest ADR is
renumbered to 0004.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BMa3aosYRWyivC4DtPbSNr

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

Pull request overview

Copilot reviewed 74 out of 76 changed files in this pull request and generated no new comments.

Files not reviewed (1)
  • directus-cms/extensions/directus-extension-programmierbar-bundle/package-lock.json: Generated file
Suppressed comments (4)

directus-cms/extensions/directus-extension-programmierbar-bundle/src/shared/isPublishable.ts:52

  • This log statement is wrapped in an unnecessary IIFE. A direct optional call is clearer and avoids ASI hazards.
    directus-cms/extensions/directus-extension-programmierbar-bundle/src/shared/isPublishable.ts:73
  • These logger statements are wrapped in unnecessary IIFEs. Direct optional calls are clearer and avoid the leading-semicolon workaround.
    directus-cms/extensions/directus-extension-programmierbar-bundle/src/create-profile/index.ts:55
  • This comment is unreachable (it sits after a return inside the try block). It looks like it was meant to describe the catch below; removing it avoids confusion.
    directus-cms/extensions/directus-extension-programmierbar-bundle/src/shared/isPublishable.ts:41
  • The logger calls are wrapped in an unnecessary IIFE and require a leading semicolon to avoid ASI. This reduces readability and is easy to simplify without changing behavior.

This issue also appears in the following locations of the same file:

  • line 50
  • line 67

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