@bradygaster/squad-sdk 0.8.25 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapter/client.d.ts +17 -0
- package/dist/adapter/client.d.ts.map +1 -1
- package/dist/adapter/client.js +101 -1
- package/dist/adapter/client.js.map +1 -1
- package/dist/agents/history-shadow.d.ts.map +1 -1
- package/dist/agents/history-shadow.js +99 -32
- package/dist/agents/history-shadow.js.map +1 -1
- package/dist/agents/index.d.ts +1 -0
- package/dist/agents/index.d.ts.map +1 -1
- package/dist/agents/index.js +2 -0
- package/dist/agents/index.js.map +1 -1
- package/dist/agents/model-selector.d.ts +2 -0
- package/dist/agents/model-selector.d.ts.map +1 -1
- package/dist/agents/model-selector.js +41 -35
- package/dist/agents/model-selector.js.map +1 -1
- package/dist/agents/personal.d.ts +35 -0
- package/dist/agents/personal.d.ts.map +1 -0
- package/dist/agents/personal.js +67 -0
- package/dist/agents/personal.js.map +1 -0
- package/dist/builders/index.d.ts +3 -2
- package/dist/builders/index.d.ts.map +1 -1
- package/dist/builders/index.js +28 -0
- package/dist/builders/index.js.map +1 -1
- package/dist/builders/types.d.ts +13 -0
- package/dist/builders/types.d.ts.map +1 -1
- package/dist/config/init.d.ts +8 -0
- package/dist/config/init.d.ts.map +1 -1
- package/dist/config/init.js +131 -20
- package/dist/config/init.js.map +1 -1
- package/dist/config/models.d.ts +112 -0
- package/dist/config/models.d.ts.map +1 -1
- package/dist/config/models.js +329 -18
- package/dist/config/models.js.map +1 -1
- package/dist/coordinator/index.js +2 -2
- package/dist/coordinator/index.js.map +1 -1
- package/dist/index.d.ts +8 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -2
- package/dist/index.js.map +1 -1
- package/dist/platform/azure-devops.d.ts +42 -0
- package/dist/platform/azure-devops.d.ts.map +1 -1
- package/dist/platform/azure-devops.js +75 -0
- package/dist/platform/azure-devops.js.map +1 -1
- package/dist/platform/comms-file-log.d.ts.map +1 -1
- package/dist/platform/comms-file-log.js +2 -1
- package/dist/platform/comms-file-log.js.map +1 -1
- package/dist/platform/index.d.ts +2 -1
- package/dist/platform/index.d.ts.map +1 -1
- package/dist/platform/index.js +1 -0
- package/dist/platform/index.js.map +1 -1
- package/dist/ralph/capabilities.d.ts +67 -0
- package/dist/ralph/capabilities.d.ts.map +1 -0
- package/dist/ralph/capabilities.js +111 -0
- package/dist/ralph/capabilities.js.map +1 -0
- package/dist/ralph/index.d.ts +2 -0
- package/dist/ralph/index.d.ts.map +1 -1
- package/dist/ralph/index.js +6 -5
- package/dist/ralph/index.js.map +1 -1
- package/dist/ralph/rate-limiting.d.ts +99 -0
- package/dist/ralph/rate-limiting.d.ts.map +1 -0
- package/dist/ralph/rate-limiting.js +170 -0
- package/dist/ralph/rate-limiting.js.map +1 -0
- package/dist/resolution.d.ts +24 -2
- package/dist/resolution.d.ts.map +1 -1
- package/dist/resolution.js +106 -6
- package/dist/resolution.js.map +1 -1
- package/dist/roles/catalog-categories.d.ts +146 -0
- package/dist/roles/catalog-categories.d.ts.map +1 -0
- package/dist/roles/catalog-categories.js +374 -0
- package/dist/roles/catalog-categories.js.map +1 -0
- package/dist/roles/catalog-engineering.d.ts +212 -0
- package/dist/roles/catalog-engineering.d.ts.map +1 -0
- package/dist/roles/catalog-engineering.js +549 -0
- package/dist/roles/catalog-engineering.js.map +1 -0
- package/dist/roles/catalog.d.ts +24 -0
- package/dist/roles/catalog.d.ts.map +1 -0
- package/dist/roles/catalog.js +28 -0
- package/dist/roles/catalog.js.map +1 -0
- package/dist/roles/index.d.ts +69 -0
- package/dist/roles/index.d.ts.map +1 -0
- package/dist/roles/index.js +197 -0
- package/dist/roles/index.js.map +1 -0
- package/dist/roles/types.d.ts +87 -0
- package/dist/roles/types.d.ts.map +1 -0
- package/dist/roles/types.js +14 -0
- package/dist/roles/types.js.map +1 -0
- package/dist/runtime/benchmarks.js +5 -5
- package/dist/runtime/benchmarks.js.map +1 -1
- package/dist/runtime/constants.d.ts +2 -2
- package/dist/runtime/constants.d.ts.map +1 -1
- package/dist/runtime/constants.js +5 -3
- package/dist/runtime/constants.js.map +1 -1
- package/dist/runtime/cross-squad.d.ts +118 -0
- package/dist/runtime/cross-squad.d.ts.map +1 -0
- package/dist/runtime/cross-squad.js +234 -0
- package/dist/runtime/cross-squad.js.map +1 -0
- package/dist/runtime/otel-init.d.ts +24 -17
- package/dist/runtime/otel-init.d.ts.map +1 -1
- package/dist/runtime/otel-init.js +29 -20
- package/dist/runtime/otel-init.js.map +1 -1
- package/dist/runtime/otel-metrics.d.ts +5 -0
- package/dist/runtime/otel-metrics.d.ts.map +1 -1
- package/dist/runtime/otel-metrics.js +54 -0
- package/dist/runtime/otel-metrics.js.map +1 -1
- package/dist/runtime/rework.d.ts +71 -0
- package/dist/runtime/rework.d.ts.map +1 -0
- package/dist/runtime/rework.js +107 -0
- package/dist/runtime/rework.js.map +1 -0
- package/dist/runtime/scheduler.d.ts +128 -0
- package/dist/runtime/scheduler.d.ts.map +1 -0
- package/dist/runtime/scheduler.js +427 -0
- package/dist/runtime/scheduler.js.map +1 -0
- package/dist/runtime/squad-observer.d.ts.map +1 -1
- package/dist/runtime/squad-observer.js +4 -0
- package/dist/runtime/squad-observer.js.map +1 -1
- package/dist/runtime/streaming.d.ts +2 -0
- package/dist/runtime/streaming.d.ts.map +1 -1
- package/dist/runtime/streaming.js +6 -0
- package/dist/runtime/streaming.js.map +1 -1
- package/dist/runtime/telemetry.d.ts +2 -0
- package/dist/runtime/telemetry.d.ts.map +1 -1
- package/dist/runtime/telemetry.js +6 -0
- package/dist/runtime/telemetry.js.map +1 -1
- package/dist/sharing/consult.d.ts +2 -2
- package/dist/sharing/consult.js +6 -6
- package/dist/sharing/consult.js.map +1 -1
- package/dist/sharing/export.d.ts.map +1 -1
- package/dist/sharing/export.js +17 -4
- package/dist/sharing/export.js.map +1 -1
- package/dist/skills/handler-types.d.ts +271 -0
- package/dist/skills/handler-types.d.ts.map +1 -0
- package/dist/skills/handler-types.js +31 -0
- package/dist/skills/handler-types.js.map +1 -0
- package/dist/skills/index.d.ts +3 -0
- package/dist/skills/index.d.ts.map +1 -1
- package/dist/skills/index.js +3 -0
- package/dist/skills/index.js.map +1 -1
- package/dist/skills/skill-script-loader.d.ts +65 -0
- package/dist/skills/skill-script-loader.d.ts.map +1 -0
- package/dist/skills/skill-script-loader.js +227 -0
- package/dist/skills/skill-script-loader.js.map +1 -0
- package/dist/skills/skill-source.d.ts.map +1 -1
- package/dist/skills/skill-source.js +5 -1
- package/dist/skills/skill-source.js.map +1 -1
- package/dist/tools/index.d.ts +10 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +49 -8
- package/dist/tools/index.js.map +1 -1
- package/dist/upstream/resolver.d.ts.map +1 -1
- package/dist/upstream/resolver.js +14 -5
- package/dist/upstream/resolver.js.map +1 -1
- package/package.json +34 -3
- package/templates/casting/Futurama.json +10 -0
- package/templates/casting-policy.json +4 -2
- package/templates/casting-reference.md +104 -0
- package/templates/cooperative-rate-limiting.md +229 -0
- package/templates/issue-lifecycle.md +412 -0
- package/templates/keda-scaler.md +164 -0
- package/templates/machine-capabilities.md +75 -0
- package/templates/mcp-config.md +0 -8
- package/templates/orchestration-log.md +27 -27
- package/templates/package.json +3 -0
- package/templates/ralph-circuit-breaker.md +313 -0
- package/templates/ralph-triage.js +543 -0
- package/templates/routing.md +5 -20
- package/templates/schedule.json +19 -0
- package/templates/scribe-charter.md +1 -1
- package/templates/skills/agent-collaboration/SKILL.md +42 -0
- package/templates/skills/agent-conduct/SKILL.md +24 -0
- package/templates/skills/architectural-proposals/SKILL.md +151 -0
- package/templates/skills/ci-validation-gates/SKILL.md +84 -0
- package/templates/skills/cli-wiring/SKILL.md +47 -0
- package/templates/skills/client-compatibility/SKILL.md +89 -0
- package/templates/skills/cross-squad/SKILL.md +114 -0
- package/templates/skills/distributed-mesh/SKILL.md +287 -0
- package/templates/skills/distributed-mesh/mesh.json.example +30 -0
- package/templates/skills/distributed-mesh/sync-mesh.ps1 +111 -0
- package/templates/skills/distributed-mesh/sync-mesh.sh +104 -0
- package/templates/skills/docs-standards/SKILL.md +71 -0
- package/templates/skills/economy-mode/SKILL.md +114 -0
- package/templates/skills/external-comms/SKILL.md +329 -0
- package/templates/skills/gh-auth-isolation/SKILL.md +183 -0
- package/templates/skills/git-workflow/SKILL.md +204 -0
- package/templates/skills/github-multi-account/SKILL.md +95 -0
- package/templates/skills/history-hygiene/SKILL.md +36 -0
- package/templates/skills/humanizer/SKILL.md +105 -0
- package/templates/skills/init-mode/SKILL.md +102 -0
- package/templates/skills/model-selection/SKILL.md +117 -0
- package/templates/skills/nap/SKILL.md +24 -0
- package/templates/skills/personal-squad/SKILL.md +57 -0
- package/templates/skills/release-process/SKILL.md +423 -0
- package/templates/skills/reskill/SKILL.md +92 -0
- package/templates/skills/reviewer-protocol/SKILL.md +79 -0
- package/templates/skills/secret-handling/SKILL.md +200 -0
- package/templates/skills/session-recovery/SKILL.md +155 -0
- package/templates/skills/squad-conventions/SKILL.md +69 -0
- package/templates/skills/test-discipline/SKILL.md +37 -0
- package/templates/skills/windows-compatibility/SKILL.md +74 -0
- package/templates/squad.agent.md +1287 -1146
- package/templates/workflows/squad-docs.yml +8 -4
- package/templates/workflows/squad-heartbeat.yml +55 -200
- package/templates/workflows/squad-insider-release.yml +1 -1
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Personal Squad — Skill Document
|
|
2
|
+
|
|
3
|
+
## What is a Personal Squad?
|
|
4
|
+
|
|
5
|
+
A personal squad is a user-level collection of AI agents that travel with you across projects. Unlike project agents (defined in a project's `.squad/` directory), personal agents live in your global config directory and are automatically discovered when you start a squad session.
|
|
6
|
+
|
|
7
|
+
## Directory Structure
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
~/.config/squad/personal-squad/ # Linux/macOS
|
|
11
|
+
%APPDATA%/squad/personal-squad/ # Windows
|
|
12
|
+
├── agents/
|
|
13
|
+
│ ├── {agent-name}/
|
|
14
|
+
│ │ ├── charter.md
|
|
15
|
+
│ │ └── history.md
|
|
16
|
+
│ └── ...
|
|
17
|
+
└── config.json # Optional: personal squad config
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## How It Works
|
|
21
|
+
|
|
22
|
+
1. **Ambient Discovery:** When Squad starts a session, it checks for a personal squad directory
|
|
23
|
+
2. **Merge:** Personal agents are merged into the session cast alongside project agents
|
|
24
|
+
3. **Ghost Protocol:** Personal agents can read project state but not write to it
|
|
25
|
+
4. **Kill Switch:** Set `SQUAD_NO_PERSONAL=1` to disable ambient discovery
|
|
26
|
+
|
|
27
|
+
## Commands
|
|
28
|
+
|
|
29
|
+
- `squad personal init` — Bootstrap a personal squad directory
|
|
30
|
+
- `squad personal list` — List your personal agents
|
|
31
|
+
- `squad personal add {name} --role {role}` — Add a personal agent
|
|
32
|
+
- `squad personal remove {name}` — Remove a personal agent
|
|
33
|
+
- `squad cast` — Show the current session cast (project + personal)
|
|
34
|
+
|
|
35
|
+
## Ghost Protocol
|
|
36
|
+
|
|
37
|
+
See `templates/ghost-protocol.md` for the full rules. Key points:
|
|
38
|
+
- Personal agents advise; project agents execute
|
|
39
|
+
- No writes to project `.squad/` state
|
|
40
|
+
- Transparent origin tagging in logs
|
|
41
|
+
- Project agents take precedence on conflicts
|
|
42
|
+
|
|
43
|
+
## Configuration
|
|
44
|
+
|
|
45
|
+
Optional `config.json` in the personal squad directory:
|
|
46
|
+
```json
|
|
47
|
+
{
|
|
48
|
+
"defaultModel": "auto",
|
|
49
|
+
"ghostProtocol": true,
|
|
50
|
+
"agents": {}
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Environment Variables
|
|
55
|
+
|
|
56
|
+
- `SQUAD_NO_PERSONAL` — Set to any value to disable personal squad discovery
|
|
57
|
+
- `SQUAD_PERSONAL_DIR` — Override the default personal squad directory path
|
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: "release-process"
|
|
3
|
+
description: "Step-by-step release checklist for Squad — prevents v0.8.22-style disasters"
|
|
4
|
+
domain: "release-management"
|
|
5
|
+
confidence: "high"
|
|
6
|
+
source: "team-decision"
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Context
|
|
10
|
+
|
|
11
|
+
This is the **definitive release runbook** for Squad. Born from the v0.8.22 release disaster (4-part semver mangled by npm, draft release never triggered publish, wrong NPM_TOKEN type, 6+ hours of broken `latest` dist-tag).
|
|
12
|
+
|
|
13
|
+
**Rule:** No agent releases Squad without following this checklist. No exceptions. No improvisation.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Pre-Release Validation
|
|
18
|
+
|
|
19
|
+
Before starting ANY release work, validate the following:
|
|
20
|
+
|
|
21
|
+
### 1. Version Number Validation
|
|
22
|
+
|
|
23
|
+
**Rule:** Only 3-part semver (major.minor.patch) or prerelease (major.minor.patch-tag.N) are valid. 4-part versions (0.8.21.4) are NOT valid semver and npm will mangle them.
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
# Check version is valid semver
|
|
27
|
+
node -p "require('semver').valid('0.8.22')"
|
|
28
|
+
# Output: '0.8.22' = valid
|
|
29
|
+
# Output: null = INVALID, STOP
|
|
30
|
+
|
|
31
|
+
# For prerelease versions
|
|
32
|
+
node -p "require('semver').valid('0.8.23-preview.1')"
|
|
33
|
+
# Output: '0.8.23-preview.1' = valid
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
**If `semver.valid()` returns `null`:** STOP. Fix the version. Do NOT proceed.
|
|
37
|
+
|
|
38
|
+
### 2. NPM_TOKEN Verification
|
|
39
|
+
|
|
40
|
+
**Rule:** NPM_TOKEN must be an **Automation token** (no 2FA required). User tokens with 2FA will fail in CI with EOTP errors.
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
# Check token type (requires npm CLI authenticated)
|
|
44
|
+
npm token list
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Look for:
|
|
48
|
+
- ✅ `read-write` tokens with NO 2FA requirement = Automation token (correct)
|
|
49
|
+
- ❌ Tokens requiring OTP = User token (WRONG, will fail in CI)
|
|
50
|
+
|
|
51
|
+
**How to create an Automation token:**
|
|
52
|
+
1. Go to npmjs.com → Settings → Access Tokens
|
|
53
|
+
2. Click "Generate New Token"
|
|
54
|
+
3. Select **"Automation"** (NOT "Publish")
|
|
55
|
+
4. Copy token and save as GitHub secret: `NPM_TOKEN`
|
|
56
|
+
|
|
57
|
+
**If using a User token:** STOP. Create an Automation token first.
|
|
58
|
+
|
|
59
|
+
### 3. Branch and Tag State
|
|
60
|
+
|
|
61
|
+
**Rule:** Release from `main` branch. Ensure clean state, no uncommitted changes, latest from origin.
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
# Ensure on main and clean
|
|
65
|
+
git checkout main
|
|
66
|
+
git pull origin main
|
|
67
|
+
git status # Should show: "nothing to commit, working tree clean"
|
|
68
|
+
|
|
69
|
+
# Check tag doesn't already exist
|
|
70
|
+
git tag -l "v0.8.22"
|
|
71
|
+
# Output should be EMPTY. If tag exists, release already done or collision.
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
**If tag exists:** STOP. Either release was already done, or there's a collision. Investigate before proceeding.
|
|
75
|
+
|
|
76
|
+
### 4. Disable bump-build.mjs
|
|
77
|
+
|
|
78
|
+
**Rule:** `bump-build.mjs` is for dev builds ONLY. It must NOT run during release builds (it increments build numbers, creating 4-part versions).
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
# Set env var to skip bump-build.mjs
|
|
82
|
+
export SKIP_BUILD_BUMP=1
|
|
83
|
+
|
|
84
|
+
# Verify it's set
|
|
85
|
+
echo $SKIP_BUILD_BUMP
|
|
86
|
+
# Output: 1
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
**For Windows PowerShell:**
|
|
90
|
+
```powershell
|
|
91
|
+
$env:SKIP_BUILD_BUMP = "1"
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
**If not set:** `bump-build.mjs` will run and mutate versions. This causes disasters (see v0.8.22).
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## Release Workflow
|
|
99
|
+
|
|
100
|
+
### Step 1: Version Bump
|
|
101
|
+
|
|
102
|
+
Update version in all 3 package.json files (root + both workspaces) in lockstep.
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
# Set target version (no 'v' prefix)
|
|
106
|
+
VERSION="0.8.22"
|
|
107
|
+
|
|
108
|
+
# Validate it's valid semver BEFORE proceeding
|
|
109
|
+
node -p "require('semver').valid('$VERSION')"
|
|
110
|
+
# Must output the version string, NOT null
|
|
111
|
+
|
|
112
|
+
# Update all 3 package.json files
|
|
113
|
+
npm version $VERSION --workspaces --include-workspace-root --no-git-tag-version
|
|
114
|
+
|
|
115
|
+
# Verify all 3 match
|
|
116
|
+
grep '"version"' package.json packages/squad-sdk/package.json packages/squad-cli/package.json
|
|
117
|
+
# All 3 should show: "version": "0.8.22"
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
**Checkpoint:** All 3 package.json files have identical versions. Run `semver.valid()` one more time to be sure.
|
|
121
|
+
|
|
122
|
+
### Step 2: Commit and Tag
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
# Commit version bump
|
|
126
|
+
git add package.json packages/squad-sdk/package.json packages/squad-cli/package.json
|
|
127
|
+
git commit -m "chore: bump version to $VERSION
|
|
128
|
+
|
|
129
|
+
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>"
|
|
130
|
+
|
|
131
|
+
# Create tag (with 'v' prefix)
|
|
132
|
+
git tag -a "v$VERSION" -m "Release v$VERSION"
|
|
133
|
+
|
|
134
|
+
# Push commit and tag
|
|
135
|
+
git push origin main
|
|
136
|
+
git push origin "v$VERSION"
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
**Checkpoint:** Tag created and pushed. Verify with `git tag -l "v$VERSION"`.
|
|
140
|
+
|
|
141
|
+
### Step 3: Create GitHub Release
|
|
142
|
+
|
|
143
|
+
**CRITICAL:** Release must be **published**, NOT draft. Draft releases don't trigger `publish.yml` workflow.
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
# Create GitHub Release (NOT draft)
|
|
147
|
+
gh release create "v$VERSION" \
|
|
148
|
+
--title "v$VERSION" \
|
|
149
|
+
--notes "Release notes go here" \
|
|
150
|
+
--latest
|
|
151
|
+
|
|
152
|
+
# Verify release is PUBLISHED (not draft)
|
|
153
|
+
gh release view "v$VERSION"
|
|
154
|
+
# Output should NOT contain "(draft)"
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
**If output contains `(draft)`:** STOP. Delete the release and recreate without `--draft` flag.
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
# If you accidentally created a draft, fix it:
|
|
161
|
+
gh release edit "v$VERSION" --draft=false
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
**Checkpoint:** Release is published (NOT draft). The `release: published` event fired and triggered `publish.yml`.
|
|
165
|
+
|
|
166
|
+
### Step 4: Monitor Workflow
|
|
167
|
+
|
|
168
|
+
The `publish.yml` workflow should start automatically within 10 seconds of release creation.
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
# Watch workflow runs
|
|
172
|
+
gh run list --workflow=publish.yml --limit 1
|
|
173
|
+
|
|
174
|
+
# Get detailed status
|
|
175
|
+
gh run view --log
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
**Expected flow:**
|
|
179
|
+
1. `publish-sdk` job runs → publishes `@bradygaster/squad-sdk`
|
|
180
|
+
2. Verify step runs with retry loop (up to 5 attempts, 15s interval) to confirm SDK on npm registry
|
|
181
|
+
3. `publish-cli` job runs → publishes `@bradygaster/squad-cli`
|
|
182
|
+
4. Verify step runs with retry loop to confirm CLI on npm registry
|
|
183
|
+
|
|
184
|
+
**If workflow fails:** Check the logs. Common issues:
|
|
185
|
+
- EOTP error = wrong NPM_TOKEN type (use Automation token)
|
|
186
|
+
- Verify step timeout = npm propagation delay (retry loop should handle this, but propagation can take up to 2 minutes in rare cases)
|
|
187
|
+
- Version mismatch = package.json version doesn't match tag
|
|
188
|
+
|
|
189
|
+
**Checkpoint:** Both jobs succeeded. Workflow shows green checkmarks.
|
|
190
|
+
|
|
191
|
+
### Step 5: Verify npm Publication
|
|
192
|
+
|
|
193
|
+
Manually verify both packages are on npm with correct `latest` dist-tag.
|
|
194
|
+
|
|
195
|
+
```bash
|
|
196
|
+
# Check SDK
|
|
197
|
+
npm view @bradygaster/squad-sdk version
|
|
198
|
+
# Output: 0.8.22
|
|
199
|
+
|
|
200
|
+
npm dist-tag ls @bradygaster/squad-sdk
|
|
201
|
+
# Output should show: latest: 0.8.22
|
|
202
|
+
|
|
203
|
+
# Check CLI
|
|
204
|
+
npm view @bradygaster/squad-cli version
|
|
205
|
+
# Output: 0.8.22
|
|
206
|
+
|
|
207
|
+
npm dist-tag ls @bradygaster/squad-cli
|
|
208
|
+
# Output should show: latest: 0.8.22
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
**If versions don't match:** Something went wrong. Check workflow logs. DO NOT proceed with GitHub Release announcement until npm is correct.
|
|
212
|
+
|
|
213
|
+
**Checkpoint:** Both packages show correct version. `latest` dist-tags point to the new version.
|
|
214
|
+
|
|
215
|
+
### Step 6: Test Installation
|
|
216
|
+
|
|
217
|
+
Verify packages can be installed from npm (real-world smoke test).
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
# Create temp directory
|
|
221
|
+
mkdir /tmp/squad-release-test && cd /tmp/squad-release-test
|
|
222
|
+
|
|
223
|
+
# Test SDK installation
|
|
224
|
+
npm init -y
|
|
225
|
+
npm install @bradygaster/squad-sdk
|
|
226
|
+
node -p "require('@bradygaster/squad-sdk/package.json').version"
|
|
227
|
+
# Output: 0.8.22
|
|
228
|
+
|
|
229
|
+
# Test CLI installation
|
|
230
|
+
npm install -g @bradygaster/squad-cli
|
|
231
|
+
squad --version
|
|
232
|
+
# Output: 0.8.22
|
|
233
|
+
|
|
234
|
+
# Cleanup
|
|
235
|
+
cd -
|
|
236
|
+
rm -rf /tmp/squad-release-test
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
**If installation fails:** npm registry issue or package metadata corruption. DO NOT announce release until this works.
|
|
240
|
+
|
|
241
|
+
**Checkpoint:** Both packages install cleanly. Versions match.
|
|
242
|
+
|
|
243
|
+
### Step 7: Sync dev to Next Preview
|
|
244
|
+
|
|
245
|
+
After main release, sync dev to the next preview version.
|
|
246
|
+
|
|
247
|
+
```bash
|
|
248
|
+
# Checkout dev
|
|
249
|
+
git checkout dev
|
|
250
|
+
git pull origin dev
|
|
251
|
+
|
|
252
|
+
# Bump to next preview version (e.g., 0.8.23-preview.1)
|
|
253
|
+
NEXT_VERSION="0.8.23-preview.1"
|
|
254
|
+
|
|
255
|
+
# Validate semver
|
|
256
|
+
node -p "require('semver').valid('$NEXT_VERSION')"
|
|
257
|
+
# Must output the version string, NOT null
|
|
258
|
+
|
|
259
|
+
# Update all 3 package.json files
|
|
260
|
+
npm version $NEXT_VERSION --workspaces --include-workspace-root --no-git-tag-version
|
|
261
|
+
|
|
262
|
+
# Commit
|
|
263
|
+
git add package.json packages/squad-sdk/package.json packages/squad-cli/package.json
|
|
264
|
+
git commit -m "chore: bump dev to $NEXT_VERSION
|
|
265
|
+
|
|
266
|
+
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>"
|
|
267
|
+
|
|
268
|
+
# Push
|
|
269
|
+
git push origin dev
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
**Checkpoint:** dev branch now shows next preview version. Future dev builds will publish to `@preview` dist-tag.
|
|
273
|
+
|
|
274
|
+
---
|
|
275
|
+
|
|
276
|
+
## Manual Publish (Fallback)
|
|
277
|
+
|
|
278
|
+
If `publish.yml` workflow fails or needs to be bypassed, use `workflow_dispatch` to manually trigger publish.
|
|
279
|
+
|
|
280
|
+
```bash
|
|
281
|
+
# Trigger manual publish
|
|
282
|
+
gh workflow run publish.yml -f version="0.8.22"
|
|
283
|
+
|
|
284
|
+
# Monitor the run
|
|
285
|
+
gh run watch
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
**Rule:** Only use this if automated publish failed. Always investigate why automation failed and fix it for next release.
|
|
289
|
+
|
|
290
|
+
---
|
|
291
|
+
|
|
292
|
+
## Rollback Procedure
|
|
293
|
+
|
|
294
|
+
If a release is broken and needs to be rolled back:
|
|
295
|
+
|
|
296
|
+
### 1. Unpublish from npm (Nuclear Option)
|
|
297
|
+
|
|
298
|
+
**WARNING:** npm unpublish is time-limited (24 hours) and leaves the version slot burned. Only use if version is critically broken.
|
|
299
|
+
|
|
300
|
+
```bash
|
|
301
|
+
# Unpublish (requires npm owner privileges)
|
|
302
|
+
npm unpublish @bradygaster/squad-sdk@0.8.22
|
|
303
|
+
npm unpublish @bradygaster/squad-cli@0.8.22
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
### 2. Deprecate on npm (Preferred)
|
|
307
|
+
|
|
308
|
+
**Preferred approach:** Mark version as deprecated, publish a hotfix.
|
|
309
|
+
|
|
310
|
+
```bash
|
|
311
|
+
# Deprecate broken version
|
|
312
|
+
npm deprecate @bradygaster/squad-sdk@0.8.22 "Broken release, use 0.8.22.1 instead"
|
|
313
|
+
npm deprecate @bradygaster/squad-cli@0.8.22 "Broken release, use 0.8.22.1 instead"
|
|
314
|
+
|
|
315
|
+
# Publish hotfix version
|
|
316
|
+
# (Follow this runbook with version 0.8.22.1)
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
### 3. Delete GitHub Release and Tag
|
|
320
|
+
|
|
321
|
+
```bash
|
|
322
|
+
# Delete GitHub Release
|
|
323
|
+
gh release delete "v0.8.22" --yes
|
|
324
|
+
|
|
325
|
+
# Delete tag locally and remotely
|
|
326
|
+
git tag -d "v0.8.22"
|
|
327
|
+
git push origin --delete "v0.8.22"
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
### 4. Revert Commit on main
|
|
331
|
+
|
|
332
|
+
```bash
|
|
333
|
+
# Revert version bump commit
|
|
334
|
+
git checkout main
|
|
335
|
+
git revert HEAD
|
|
336
|
+
git push origin main
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
**Checkpoint:** Tag and release deleted. main branch reverted. npm packages deprecated or unpublished.
|
|
340
|
+
|
|
341
|
+
---
|
|
342
|
+
|
|
343
|
+
## Common Failure Modes
|
|
344
|
+
|
|
345
|
+
### EOTP Error (npm OTP Required)
|
|
346
|
+
|
|
347
|
+
**Symptom:** Workflow fails with `EOTP` error.
|
|
348
|
+
**Root cause:** NPM_TOKEN is a User token with 2FA enabled. CI can't provide OTP.
|
|
349
|
+
**Fix:** Replace NPM_TOKEN with an Automation token (no 2FA). See "NPM_TOKEN Verification" above.
|
|
350
|
+
|
|
351
|
+
### Verify Step 404 (npm Propagation Delay)
|
|
352
|
+
|
|
353
|
+
**Symptom:** Verify step fails with 404 even though publish succeeded.
|
|
354
|
+
**Root cause:** npm registry propagation delay (5-30 seconds).
|
|
355
|
+
**Fix:** Verify step now has retry loop (5 attempts, 15s interval). Should auto-resolve. If not, wait 2 minutes and re-run workflow.
|
|
356
|
+
|
|
357
|
+
### Version Mismatch (package.json ≠ tag)
|
|
358
|
+
|
|
359
|
+
**Symptom:** Verify step fails with "Package version (X) does not match target version (Y)".
|
|
360
|
+
**Root cause:** package.json version doesn't match the tag version.
|
|
361
|
+
**Fix:** Ensure all 3 package.json files were updated in Step 1. Re-run `npm version` if needed.
|
|
362
|
+
|
|
363
|
+
### 4-Part Version Mangled by npm
|
|
364
|
+
|
|
365
|
+
**Symptom:** Published version on npm doesn't match package.json (e.g., 0.8.21.4 became 0.8.2-1.4).
|
|
366
|
+
**Root cause:** 4-part versions are NOT valid semver. npm's parser misinterprets them.
|
|
367
|
+
**Fix:** NEVER use 4-part versions. Only 3-part (0.8.22) or prerelease (0.8.23-preview.1). Run `semver.valid()` before ANY commit.
|
|
368
|
+
|
|
369
|
+
### Draft Release Didn't Trigger Workflow
|
|
370
|
+
|
|
371
|
+
**Symptom:** Release created but `publish.yml` never ran.
|
|
372
|
+
**Root cause:** Release was created as a draft. Draft releases don't emit `release: published` event.
|
|
373
|
+
**Fix:** Edit release and change to published: `gh release edit "v$VERSION" --draft=false`. Workflow should trigger immediately.
|
|
374
|
+
|
|
375
|
+
---
|
|
376
|
+
|
|
377
|
+
## Validation Checklist
|
|
378
|
+
|
|
379
|
+
Before starting ANY release, confirm:
|
|
380
|
+
|
|
381
|
+
- [ ] Version is valid semver: `node -p "require('semver').valid('VERSION')"` returns the version string (NOT null)
|
|
382
|
+
- [ ] NPM_TOKEN is an Automation token (no 2FA): `npm token list` shows `read-write` without OTP requirement
|
|
383
|
+
- [ ] Branch is clean: `git status` shows "nothing to commit, working tree clean"
|
|
384
|
+
- [ ] Tag doesn't exist: `git tag -l "vVERSION"` returns empty
|
|
385
|
+
- [ ] `SKIP_BUILD_BUMP=1` is set: `echo $SKIP_BUILD_BUMP` returns `1`
|
|
386
|
+
|
|
387
|
+
Before creating GitHub Release:
|
|
388
|
+
|
|
389
|
+
- [ ] All 3 package.json files have matching versions: `grep '"version"' package.json packages/*/package.json`
|
|
390
|
+
- [ ] Commit is pushed: `git log origin/main..main` returns empty
|
|
391
|
+
- [ ] Tag is pushed: `git ls-remote --tags origin vVERSION` returns the tag SHA
|
|
392
|
+
|
|
393
|
+
After GitHub Release:
|
|
394
|
+
|
|
395
|
+
- [ ] Release is published (NOT draft): `gh release view "vVERSION"` output doesn't contain "(draft)"
|
|
396
|
+
- [ ] Workflow is running: `gh run list --workflow=publish.yml --limit 1` shows "in_progress"
|
|
397
|
+
|
|
398
|
+
After workflow completes:
|
|
399
|
+
|
|
400
|
+
- [ ] Both jobs succeeded: Workflow shows green checkmarks
|
|
401
|
+
- [ ] SDK on npm: `npm view @bradygaster/squad-sdk version` returns correct version
|
|
402
|
+
- [ ] CLI on npm: `npm view @bradygaster/squad-cli version` returns correct version
|
|
403
|
+
- [ ] `latest` tags correct: `npm dist-tag ls @bradygaster/squad-sdk` shows `latest: VERSION`
|
|
404
|
+
- [ ] Packages install: `npm install @bradygaster/squad-cli` succeeds
|
|
405
|
+
|
|
406
|
+
After dev sync:
|
|
407
|
+
|
|
408
|
+
- [ ] dev branch has next preview version: `git show dev:package.json | grep version` shows next preview
|
|
409
|
+
|
|
410
|
+
---
|
|
411
|
+
|
|
412
|
+
## Post-Mortem Reference
|
|
413
|
+
|
|
414
|
+
This skill was created after the v0.8.22 release disaster. Full retrospective: `.squad/decisions/inbox/keaton-v0822-retrospective.md`
|
|
415
|
+
|
|
416
|
+
**Key learnings:**
|
|
417
|
+
1. No release without a runbook = improvisation = disaster
|
|
418
|
+
2. Semver validation is mandatory — 4-part versions break npm
|
|
419
|
+
3. NPM_TOKEN type matters — User tokens with 2FA fail in CI
|
|
420
|
+
4. Draft releases are a footgun — they don't trigger automation
|
|
421
|
+
5. Retry logic is essential — npm propagation takes time
|
|
422
|
+
|
|
423
|
+
**Never again.**
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: "reskill"
|
|
3
|
+
description: "Team-wide charter and history optimization through skill extraction"
|
|
4
|
+
domain: "team-optimization"
|
|
5
|
+
confidence: "high"
|
|
6
|
+
source: "manual — Brady directive to reduce per-agent context overhead"
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Context
|
|
10
|
+
|
|
11
|
+
When the coordinator hears "team, reskill" (or similar: "optimize context", "slim down charters"), trigger a team-wide optimization pass. The goal: reduce per-agent context consumption by extracting shared patterns from charters and histories into reusable skills.
|
|
12
|
+
|
|
13
|
+
This is a periodic maintenance activity. Run whenever charter/history bloat is suspected.
|
|
14
|
+
|
|
15
|
+
## Process
|
|
16
|
+
|
|
17
|
+
### Step 1: Audit
|
|
18
|
+
Read all agent charters and histories. Measure byte sizes. Identify:
|
|
19
|
+
|
|
20
|
+
- **Boilerplate** — sections repeated across ≥3 charters with <10% variation (collaboration, model, boundaries template)
|
|
21
|
+
- **Shared knowledge** — domain knowledge duplicated in 2+ charters (incident postmortems, technical patterns)
|
|
22
|
+
- **Mature learnings** — history entries appearing 3+ times across agents that should be promoted to skills
|
|
23
|
+
|
|
24
|
+
### Step 2: Extract
|
|
25
|
+
For each identified pattern:
|
|
26
|
+
1. Create or update a skill at `.squad/skills/{skill-name}/SKILL.md`
|
|
27
|
+
2. Follow the skill template format (frontmatter + Context + Patterns + Examples + Anti-Patterns)
|
|
28
|
+
3. Set confidence: low (first observation), medium (2+ agents), high (team-wide)
|
|
29
|
+
|
|
30
|
+
### Step 3: Trim
|
|
31
|
+
**Charters** — target ≤1.5KB per agent:
|
|
32
|
+
- Remove Collaboration section entirely (spawn prompt + agent-collaboration skill covers it)
|
|
33
|
+
- Remove Voice section (tagline blockquote at top of charter already captures it)
|
|
34
|
+
- Trim Model section to single line: `Preferred: {model}`
|
|
35
|
+
- Remove "When I'm unsure" boilerplate from Boundaries
|
|
36
|
+
- Remove domain knowledge now covered by a skill — add skill reference comment if helpful
|
|
37
|
+
- Keep: Identity, What I Own, unique How I Work patterns, Boundaries (domain list only)
|
|
38
|
+
|
|
39
|
+
**Histories** — target ≤8KB per agent:
|
|
40
|
+
- Apply history-hygiene skill to any history >12KB
|
|
41
|
+
- Promote recurring patterns (3+ occurrences across agents) to skills
|
|
42
|
+
- Summarize old entries into `## Core Context` section
|
|
43
|
+
- Remove session-specific metadata (dates, branch names, requester names)
|
|
44
|
+
|
|
45
|
+
### Step 4: Report
|
|
46
|
+
Output a savings table:
|
|
47
|
+
|
|
48
|
+
| Agent | Charter Before | Charter After | History Before | History After | Saved |
|
|
49
|
+
|-------|---------------|---------------|----------------|---------------|-------|
|
|
50
|
+
|
|
51
|
+
Include totals and percentage reduction.
|
|
52
|
+
|
|
53
|
+
## Patterns
|
|
54
|
+
|
|
55
|
+
### Minimal Charter Template (target format after reskill)
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
# {Name} — {Role}
|
|
59
|
+
|
|
60
|
+
> {Tagline — one sentence capturing voice and philosophy}
|
|
61
|
+
|
|
62
|
+
## Identity
|
|
63
|
+
- **Name:** {Name}
|
|
64
|
+
- **Role:** {Role}
|
|
65
|
+
- **Expertise:** {comma-separated list}
|
|
66
|
+
|
|
67
|
+
## What I Own
|
|
68
|
+
- {bullet list of owned artifacts/domains}
|
|
69
|
+
|
|
70
|
+
## How I Work
|
|
71
|
+
- {unique patterns and principles — NOT boilerplate}
|
|
72
|
+
|
|
73
|
+
## Boundaries
|
|
74
|
+
**I handle:** {domain list}
|
|
75
|
+
**I don't handle:** {explicit exclusions}
|
|
76
|
+
|
|
77
|
+
## Model
|
|
78
|
+
Preferred: {model}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Skill Extraction Threshold
|
|
82
|
+
- **1 charter** → leave in charter (unique to that agent)
|
|
83
|
+
- **2 charters** → consider extracting if >500 bytes of overlap
|
|
84
|
+
- **3+ charters** → always extract to a shared skill
|
|
85
|
+
|
|
86
|
+
## Anti-Patterns
|
|
87
|
+
- Don't delete unique per-agent identity or domain-specific knowledge
|
|
88
|
+
- Don't create skills for content only one agent uses
|
|
89
|
+
- Don't merge unrelated patterns into a single mega-skill
|
|
90
|
+
- Don't remove Model preference line (coordinator needs it for model selection)
|
|
91
|
+
- Don't touch `.squad/decisions.md` during reskill
|
|
92
|
+
- Don't remove the tagline blockquote — it's the charter's soul in one line
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: "reviewer-protocol"
|
|
3
|
+
description: "Reviewer rejection workflow and strict lockout semantics"
|
|
4
|
+
domain: "orchestration"
|
|
5
|
+
confidence: "high"
|
|
6
|
+
source: "extracted"
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Context
|
|
10
|
+
|
|
11
|
+
When a team member has a **Reviewer** role (e.g., Tester, Code Reviewer, Lead), they may approve or reject work from other agents. On rejection, the coordinator enforces strict lockout rules to ensure the original author does NOT self-revise. This prevents defensive feedback loops and ensures independent review.
|
|
12
|
+
|
|
13
|
+
## Patterns
|
|
14
|
+
|
|
15
|
+
### Reviewer Rejection Protocol
|
|
16
|
+
|
|
17
|
+
When a team member has a **Reviewer** role:
|
|
18
|
+
|
|
19
|
+
- Reviewers may **approve** or **reject** work from other agents.
|
|
20
|
+
- On **rejection**, the Reviewer may choose ONE of:
|
|
21
|
+
1. **Reassign:** Require a *different* agent to do the revision (not the original author).
|
|
22
|
+
2. **Escalate:** Require a *new* agent be spawned with specific expertise.
|
|
23
|
+
- The Coordinator MUST enforce this. If the Reviewer says "someone else should fix this," the original agent does NOT get to self-revise.
|
|
24
|
+
- If the Reviewer approves, work proceeds normally.
|
|
25
|
+
|
|
26
|
+
### Strict Lockout Semantics
|
|
27
|
+
|
|
28
|
+
When an artifact is **rejected** by a Reviewer:
|
|
29
|
+
|
|
30
|
+
1. **The original author is locked out.** They may NOT produce the next version of that artifact. No exceptions.
|
|
31
|
+
2. **A different agent MUST own the revision.** The Coordinator selects the revision author based on the Reviewer's recommendation (reassign or escalate).
|
|
32
|
+
3. **The Coordinator enforces this mechanically.** Before spawning a revision agent, the Coordinator MUST verify that the selected agent is NOT the original author. If the Reviewer names the original author as the fix agent, the Coordinator MUST refuse and ask the Reviewer to name a different agent.
|
|
33
|
+
4. **The locked-out author may NOT contribute to the revision** in any form — not as a co-author, advisor, or pair. The revision must be independently produced.
|
|
34
|
+
5. **Lockout scope:** The lockout applies to the specific artifact that was rejected. The original author may still work on other unrelated artifacts.
|
|
35
|
+
6. **Lockout duration:** The lockout persists for that revision cycle. If the revision is also rejected, the same rule applies again — the revision author is now also locked out, and a third agent must revise.
|
|
36
|
+
7. **Deadlock handling:** If all eligible agents have been locked out of an artifact, the Coordinator MUST escalate to the user rather than re-admitting a locked-out author.
|
|
37
|
+
|
|
38
|
+
## Examples
|
|
39
|
+
|
|
40
|
+
**Example 1: Reassign after rejection**
|
|
41
|
+
1. Fenster writes authentication module
|
|
42
|
+
2. Hockney (Tester) reviews → rejects: "Error handling is missing. Verbal should fix this."
|
|
43
|
+
3. Coordinator: Fenster is now locked out of this artifact
|
|
44
|
+
4. Coordinator spawns Verbal to revise the authentication module
|
|
45
|
+
5. Verbal produces v2
|
|
46
|
+
6. Hockney reviews v2 → approves
|
|
47
|
+
7. Lockout clears for next artifact
|
|
48
|
+
|
|
49
|
+
**Example 2: Escalate for expertise**
|
|
50
|
+
1. Edie writes TypeScript config
|
|
51
|
+
2. Keaton (Lead) reviews → rejects: "Need someone with deeper TS knowledge. Escalate."
|
|
52
|
+
3. Coordinator: Edie is now locked out
|
|
53
|
+
4. Coordinator spawns new agent (or existing TS expert) to revise
|
|
54
|
+
5. New agent produces v2
|
|
55
|
+
6. Keaton reviews v2
|
|
56
|
+
|
|
57
|
+
**Example 3: Deadlock handling**
|
|
58
|
+
1. Fenster writes module → rejected
|
|
59
|
+
2. Verbal revises → rejected
|
|
60
|
+
3. Hockney revises → rejected
|
|
61
|
+
4. All 3 eligible agents are now locked out
|
|
62
|
+
5. Coordinator: "All eligible agents have been locked out. Escalating to user: [artifact details]"
|
|
63
|
+
|
|
64
|
+
**Example 4: Reviewer accidentally names original author**
|
|
65
|
+
1. Fenster writes module → rejected
|
|
66
|
+
2. Hockney says: "Fenster should fix the error handling"
|
|
67
|
+
3. Coordinator: "Fenster is locked out as the original author. Please name a different agent."
|
|
68
|
+
4. Hockney: "Verbal, then"
|
|
69
|
+
5. Coordinator spawns Verbal
|
|
70
|
+
|
|
71
|
+
## Anti-Patterns
|
|
72
|
+
|
|
73
|
+
- ❌ Allowing the original author to self-revise after rejection
|
|
74
|
+
- ❌ Treating the locked-out author as an "advisor" or "co-author" on the revision
|
|
75
|
+
- ❌ Re-admitting a locked-out author when deadlock occurs (must escalate to user)
|
|
76
|
+
- ❌ Applying lockout across unrelated artifacts (scope is per-artifact)
|
|
77
|
+
- ❌ Accepting the Reviewer's assignment when they name the original author (must refuse and ask for a different agent)
|
|
78
|
+
- ❌ Clearing lockout before the revision is approved (lockout persists through revision cycle)
|
|
79
|
+
- ❌ Skipping verification that the revision agent is not the original author
|