Skip to content

Docs, agent harness, and worktree helper (D11/12 groundwork)#468

Open
andypost wants to merge 1 commit into
masterfrom
harness-start
Open

Docs, agent harness, and worktree helper (D11/12 groundwork)#468
andypost wants to merge 1 commit into
masterfrom
harness-start

Conversation

@andypost

Copy link
Copy Markdown
Contributor

What

Establishes narrative documentation, an inheritable Claude Code agent harness, and a
parallel-environment helper for this template, plus the Drupal 11/12 transitional upgrade
runbook
. Documentation + scaffolding only — no runtime behavior changes.

Why

The review-app mechanism, install flow, and upgrade path lived only in .gitlab-ci.yml / Makefile
with no narrative docs; the repo is pinned to Drupal 10.3; and there was no agent scaffolding. This
PR is the groundwork to make the template easy to maintain via agents and to move it to D11/12.

Contents

docs/review-apps.md (lifecycle, Traefik URLs, TTLs, CI/CD vars), ci-pipeline.md
(job → make target map, the cinsp ordering rule #323), architecture.md, local-development.md
(+macOS #400), upgrading.md (D10→11→12), observability.md (logs + opt-in OTel traces),
parallel-environments.md (git-worktree stacks), delivery-and-ops.md, backlog.md, index.

.claude/settings.json allowlist; 5 skills (drupal-upgrade, dep-bump,
review-app-triage, backlog-grooming, observability-up); 3 subagents (upgrade-validator,
ci-log-analyzer, dep-bumper); 2 workflows (drupal-upgrade, newrelic-bump). Forks inherit it;
existing projects copy .claude/ once.

scripts/makefile/worktree.mkmake worktree-name derives a unique COMPOSE_PROJECT_NAME /
MAIN_DOMAIN_NAME per git worktree for parallel local stacks.

RootCONTRIBUTING.md; expanded CLAUDE.md and README.md with doc/harness links.

Verified facts baked in

  • skilldlabs/druxxy gates D11: latest v1.5.1 requires drupal/core-recommended: ^10.6; no
    published version allows ^11. The runbook documents the gate + a PROFILE_NAME=standard workaround.
  • skilldlabs/php:84-* images exist → D12's PHP 8.4 requirement is satisfiable.
  • palantirnet/drupal-rector needs a bump from ^0.20.3 (latest 1.0.0-beta2); upgrade_status
    is the readiness authority.
  • Nginx Unit is already the default again (commit 35a7f38) → issue Set Nginx Unit as default instead of FrankenPHP  #467 effectively done.

Not in this PR (deferred / tracked separately)

  • The actual D11 composer.json bump + green review-app proof (needs Docker and a D11-capable druxxy).
  • Landing/rebasing PR Open Telemetry tracing #466 (OpenTelemetry) for the traces tier.

A tracking issue enumerates the remaining workstreams.

Verification

  • All relative markdown links resolve; .claude/settings.json is valid JSON; both workflow scripts
    pass an ES-module syntax check in the harness's async context.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Pv3rn53U7YYUuYFutvFCzD

@andypost

Copy link
Copy Markdown
Contributor Author

Progress for the whole initiative (D11/12, observability, harness dry-runs, backlog) is tracked in #469.

@gemini-code-assist gemini-code-assist Bot 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.

Code Review

This pull request introduces a Claude Code agent harness under .claude/ (including skills, subagents, and workflows) and adds comprehensive documentation in docs/ to support agent-driven maintenance, parallel local environments, and CI review apps. Feedback highlights a potential ReferenceError in the upgrade workflow if the global budget object is undefined, and addresses macOS compatibility issues with sed -i in both the Makefile helper and the documentation, suggesting more portable alternatives.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread .claude/workflows/drupal-upgrade.workflow.js Outdated
Comment thread scripts/makefile/worktree.mk Outdated
Comment thread docs/parallel-environments.md
@andypost

Copy link
Copy Markdown
Contributor Author

@codex review once

@andypost

Copy link
Copy Markdown
Contributor Author

/gemini review

@gemini-code-assist gemini-code-assist Bot 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.

Code Review

This pull request introduces a comprehensive Claude Code agent harness under .claude/ (including skills, subagents, and workflows) and extensive narrative documentation under docs/ to make the template agent-manageable. It also adds a static validation script validate-harness.mjs and Makefile helpers to support parallel local environments and CI validation. The review feedback identifies several critical issues: non-portable sed -i usage on macOS in worktree.mk, incorrect wildcard patterns in settings.json that prevent permission matching, potential ES module parsing failures for .js workflow files in downstream projects, and a naive regex in the validation script that causes false positives when parsing code spans.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread scripts/makefile/worktree.mk Outdated
Comment thread .claude/settings.json
Comment thread scripts/ci/validate-harness.mjs
Comment thread scripts/ci/validate-harness.mjs
@andypost

Copy link
Copy Markdown
Contributor Author

Thanks @gemini-code-assist — addressed in 687d4c7. Summary of dispositions:

1. worktree.mk sed -i portability — ✅ fixed. The recipe now branches on uname (sed -i '' on BSD/macOS, sed -i on GNU/Linux). Good catch — macOS is a supported dev platform.

2. .claude/settings.json permission format — ⚠️ declined (respectfully). Bash(make:*) is the correct Claude Code permission syntax: :* is the prefix wildcard, so it matches make all, make tests, etc. — not a literal colon. The suggested Bash(command="make *") isn't a valid Claude Code permission form and would match nothing. Left as-is.

3. Workflows .js parsed as CommonJS downstream — ✅ fixed, different mechanism. Rather than rename to .mjs (which would disrupt harness discovery + doc links + the existing run() convention), I added .claude/workflows/package.json{"type":"module"}, which forces ESM for those files in any downstream project regardless of the root package.json. Verified node --check passes.

4. makeTokensInCodeSpans naive regex — ✅ fixed. Adopted the hardened version (strip escaped backticks; match fenced ``` blocks and inline spans separately). It also correctly surfaced a real over-strict case in T0.5b (make tests is referenced in ci-pipeline.md as the local equivalent, but CI runs its decomposed sub-jobs) — fixed by exempting the local-only tests/sniffers aggregators.

Also recovered a previously-unpushed change tightening T0.5c: review-app variables must now be backed by real runtime config (.gitlab-ci.yml, .env.default, Makefile, scripts/makefile, docker) with # comments stripped, so a comment-only mention no longer counts.

Static gate: 80 checks pass locally and the negative test still fails as expected.

@gemini-code-assist

Copy link
Copy Markdown

Thanks for the detailed breakdown, @andypost. The adjustments to the worktree.mk portability, the ESM module handling via package.json, and the hardened regex for code spans all look solid and address the points raised effectively. The decision to keep the make:* permission in .claude/settings.json is pragmatic given the project's heavy reliance on the Makefile as the primary interface. Everything seems well-aligned with the goal of making the template agent-manageable while maintaining the existing contract.

@andypost

Copy link
Copy Markdown
Contributor Author

/gemini review

@gemini-code-assist gemini-code-assist Bot 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.

Code Review

This pull request introduces a comprehensive Claude Code agent harness containing skills, subagents, and workflows to automate maintenance tasks like Drupal upgrades, dependency bumps, and backlog grooming. It also adds extensive narrative documentation under the docs/ directory and introduces static validation tools, including a Node-based harness validator and new Makefile targets. The code review feedback is highly constructive and should be fully addressed, as it identifies critical issues such as potential regex false positives in the Makefile target parser, missing .env initialization in the worktree helper, unhandled null/undefined values in the NewRelic bump workflow, a potential fatal PHP error in the Rector configuration, and cross-platform line-ending issues in the frontmatter parser.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread scripts/ci/validate-harness.mjs Outdated
Comment thread scripts/makefile/worktree.mk
Comment thread .claude/workflows/newrelic-bump.workflow.js Outdated
Comment thread docs/upgrading.md Outdated
Comment thread scripts/ci/validate-harness.mjs Outdated
Documentation, an inheritable Claude Code harness, and a Tier 0 validation
gate for this template. No runtime/Drupal behavior changes.

- docs/: review-apps, ci-pipeline, architecture, local-development, upgrading
  (D10->11->12), observability, parallel-environments, delivery-and-ops,
  testing, backlog, and an index.
- .claude/: settings allowlist, 5 skills, 3 subagents, 2 workflows.
- scripts/makefile/worktree.mk: `make worktree-name` for parallel per-branch
  local stacks.
- scripts/ci/validate-harness.mjs + scripts/makefile/validate.mk: Tier 0 static
  gate (links, settings.json, workflow modules, frontmatter, doc/CI drift,
  EOF newlines, self-consistency).
- .github/workflows/validation.yml: runs the harness gate + Makefile sniffers
  (clang/compval/phpcs/newlineeof) on pull requests.
- .gitlab-ci.yml: sniffers:harness job.
- CONTRIBUTING.md; expand CLAUDE.md and README with doc/harness links.

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

Copy link
Copy Markdown
Contributor Author

Second-round review addressed in 2493f07 — all 5 medium findings fixed:

  1. realMakeTargets matched := assignments — regex now uses a negative lookahead :(?!=), so NAME := value no longer leaks variable names into the target set (verified COMPOSE_NET_NAME is no longer treated as a target; real targets still detected).
  2. worktree-name could fail if .env is missing — added [ -f .env ] || cp .env.default .env before the sed (defensive even though the root Makefile already creates .env at parse time).
  3. newrelic-bump could bump to undefined — added an early guard: if the latest version can't be determined, return bumped:false instead of proceeding.
  4. rector.php D11 set could fatal — the upgrading.md snippet now wraps the D11 set in class_exists(\DrupalRector\Set\Drupal11SetList::class).
  5. Frontmatter parser broke on CRLF — the boundary regex and line split now accept \r?\n.

Static gate still 80 checks pass.

@andypost

Copy link
Copy Markdown
Contributor Author

/gemini review

@gemini-code-assist gemini-code-assist Bot 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.

Code Review

This pull request introduces a comprehensive agent harness under .claude/ along with extensive documentation in docs/ to make the repository manageable with Claude Code. It also adds Makefile helpers for static validation and parallel local environments using git worktrees. The review feedback highlights several critical improvements: ensuring PHP commands like rector are executed inside containers rather than on the host, handling detached HEAD states in worktree.mk to prevent container collisions, using optional chaining to prevent crashes when the budget object is undefined, and changing a documentation placeholder to make NOPE to avoid triggering false positives in the static validator.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +91 to +92
Prefer \`vendor/bin/rector process web/modules/custom web/themes/custom\` for the auto-fixable ones,
then hand-edit the rest. Do not touch contrib/core. Keep edits minimal.`,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

According to the golden rule in CLAUDE.md, all PHP and Drupal commands must run inside the container because the host environment lacks the required PHP runtime and dependencies. Suggesting the agent to run raw vendor/bin/rector on the host will fail.

Updating the instruction to use docker compose exec php vendor/bin/rector ensures the command runs successfully in the correct environment.

Comment on lines +9 to +11
@branch=$$(git rev-parse --abbrev-ref HEAD 2>/dev/null || basename $(CURDIR)); \
name=$$(echo "$$branch" | tr -cd '[:alnum:]' | tr '[:upper:]' '[:lower:]'); \
[ -n "$$name" ] || name=$$(basename $(CURDIR) | tr -cd '[:alnum:]' | tr '[:upper:]' '[:lower:]'); \

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

In a detached HEAD state (common in CI pipelines or when checking out specific commits), git rev-parse --abbrev-ref HEAD returns the literal string HEAD. This causes COMPOSE_PROJECT_NAME to be set to head for all such worktrees, leading to container and network collisions between parallel stacks.

Updating the logic to check for HEAD and falling back to the directory name ensures unique project names even in detached HEAD states.

	@branch=$$(git rev-parse --abbrev-ref HEAD 2>/dev/null); \\
	if [ "$$branch" = "HEAD" ] || [ -z "$$branch" ]; then branch=$$(basename $(CURDIR)); fi; \\
	name=$$(echo "$$branch" | tr -cd '[:alnum:]' | tr '[:upper:]' '[:lower:]'); \\
	[ -n "$$name" ] || name=$$(basename $(CURDIR) | tr -cd '[:alnum:]' | tr '[:upper:]' '[:lower:]'); \\

Comment thread docs/testing.md
| T0.6 | `AGENTS.md` and new files under `docs/`, `.claude/`, `scripts/` end with a newline |
| T0.7 | `.claude/README.md` mentions every skill/agent/workflow on disk |

**Negative test** (prove the gate bites): add a broken link or a fake `` `make nope` `` to a scratch

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The static validation script scripts/ci/validate-harness.mjs checks all make commands in code spans against actual Makefile targets. Because make nope is written in lowercase, the regex \bmake\s+([a-z][a-z0-9_-]*) extracts nope as a target and fails the validation since nope is not a real target.

Changing it to uppercase make NOPE avoids triggering this validation check while keeping the placeholder clear.

// --- Validate and iterate to ready ---
phase('Validate')
let verdict = null
const MAX_ITERS = budget.total ? 6 : 3

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

If the workflow is invoked without a budget object (or if budget is undefined), destructuring it in the run function signature is safe, but accessing budget.total directly will throw a TypeError: Cannot read properties of undefined (reading 'total') and crash the workflow.

Using optional chaining (budget?.total) prevents this potential crash.

Suggested change
const MAX_ITERS = budget.total ? 6 : 3
const MAX_ITERS = budget?.total ? 6 : 3

Then report:
- **Blockers**: deprecations `upgrade_status` flags in custom code, grouped by file, each with the
deprecated API and the D11/D12 replacement.
- **Auto-fixable**: what rector can rewrite (note: `vendor/bin/rector process` would apply them).

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The instruction suggests running vendor/bin/rector process on the host, which violates the golden rule of running everything in containers and will fail due to missing dependencies on the host.

Updating this to docker compose exec php vendor/bin/rector process aligns with the container-first architecture.

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