feat: add parallel-delegate-shared-files skill from iWP Cache incident
This commit is contained in:
@@ -51,6 +51,9 @@ than assuming the delegate can fetch it itself.
|
||||
configuration strength, including reverse-proxy-layer gotchas.
|
||||
- `code-sanitization` -- framework-agnostic injection-prevention baseline
|
||||
(SQLi, XSS, command injection, path traversal, uploads, deserialization).
|
||||
- `parallel-delegate-shared-files` -- never have 2+ parallel delegates edit
|
||||
the same bootstrap/wiring file; use self-registration instead. Real
|
||||
incident from the iWP Cache build (lost updates, twice).
|
||||
|
||||
## Provenance
|
||||
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
---
|
||||
name: parallel-delegate-shared-files
|
||||
description: Use when briefing 2+ delegates to work in parallel on the same plugin/theme/module. Never have them edit one shared bootstrap file -- design for self-registration instead.
|
||||
license: MIT
|
||||
source: original, from a real incident on the iWP Cache build (CloudHost/iWP-Cache)
|
||||
---
|
||||
|
||||
# Parallel Delegates and Shared Files
|
||||
|
||||
**Running delegates in parallel is fine. Having them edit the same file in
|
||||
parallel is not.** If two delegates (agy, kimi, vibe, a Claude subagent,
|
||||
codex -- any combination) each read-modify-write the same file at
|
||||
overlapping times, one edit silently wins and the other is lost. No error,
|
||||
no conflict marker, no delegate-side signal that anything went wrong --
|
||||
both will self-report success, because from each one's point of view its
|
||||
own write did land.
|
||||
|
||||
## The incident
|
||||
|
||||
Building `iWP Cache`, the plan called for a shared `iwp-cache.php` bootstrap
|
||||
that each module (minify, db-cleanup, cdn, lazyload, preload, invalidation)
|
||||
would wire into via its own `require_once` + `new IWP_Cache_X()` line inside
|
||||
the shared constructor, added by whichever delegate built that module.
|
||||
Two different delegates' edits to that same block landed close enough
|
||||
together that one was clobbered -- confirmed by session Claude's own
|
||||
re-read of the file after both delegates reported success, not by either
|
||||
delegate noticing anything wrong. It then happened a second time to a
|
||||
different module. Both times the result was dead code: a fully-built,
|
||||
individually-correct module class that was simply never instantiated,
|
||||
because the line wiring it in had been overwritten.
|
||||
|
||||
## The fix: self-registering modules, not a shared wiring file
|
||||
|
||||
Each module file registers itself at the bottom of its own file:
|
||||
|
||||
```php
|
||||
add_action('plugins_loaded', function () {
|
||||
new IWP_Cache_ModuleName();
|
||||
});
|
||||
```
|
||||
|
||||
The bootstrap file never lists individual modules. It either requires a
|
||||
fixed set of foundation files that never grow (config/engine/core -- built
|
||||
once, by one person, not touched again) plus an auto-glob for everything
|
||||
else:
|
||||
|
||||
```php
|
||||
foreach (glob(IWP_CACHE_PATH . 'includes/class-iwp-cache-*.php') as $file) {
|
||||
if (!in_array(basename($file), $foundation_files, true)) {
|
||||
require_once $file;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
With this shape, a new delegate adding a new module touches exactly one
|
||||
file -- their own -- and nothing else. There is no shared line for two
|
||||
delegates to race on, so there is nothing to lose.
|
||||
|
||||
## When briefing delegates under this pattern
|
||||
|
||||
Tell each delegate explicitly:
|
||||
- "Your module is self-contained in `includes/class-iwp-cache-yourmodule.php`.
|
||||
Do not edit the main plugin bootstrap file. Register your class with
|
||||
`add_action('plugins_loaded', ...)` at the bottom of your own file."
|
||||
- If a module genuinely needs to be wired into a *different* shared
|
||||
resource (an admin menu, a settings schema) that can't be glob-discovered,
|
||||
that wiring is session Claude's job to add after all delegates finish --
|
||||
not something to hand to whichever delegate gets there first.
|
||||
|
||||
## Verify it actually worked
|
||||
|
||||
Self-registration removes the race, but still verify after the fact --
|
||||
per [[verification-before-completion]]. After all delegates report done:
|
||||
|
||||
```bash
|
||||
grep -rn "new IWP_Cache_" includes/ *.php
|
||||
```
|
||||
|
||||
Confirm every module class is instantiated exactly once (watch for the
|
||||
inverse bug: a leftover direct `new X()` call in the old shared
|
||||
constructor that an auto-merge or a stale delegate edit restored,
|
||||
double-instantiating a class that also self-registers -- this happened
|
||||
once too, caught by re-reading the bootstrap file before declaring the
|
||||
refactor done, not by trusting the diff summary).
|
||||
|
||||
## General rule beyond this one plugin
|
||||
|
||||
Any time 2+ delegates are briefed to work in parallel on the same
|
||||
codebase, ask first: do any of their file sets overlap? If yes, either
|
||||
serialize those specific delegates (not the whole batch -- just the ones
|
||||
touching the shared file), or restructure the work so the shared surface
|
||||
is auto-discovered rather than hand-edited by each contributor.
|
||||
Reference in New Issue
Block a user