-
Notifications
You must be signed in to change notification settings - Fork 0
feat(standards): adopt the Druxt repository standard with a Drupal 11 example #80
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
Decipher
wants to merge
27
commits into
main
Choose a base branch
from
feat/repo-standards
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
27 commits
Select commit
Hold shift + click to select a range
4d1e4b3
feat(standards): adopt the Druxt repository standard
e282de8
fix(ci): pin CodeQL actions and arm the visual job only when baseline…
fe2286d
feat(standards): forbid AI attribution and lint prose, as the standar…
Decipher d5f3cf3
fix(devcontainer): generate common locales and greet each new terminal
Decipher 41febc8
fix(devcontainer): install mise through gh-release, the contrib featu…
Decipher 6e774d0
feat(example): run the example on Drupal 11 without Docker and test i…
Decipher 33aeca2
ci(gitlab): give node-gyp the distutils shim it needs to build deasync
Decipher 864cd0a
ci: skip native install scripts in the Playwright jobs and spell the …
Decipher 9efc5b3
fix(devcontainer): drop the php image's stale Yarn apt source before …
Decipher b8b8d61
fix(devcontainer): pass PHP_INI_DIR through sudo so the extensions en…
Decipher bb5bec8
fix(devcontainer): install the build tooling deasync needs and the Pl…
Decipher d01e7e9
fix(devcontainer): build on the trixie base image so SQLite meets the…
Decipher f57f08f
fix(devcontainer): give Playwright a package list trixie can resolve
Decipher 9b68fa9
fix(devcontainer): include the architecture in the Playwright platfor…
Decipher ee5e21c
ci(coderabbit): filter the generated Drupal files out of the review
Decipher b6635d6
fix(serve): survive a malformed percent escape in the request path
Decipher 90261bf
ci: wait for the static server to answer instead of sleeping
Decipher 5fdbd76
fix(scripts): fail the note scripts on an API error, and page the lookup
Decipher 8c7e217
fix(devcontainer): check every forwarded locale, not only LANG
Decipher e7b71f4
fix(lint): find RFC1918 addresses inside IPv4-mapped IPv6 literals
Decipher 324fb38
fix(example): check the process on the port is the server we started
Decipher 59a20a2
fix(knip): analyse the server file the package actually runs
Decipher ba1b69d
docs: describe the checks the pipelines now run
Decipher 2381440
fix(scripts): keep retries off the note writes, and reject a garbled …
Decipher e0eb574
fix(lint): normalise every IPv4-mapped IPv6 spelling before the check
Decipher 31f4827
fix(devcontainer): cover every locale category the host can forward
Decipher 26bffea
ci: bound each readiness probe so the deadline holds
Decipher File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| # Informational, not blocking. The blocking gate is jest's coverageThreshold, | ||
| # which fails the job locally and in CI without depending on an external | ||
| # service being reachable. This adds the per-merge-request diff view on top. | ||
| coverage: | ||
| status: | ||
| project: | ||
| default: | ||
| target: auto | ||
| threshold: 1% | ||
| informational: true | ||
| patch: | ||
| default: | ||
| target: 80% | ||
| informational: true | ||
|
|
||
| comment: | ||
| layout: 'reach, diff, flags, files' | ||
| behavior: default |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json | ||
| # | ||
| # CodeRabbit skips any review over 100 changed files, and a Drupal example | ||
| # carries hundreds of generated ones. The filters below leave the module, the | ||
| # tooling and the pipelines, which is what a reviewer can act on. | ||
| language: en-AU | ||
| reviews: | ||
| path_filters: | ||
| # Drupal's own exports, written by drush, never by hand. | ||
| - '!example/drupal/config/**' | ||
| - '!example/drupal/content/**' | ||
| # Composer's scaffolded docroot. | ||
| - '!example/drupal/web/**' | ||
| # Lock files. | ||
| - '!**/package-lock.json' | ||
| - '!**/composer.lock' | ||
| # Playwright baselines. | ||
| - '!test/e2e/__snapshots__/**' | ||
| auto_review: | ||
| enabled: true | ||
| drafts: false |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| # Words this project uses that the standard dictionaries do not carry. | ||
| # Add a term here rather than switching the check off for a file. | ||
| actionlint | ||
| autobuild | ||
| Autobuild | ||
| automerge | ||
| behaviour | ||
| bookworm | ||
| cloudflared | ||
| Codespaces | ||
| colour | ||
| commitlint | ||
| consola | ||
| corepack | ||
| cspell | ||
| davidanson | ||
| dbaeumer | ||
| DDEV | ||
| devcontainer | ||
| devcontainers | ||
| druxt | ||
| Druxt | ||
| druxtjs | ||
| esbenp | ||
| esbuild | ||
| freetype | ||
| gitleaks | ||
| hverlin | ||
| hyperscript | ||
| interruptible | ||
| jsonapi | ||
| knip | ||
| Ksection | ||
| Lando | ||
| libfreetype | ||
| libicu | ||
| libjpeg | ||
| libonig | ||
| libpng | ||
| libsqlite | ||
| libxml | ||
| libzip | ||
| Licence | ||
| lndo | ||
| markdownlint | ||
| mise | ||
| networkidle | ||
| nproc | ||
| Nuxt | ||
| nuxt | ||
| nvm | ||
| nvmrc | ||
| opcache | ||
| opencode | ||
| pdo | ||
| pyyaml | ||
| shivammathur | ||
| siroc | ||
| sqlite | ||
| unparseable | ||
| vfox | ||
| viewports | ||
| yamllint |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| { | ||
| "files": ["**/*.{js,mjs,vue,json,jsonc,md,yml,yaml}"], | ||
| "dictionaryDefinitions": [ | ||
| { | ||
| "name": "project-words", | ||
| "path": "./.cspell-project-words.txt" | ||
| } | ||
| ], | ||
| "dictionaries": ["project-words", "bash", "misc", "node", "softwareTerms"], | ||
| "ignorePaths": [ | ||
| ".git/", | ||
| "node_modules/", | ||
| "**/node_modules/", | ||
| "dist/", | ||
| "coverage/", | ||
| "reports/", | ||
| "test-results/", | ||
| "playwright-report/", | ||
| "example/drupal/", | ||
| "**/CHANGELOG.md", | ||
| "*.lock", | ||
| "package-lock.json", | ||
| "*.svg", | ||
| "*.png", | ||
| "*.snap", | ||
| ".vale/", | ||
| "example/drupal/vendor/", | ||
| "example/drupal/web/", | ||
| "example/nuxt/dist/", | ||
| "example/nuxt/.nuxt/" | ||
| ], | ||
| "useGitignore": true, | ||
| "words": [ | ||
| "coderabbit", | ||
| "deasync", | ||
| "distutils", | ||
| "docroot", | ||
| "drush", | ||
| "libwebp", | ||
| "phpize", | ||
| "setuptools", | ||
| "trixie", | ||
| "webp" | ||
| ] | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| { | ||
| "name": "Druxt module", | ||
| // PHP for the example's Drupal backend, provisioned without Docker by | ||
| // example/drupal/.devtools. The PHP feature builds against trixie's | ||
| // libsqlite3, which meets Drupal 11's 3.45 minimum; the PHP image is on | ||
| // bookworm's 3.40 and cannot install it. Node 16 for the module comes from | ||
| // its feature: Nuxt 2 builds on webpack 4, which does not run on a newer Node. | ||
| "image": "mcr.microsoft.com/devcontainers/base:trixie", | ||
| "features": { | ||
| "ghcr.io/devcontainers/features/node:1": { | ||
| "version": "16.20.1" | ||
| }, | ||
| "ghcr.io/devcontainers/features/php:1": { | ||
| "version": "8.4", | ||
| "installComposer": true | ||
| }, | ||
| "ghcr.io/devcontainers/features/github-cli:1": {}, | ||
| // Installed through gh-release rather than a mise feature: the | ||
| // devcontainers-contrib registry that hosted one is gone, and the | ||
| // devcontainers-extra one asks for the "latest" jdx/mise release with | ||
| // no tag filter, which now resolves to a vfox-* release with no asset. | ||
| // The regex keeps this on mise's own v-tags. Same setup as druxt.js. | ||
| "ghcr.io/devcontainers-extra/features/gh-release:1": { | ||
| "repo": "jdx/mise", | ||
| "binaryNames": "mise", | ||
| "assetRegex": ".tar.gz$", | ||
| "releaseTagRegex": "^v[0-9]+\\.[0-9]+\\.[0-9]+$" | ||
| } | ||
| }, | ||
| "containerEnv": { | ||
| // Node and PHP come from the image and features; .mise.toml's pins are | ||
| // for host users. Without this, `mise install` builds both from source | ||
| // in here. | ||
| "MISE_DISABLE_TOOLS": "node,php", | ||
| // Pin the example backend's port so the forward below always matches. | ||
| "WEBSERVER_PORT": "8888" | ||
| }, | ||
| "postCreateCommand": "bash .devcontainer/post-create.sh", | ||
| "customizations": { | ||
| "vscode": { | ||
| "extensions": [ | ||
| "hverlin.mise-vscode", | ||
| "dbaeumer.vscode-eslint", | ||
| "esbenp.prettier-vscode", | ||
| "davidanson.vscode-markdownlint", | ||
| "streetsidesoftware.code-spell-checker", | ||
| "ms-playwright.playwright", | ||
| "editorconfig.editorconfig" | ||
| ], | ||
| "settings": { | ||
| // Where the gh-release feature puts the binary. The extension's | ||
| // default bare "mise" is treated as workspace-relative and | ||
| // re-prompts for approval on every reload. | ||
| "mise.binPath": "/usr/local/bin/mise", | ||
| "editor.formatOnSave": true, | ||
| "editor.defaultFormatter": "esbenp.prettier-vscode", | ||
| "eslint.validate": ["javascript", "vue"] | ||
| } | ||
| } | ||
| }, | ||
| "forwardPorts": [3000, 8888], | ||
| "portsAttributes": { | ||
| "3000": { | ||
| "label": "Example application", | ||
| "onAutoForward": "notify" | ||
| }, | ||
| "8888": { | ||
| "label": "Example backend (example/drupal/.devtools)", | ||
| "onAutoForward": "silent" | ||
| } | ||
| }, | ||
| "remoteUser": "vscode" | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,86 @@ | ||
| #!/usr/bin/env bash | ||
| # One definition for VS Code, Codespaces and DevPod, replacing the Gitpod | ||
| # configuration that drifted in every repository still carrying one. | ||
| # | ||
| # Idempotent: a devcontainer gets rebuilt, and a post-create step that only | ||
| # works on a clean container is a step that fails the second time. | ||
| set -euo pipefail | ||
|
|
||
| echo "Trusting this repository's .mise.toml..." | ||
| mise trust | ||
|
|
||
| # PHP comes from the dev container PHP feature, built from source against | ||
| # trixie's libsqlite3: Drupal 11 needs 3.45 or later. The feature leaves gd | ||
| # out, and Drupal's installer requires it, so gd is built from PHP's own | ||
| # source tree below. sqlite3 is the CLI drush uses to reset the throwaway | ||
| # database. | ||
| echo "Installing build tooling and image libraries..." | ||
| sudo apt-get update -qq > /dev/null | ||
| # python3-setuptools: trixie's Python 3.13 has no distutils, and the node-gyp | ||
| # bundled with Node 16's npm still imports it when vue-jest's deasync builds. | ||
| sudo apt-get install -y -qq python3 python3-setuptools build-essential sqlite3 libjpeg-dev libpng-dev libwebp-dev libfreetype-dev zlib1g-dev > /dev/null | ||
|
|
||
| CONF_DIR=$(php --ini | grep 'Scan for additional .ini files' | sed 's/.*: *//') | ||
|
|
||
| # The feature ships Xdebug active on every request, so each CLI call would | ||
| # warn that no debugger is listening. Trigger mode keeps it available on demand. | ||
| echo 'xdebug.start_with_request = trigger' | sudo tee "$CONF_DIR/zz-xdebug-trigger.ini" > /dev/null | ||
|
|
||
| echo "Building the gd extension from PHP's source tree..." | ||
| PHP_FULL_VERSION=$(php -r 'echo PHP_VERSION;') | ||
| PHP_SRC_TMP="$(mktemp -d)" | ||
| trap 'rm -rf "$PHP_SRC_TMP"' EXIT | ||
| mkdir -p "$PHP_SRC_TMP/gd" | ||
| curl -fsSL "https://www.php.net/distributions/php-${PHP_FULL_VERSION}.tar.gz" -o "$PHP_SRC_TMP/php-src.tar.gz" | ||
| tar -xzf "$PHP_SRC_TMP/php-src.tar.gz" -C "$PHP_SRC_TMP/gd" --strip-components=3 "php-${PHP_FULL_VERSION}/ext/gd" | ||
| ( | ||
| cd "$PHP_SRC_TMP/gd" | ||
| phpize > /dev/null | ||
| ./configure --with-jpeg --with-webp --with-freetype > /dev/null | ||
| make -j"$(nproc)" > /dev/null | ||
| sudo make install > /dev/null | ||
| ) | ||
| echo 'extension=gd' | sudo tee "$CONF_DIR/gd.ini" > /dev/null | ||
| php -r "exit(extension_loaded('gd') && extension_loaded('pdo_sqlite') ? 0 : 1);" || { echo "gd or pdo_sqlite is not loaded" >&2; exit 1; } | ||
|
|
||
| echo "Installing dependencies..." | ||
| npm install | ||
|
|
||
| # Playwright does not know trixie and falls back to a package list from | ||
| # Ubuntu 20.04, whose font packages no longer exist. Its Ubuntu 24.04 list | ||
| # uses the same t64 names as trixie and every package in it is available here. | ||
| # The platform key carries the architecture. | ||
| echo "Installing the Playwright browser for the end-to-end tests..." | ||
| case "$(uname -m)" in aarch64 | arm64) PLAYWRIGHT_ARCH=arm64 ;; *) PLAYWRIGHT_ARCH=x64 ;; esac | ||
| PLAYWRIGHT_HOST_PLATFORM_OVERRIDE="ubuntu24.04-$PLAYWRIGHT_ARCH" npx playwright install --with-deps chromium > /dev/null | ||
|
|
||
| echo "Building the module, which the example links to by path..." | ||
| npm run build | ||
|
|
||
| echo "Provisioning and starting the example backend, then installing the example..." | ||
| npm run example:setup | ||
|
|
||
| # npm install enables the hooks via scripts/postinstall.mjs. Repeated here for | ||
| # the case where the container was built with install scripts disabled, which | ||
| # is a common hardening default. | ||
| echo "Enabling git hooks..." | ||
| git config core.hooksPath .githooks | ||
|
|
||
| # OpenSSH forwards the host's LANG and LC_*, and bash warns on every start | ||
| # when that locale is not generated here. This covers the usual English | ||
| # ones before the shell starts; shell-init.sh falls back for anything else. | ||
| echo "Generating the English locales hosts commonly send over SSH..." | ||
| sudo apt-get update -qq > /dev/null | ||
| sudo apt-get install -y -qq locales > /dev/null | ||
| sudo sed -i -E 's/^# (en_(AU|CA|GB|IE|NZ|US)\.UTF-8 UTF-8)/\1/' /etc/locale.gen | ||
| sudo locale-gen > /dev/null | ||
|
|
||
| # Sourced from ~/.bashrc rather than run once here, so every new terminal | ||
| # gets the locale fix and the summary, not only the creation log. | ||
| echo "Installing the shell locale fallback and welcome..." | ||
| if ! grep -qF '.devcontainer/shell-init.sh' ~/.bashrc; then | ||
| printf '\n# Dev container shell setup: locale fallback and welcome.\nexport WORKSPACE_ROOT=%q\n[ -f "$WORKSPACE_ROOT/.devcontainer/shell-init.sh" ] && . "$WORKSPACE_ROOT/.devcontainer/shell-init.sh"\n' "$PWD" >> ~/.bashrc | ||
| fi | ||
|
|
||
| echo | ||
| echo "Ready. Open a new terminal for the summary of commands." |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| #!/usr/bin/env bash | ||
| # Sourced by ~/.bashrc inside the dev container. post-create.sh installs the | ||
| # line that sources it, so a fresh container gets both halves below. | ||
|
|
||
| # The host's locale arrives over SSH: OpenSSH sends LANG and LC_* by default, | ||
| # and DevPod's shell inherits them. When the value names a locale this image | ||
| # has not generated, every command warns "setlocale: cannot change locale" | ||
| # and manpath gives up. Fall back to the image's UTF-8 locale instead. | ||
| # Every forwarded value is checked, not only LANG: a host that sends an | ||
| # ungenerated LC_TIME warns just as loudly as one that sends an ungenerated LANG. | ||
| available="$(locale -a 2>/dev/null)" | ||
| for forwarded in "${LANG:-}" "${LC_ALL:-}" "${LC_ADDRESS:-}" "${LC_COLLATE:-}" \ | ||
| "${LC_CTYPE:-}" "${LC_IDENTIFICATION:-}" "${LC_MEASUREMENT:-}" "${LC_MESSAGES:-}" \ | ||
| "${LC_MONETARY:-}" "${LC_NAME:-}" "${LC_NUMERIC:-}" "${LC_PAPER:-}" \ | ||
| "${LC_TELEPHONE:-}" "${LC_TIME:-}"; do | ||
| case "$forwarded" in '' | C | C.* | POSIX) continue ;; esac | ||
| if ! printf '%s\n' "$available" | grep -qix "$(printf '%s' "$forwarded" | sed 's/UTF-8$/utf8/')"; then | ||
| export LANG=C.UTF-8 | ||
| unset LC_ALL LC_ADDRESS LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ | ||
| LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ | ||
| LC_TELEPHONE LC_TIME | ||
| break | ||
| fi | ||
| done | ||
| unset available forwarded | ||
|
|
||
| # The rest is for a person at a prompt. | ||
| case $- in *i*) ;; *) return 0 2>/dev/null || exit 0 ;; esac | ||
|
|
||
| backend="not started" | ||
| if [ -f "${WORKSPACE_ROOT:-$PWD}/example/.env" ]; then | ||
| backend="$(sed -n 's/^BASE_URL=//p' "${WORKSPACE_ROOT:-$PWD}/example/.env" | head -1)" | ||
| backend="${backend:-not started}" | ||
| fi | ||
|
|
||
| cat <<EOF | ||
|
|
||
| Druxt module template | ||
| npm run build Build the module | ||
| npm test Unit tests, with the coverage floor enforced | ||
| npm run lint Every linter except prose | ||
| npm run lint:prose Vale, after \`npm run lint:prose:install\` | ||
|
|
||
| Example application, backend: ${backend} | ||
| npm run example:dev Nuxt on http://localhost:3000 with the module linked | ||
| npm run test:e2e Playwright against the example | ||
| npm run example:info Backend details; example:stop and example:start | ||
|
|
||
| EOF | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,8 +1,21 @@ | ||
| module.exports = { | ||
| // root: true stops ESLint walking up past this repository. Without it, a | ||
| // checkout inside another workspace inherits that workspace's rules, which is | ||
| // exactly how a submodule ends up linted by its parent's configuration. | ||
| root: true, | ||
| env: { browser: true, es6: true, node: true }, | ||
| parserOptions: { ecmaVersion: 2022, sourceType: 'module' }, | ||
| extends: [ | ||
| 'eslint:recommended', | ||
| 'plugin:nuxt/recommended', | ||
| 'plugin:vue/recommended' | ||
| 'plugin:vue/recommended', | ||
| // Last, so formatting rules that would fight Prettier are turned off. | ||
| 'prettier', | ||
| ], | ||
| overrides: [ | ||
| { | ||
| files: ['*.test.js', 'test/**/*.js'], | ||
| env: { jest: true }, | ||
| }, | ||
| ], | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| #!/usr/bin/env sh | ||
| # Conventional Commits, checked before the commit exists rather than in CI. | ||
| # | ||
| # These repositories squash-merge, so the merge request or pull request title | ||
| # becomes the commit subject too. A prose title breaks the next push to the | ||
| # target branch for everyone, not just its author. | ||
| exec npx --no -- commitlint --edit "$1" |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win
Include all locale categories in both lists.
If SSH forwards an invalid
LC_ADDRESS,LC_IDENTIFICATION,LC_MEASUREMENT,LC_NAME,LC_PAPER, orLC_TELEPHONE, the loop does not select the fallback and the invalid variable remains active. Locale-aware commands can then continue to emit locale warnings despite a validLANG. Add these six variables to both the validation loop and the clearing list.🤖 Prompt for AI Agents