@chris1807/claude-kit 2.2.3 → 2.2.4
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/README.md +1 -0
- package/package.json +1 -1
- package/templates/commands/cherry-pick.md +6 -4
- package/templates/commands/deploy-release.md +6 -4
- package/templates/commands/implement.md +23 -7
- package/templates/commands/promote.md +6 -4
- package/templates/commands/rework.md +8 -3
- package/templates/infrastructure/CLAUDE-WORKFLOW.md +39 -1
package/README.md
CHANGED
|
@@ -279,6 +279,7 @@ Claude automatically:
|
|
|
279
279
|
7. Generates a UAT checklist from acceptance criteria
|
|
280
280
|
8. **Pauses for you to manually test**
|
|
281
281
|
9. Creates the PR after you confirm
|
|
282
|
+
10. **Attaches any hand-run deployment script** to the work item, with the run command in the attachment comment, so `/promote`, `/cherry-pick`, and `/deploy-release` list it for every environment. Data fixes are planned as run-once migrations the app applies by itself wherever the project has that mechanism; a hand-run script is the fallback and the plan says why
|
|
282
283
|
|
|
283
284
|
**Implementing a whole Feature:** point `/implement` at a Feature work item and it implements the child User Stories in waves driven by the `Custom.Order` field — stories with the same order value are implemented in parallel (one agent per story, each in an isolated git worktree), and the next order value starts only after the previous wave is merged and green. Everything lands on one `feature/` branch with a single review, UAT pass, and PR that links every story.
|
|
284
285
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chris1807/claude-kit",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.4",
|
|
4
4
|
"description": "Claude Code starter kit for Azure DevOps teams — agents, hooks, MCP servers, slash commands, and end-to-end work item → PR → release → deploy workflow automation",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -52,14 +52,16 @@ Show them with the table above, before the confirmation:
|
|
|
52
52
|
```
|
|
53
53
|
📜 Scripts to run with this promotion:
|
|
54
54
|
|
|
55
|
-
| Work Item | Script |
|
|
56
|
-
|
|
57
|
-
| AB#1234 | 2026-09-11_add_delivery_index.sql |
|
|
58
|
-
| AB#1240 | backfill-tenant-flags.ps1 |
|
|
55
|
+
| Work Item | Script | How to run |
|
|
56
|
+
|-----------|--------|------------|
|
|
57
|
+
| AB#1234 | 2026-09-11_add_delivery_index.sql | sqlcmd -S <server> -d Compass -i 2026-09-11_add_delivery_index.sql |
|
|
58
|
+
| AB#1240 | backfill-tenant-flags.ps1 | — |
|
|
59
59
|
|
|
60
60
|
Download them from the work items. This command does not run them.
|
|
61
61
|
```
|
|
62
62
|
|
|
63
|
+
`How to run` is the attachment's comment (`attributes.comment` on the relation) — `/implement` and `/rework` write the run command there when they attach a script. Show `—` when it is empty.
|
|
64
|
+
|
|
63
65
|
If nothing carries an attachment, say `No deployment scripts attached` on one line and move on.
|
|
64
66
|
|
|
65
67
|
**Reported, never enforced.** A script does not block the promotion and does not change the gate check: the attachment may already have been run, may be a reference copy, may not be a script at all. Listing it is the whole job — the person deploying decides.
|
|
@@ -93,14 +93,16 @@ Show them with the gate check, before Step 4's confirmation:
|
|
|
93
93
|
```
|
|
94
94
|
📜 Scripts to run with this promotion:
|
|
95
95
|
|
|
96
|
-
| Work Item | Script |
|
|
97
|
-
|
|
98
|
-
| AB#1234 | 2026-09-11_add_delivery_index.sql |
|
|
99
|
-
| AB#1240 | backfill-tenant-flags.ps1 |
|
|
96
|
+
| Work Item | Script | How to run |
|
|
97
|
+
|-----------|--------|------------|
|
|
98
|
+
| AB#1234 | 2026-09-11_add_delivery_index.sql | sqlcmd -S <server> -d Compass -i 2026-09-11_add_delivery_index.sql |
|
|
99
|
+
| AB#1240 | backfill-tenant-flags.ps1 | — |
|
|
100
100
|
|
|
101
101
|
Download them from the work items. This command does not run them.
|
|
102
102
|
```
|
|
103
103
|
|
|
104
|
+
`How to run` is the attachment's comment (`attributes.comment` on the relation) — `/implement` and `/rework` write the run command there when they attach a script. Show `—` when it is empty.
|
|
105
|
+
|
|
104
106
|
If nothing carries an attachment, say `No deployment scripts attached` on one line and move on.
|
|
105
107
|
|
|
106
108
|
**Reported, never enforced.** A script does not block the promotion and does not change the gate check: the attachment may already have been run, may be a reference copy, may not be a script at all. Listing it is the whole job — the person deploying decides.
|
|
@@ -98,7 +98,7 @@ Each question below is about a cost that is cheap now and expensive once the cod
|
|
|
98
98
|
| 2 | **Is each piece in the right layer?** Domain / Application / Infrastructure / API boundaries hold — no business rules in a controller, no Mongo or EF types in Domain, no HTTP concepts below API. | An `IMongoCollection<T>` parameter on a Domain method |
|
|
99
99
|
| 3 | **What is the simplest plan that still meets every AC?** State it, then adopt it or say in one line why the heavier one is needed. | An interface with exactly one implementation, added "for testability" |
|
|
100
100
|
| 4 | **What else touches the files being modified?** Name the callers. A change to a shared contract, DTO, or response shape is a breaking change until proven otherwise. | Editing a shared DTO with no note about its other consumers |
|
|
101
|
-
| 5 | **What happens to data that already exists?** New required fields, schema changes, and backfills each need an answer for rows written before this change. | A non-nullable field added with no default and no backfill |
|
|
101
|
+
| 5 | **What happens to data that already exists?** New required fields, schema changes, and backfills each need an answer for rows written before this change — and the answer should run itself: the project's run-once migration mechanism if it has one, not a script someone has to remember in every environment (see **Deployment Scripts** in CLAUDE.md). | A non-nullable field added with no default and no backfill; a `backfill.js` to run by hand on test, staging and prod when the API already runs one-time migrations at startup |
|
|
102
102
|
| 6 | **How does it fail?** Partial failure, concurrent callers, a retried request. Is the operation idempotent, and does it need to be? | A multi-step write with no story for a crash between steps |
|
|
103
103
|
| 7 | **Does it hold at real data volume?** Queries inside loops, unbounded result sets, a missing index, a list endpoint with no paging. | A `foreach` over accounts issuing one query each |
|
|
104
104
|
| 8 | **Is it safe?** Authorization on every new endpoint, and **no sensitive field** (TIN, SSN, EIN, TaxId, BankAccountNumber, RoutingNumber, any `Encrypted*`) read, logged, returned, or projected — see the sensitive-data rule in CLAUDE.md. | A new endpoint returning a whole entity because it was convenient |
|
|
@@ -131,6 +131,10 @@ Present the plan to the user:
|
|
|
131
131
|
### Files to Delete (if any)
|
|
132
132
|
- `path/to/old/file.cs` — {why it's being removed}
|
|
133
133
|
|
|
134
|
+
### Data Changes (if any)
|
|
135
|
+
- {what changes in existing data} — **automated** by {the project's run-once mechanism}: `{file}`
|
|
136
|
+
- {what changes in existing data} — **hand-run** `{script path}`, because {which Deployment Scripts reason applies}. Attached to the work item when the PR goes up.
|
|
137
|
+
|
|
134
138
|
### Unit Tests
|
|
135
139
|
- `path/to/new.tests.cs` — covers {scenario 1}, {scenario 2}, {edge case}
|
|
136
140
|
- `path/to/existing.tests.cs` — adds cases for {new behavior}
|
|
@@ -390,14 +394,25 @@ Wait for the user's response before proceeding. Do NOT create a PR until confirm
|
|
|
390
394
|
- **title**: `AB#{id}: {work item title}`
|
|
391
395
|
- **labels**: `["hotfix"]` if the work item type is Hot Fix
|
|
392
396
|
3. Link the PR to the work item via `wit_work_item_link_write` (action `link_to_pull_request`)
|
|
393
|
-
4. **
|
|
394
|
-
5. **
|
|
397
|
+
4. **Attach deployment scripts** — see "Attaching Deployment Scripts" below.
|
|
398
|
+
5. **Close related Tasks and log hours** — see "Closing Related Tasks" below.
|
|
399
|
+
6. **Move the work item to `Code Review`** via `wit_work_item_write` (action `update`):
|
|
395
400
|
- **path**: `/fields/System.State`
|
|
396
401
|
- **value**: `Code Review`
|
|
397
402
|
|
|
398
403
|
If the project's process template does not have a `Code Review` state (the update call returns an invalid-state error), fall back in this order: `Resolved` → `In Review` → leave the current state and warn the user that the state could not be advanced automatically. Do not silently swallow the error.
|
|
399
404
|
|
|
400
|
-
> **Only the Task ever gets closed — never the parent.** The child Task is closed here, at PR creation (step
|
|
405
|
+
> **Only the Task ever gets closed — never the parent.** The child Task is closed here, at PR creation (step 5 above). When the PR is later completed/merged, do **not** enable Azure DevOps's "Complete associated work items" option: it transitions *every* linked work item, including the parent this PR is linked to. The parent User Story or Bug stays in `Code Review`: merging this PR into `main` deploys nothing, and promoting to `dev` deploys the code but **leaves the state alone** — the developer moves it to `Ready for Testing` once they have checked it on Dev. From there `/promote` and `/deploy-release` advance it to `Testing` → `Staging` → `Deployed` across `test → staging → prod` (see **Work Item States ↔ Environments** in CLAUDE.md).
|
|
406
|
+
|
|
407
|
+
### Attaching Deployment Scripts
|
|
408
|
+
|
|
409
|
+
A script that has to be run by hand — a SQL migration, a data backfill, a rename — is useless to the next environment if it only lives in the repo: `/promote`, `/cherry-pick` and `/deploy-release` find scripts on the **work item**, never in the diff. So every one this change adds or modifies is attached to the work item now, not left for someone to remember.
|
|
410
|
+
|
|
411
|
+
List the files the PR adds or modifies (`git diff --name-only --diff-filter=AM {BASE_BRANCH}...HEAD`) and pick out the ones a person runs by hand, once per environment. The test: if the UAT checklist, the PR, or your report tells someone to run it, it's one of these. App code, tests, build tooling and migrations the app or pipeline applies by itself are not. Each one should already be in the approved plan's **Data Changes** section with its reason for not being automated. A hand-run script that isn't there still gets attached, but say plainly that it wasn't in the plan.
|
|
412
|
+
|
|
413
|
+
Attach each one per **Deployment Scripts** in CLAUDE.md — upload through the REST API (the MCP server can only download), link it as an `AttachedFile` whose comment holds the repo path and the exact run command with the environment as a placeholder, and replace a stale same-name attachment rather than adding a second copy. Never attach a file with a connection string, key, password, or sensitive field value in it.
|
|
414
|
+
|
|
415
|
+
Report it on one line per script — `📜 Attached to AB#{id}: {file} — {how to run}` — or `No deployment scripts in this change` when there are none. A failed upload does not undo the PR; say `⚠️ NOT attached: {file} → AB#{id}` with the error and keep going.
|
|
401
416
|
|
|
402
417
|
### Closing Related Tasks
|
|
403
418
|
|
|
@@ -559,6 +574,7 @@ Present **one combined UAT checklist grouped by story** (Step 9 rules). Wait for
|
|
|
559
574
|
|
|
560
575
|
1. Push the feature branch and create **one PR**: title `AB#{feature-id}: {feature title}`, source `feature/...`, target `BASE_BRANCH`.
|
|
561
576
|
2. Link the **Feature and every implemented story** to the PR.
|
|
562
|
-
3. Run **
|
|
563
|
-
4.
|
|
564
|
-
5.
|
|
577
|
+
3. Run **Attaching Deployment Scripts** (Step 10) over the whole feature diff. Each script goes on the **story** whose change needs it — never on the Feature, which promotions don't gate.
|
|
578
|
+
4. Run **Closing Related Tasks** (Step 10) once, covering the child Tasks of every implemented story — one combined table, then the usual per-task hour prompts. Every story that got a Task in F4 has one to close here; a story whose Task creation was skipped gets one created and closed now, as in Step 10.
|
|
579
|
+
5. Move each implemented story to `Code Review` (same fallback rules as Step 10). **Do not change the Feature's state** — the Feature is a parent container; it advances only when its child stories are verified/closed, not when the PR goes up for review.
|
|
580
|
+
6. The Step 10 closing rule applies unchanged: only child **Tasks** are ever closed — here at PR creation, never the stories and never the Feature. Don't enable "Complete associated work items" when the PR is merged; it would transition the stories and the Feature along with the Tasks.
|
|
@@ -98,14 +98,16 @@ Show them with the gate check, before the confirmation:
|
|
|
98
98
|
```
|
|
99
99
|
📜 Scripts to run with this promotion:
|
|
100
100
|
|
|
101
|
-
| Work Item | Script |
|
|
102
|
-
|
|
103
|
-
| AB#1234 | 2026-09-11_add_delivery_index.sql |
|
|
104
|
-
| AB#1240 | backfill-tenant-flags.ps1 |
|
|
101
|
+
| Work Item | Script | How to run |
|
|
102
|
+
|-----------|--------|------------|
|
|
103
|
+
| AB#1234 | 2026-09-11_add_delivery_index.sql | sqlcmd -S <server> -d Compass -i 2026-09-11_add_delivery_index.sql |
|
|
104
|
+
| AB#1240 | backfill-tenant-flags.ps1 | — |
|
|
105
105
|
|
|
106
106
|
Download them from the work items. This command does not run them.
|
|
107
107
|
```
|
|
108
108
|
|
|
109
|
+
`How to run` is the attachment's comment (`attributes.comment` on the relation) — `/implement` and `/rework` write the run command there when they attach a script. Show `—` when it is empty.
|
|
110
|
+
|
|
109
111
|
If nothing carries an attachment, say `No deployment scripts attached` on one line and move on.
|
|
110
112
|
|
|
111
113
|
**Reported, never enforced.** A script does not block the promotion and does not change the gate check: the attachment may already have been run, may be a reference copy, may not be a script at all. Listing it is the whole job — the person deploying decides.
|
|
@@ -123,7 +123,7 @@ Each question below is about a cost that is cheap now and expensive once the cod
|
|
|
123
123
|
| 2 | **Is each piece in the right layer?** Domain / Application / Infrastructure / API boundaries hold — no business rules in a controller, no Mongo or EF types in Domain, no HTTP concepts below API. | An `IMongoCollection<T>` parameter on a Domain method |
|
|
124
124
|
| 3 | **What is the simplest plan that still meets every AC?** State it, then adopt it or say in one line why the heavier one is needed. | An interface with exactly one implementation, added "for testability" |
|
|
125
125
|
| 4 | **What else touches the files being modified?** Name the callers. A change to a shared contract, DTO, or response shape is a breaking change until proven otherwise. | Editing a shared DTO with no note about its other consumers |
|
|
126
|
-
| 5 | **What happens to data that already exists?** New required fields, schema changes, and backfills each need an answer for rows written before this change. | A non-nullable field added with no default and no backfill |
|
|
126
|
+
| 5 | **What happens to data that already exists?** New required fields, schema changes, and backfills each need an answer for rows written before this change — and the answer should run itself: the project's run-once migration mechanism if it has one, not a script someone has to remember in every environment (see **Deployment Scripts** in CLAUDE.md). | A non-nullable field added with no default and no backfill; a `backfill.js` to run by hand on test, staging and prod when the API already runs one-time migrations at startup |
|
|
127
127
|
| 6 | **How does it fail?** Partial failure, concurrent callers, a retried request. Is the operation idempotent, and does it need to be? | A multi-step write with no story for a crash between steps |
|
|
128
128
|
| 7 | **Does it hold at real data volume?** Queries inside loops, unbounded result sets, a missing index, a list endpoint with no paging. | A `foreach` over accounts issuing one query each |
|
|
129
129
|
| 8 | **Is it safe?** Authorization on every new endpoint, and **no sensitive field** (TIN, SSN, EIN, TaxId, BankAccountNumber, RoutingNumber, any `Encrypted*`) read, logged, returned, or projected — see the sensitive-data rule in CLAUDE.md. | A new endpoint returning a whole entity because it was convenient |
|
|
@@ -158,6 +158,10 @@ Present the plan to the user:
|
|
|
158
158
|
### Files to Delete (if any)
|
|
159
159
|
- `path/to/old/file.cs` — {why it's being removed}
|
|
160
160
|
|
|
161
|
+
### Data Changes (if any)
|
|
162
|
+
- {what changes in existing data} — **automated** by {the project's run-once mechanism}: `{file}`
|
|
163
|
+
- {what changes in existing data} — **hand-run** `{script path}`, because {which Deployment Scripts reason applies}. Attached to the work item when the PR goes up.
|
|
164
|
+
|
|
161
165
|
### Unit Tests
|
|
162
166
|
- `path/to/new.tests.cs` — covers {scenario the rework adds or fixes}
|
|
163
167
|
- `path/to/existing.tests.cs` — updates assertions for {changed behavior}
|
|
@@ -389,8 +393,9 @@ Wait for the user's response before proceeding. Do NOT push until confirmed.
|
|
|
389
393
|
|
|
390
394
|
1. Push the changes: `git push`
|
|
391
395
|
2. **Do not post a rework summary comment.** Do not add a summary of what changed to the work item Discussion (`wit_work_item_comment_write` (action `add`)) or as a PR thread. The pushed commits and the PR diff are the record of what changed — a prose summary duplicates them and clutters the work item. If the reviewer left specific PR comment threads, reply on those threads directly (that is what `/resolve-feedback` and `/fix-review` do); otherwise post nothing.
|
|
392
|
-
3. **
|
|
393
|
-
4. **
|
|
396
|
+
3. **Attach deployment scripts.** Run `/implement`'s **Attaching Deployment Scripts** step against this branch — diff it against the PR's target branch (`git diff --name-only --diff-filter=AM {target}...HEAD`), so a script the original PR added and never attached is caught too. A script this rework changed is already attached in its old form: replace that attachment, don't add a second copy — a promotion that lists both versions invites someone to run the stale one. Same rules and report lines as in `/implement` (see **Deployment Scripts** in CLAUDE.md).
|
|
397
|
+
4. **Close related Tasks and log hours** — see "Closing Related Tasks" below. This includes the rework Task created in Step 5 as well as any other child Tasks that became `Completed` as a result of this rework round.
|
|
398
|
+
5. **Move the work item back to `Code Review`** via `wit_work_item_write` (action `update`):
|
|
394
399
|
- **path**: `/fields/System.State`
|
|
395
400
|
- **value**: `Code Review`
|
|
396
401
|
|
|
@@ -185,10 +185,48 @@ How the commands use this table:
|
|
|
185
185
|
|
|
186
186
|
#### Deployment Scripts
|
|
187
187
|
|
|
188
|
-
A SQL migration
|
|
188
|
+
A SQL migration, a data backfill, a rename script — anything someone has to **run by hand** against an environment — is attached to the work item it belongs to, and it has to run in **every** environment that item's code lands in — test, then staging, then prod. The promotion carries the code, never the script.
|
|
189
189
|
|
|
190
190
|
`/promote`, `/cherry-pick` and `/deploy-release` therefore read the carried items' attachments (`wit_work_item` `action: get`, `expand: "Relations"`) and list any that look like something to run: an `AttachedFile` whose extension is **not** a document, image or video (`.docx .xlsx .csv .pdf .png .jpg .mp4` and friends). Everything else counts — the rule is loose on purpose, because a filename glanced at and dismissed costs seconds while a migration nobody ran costs an environment. The list appears before the confirmation, in the PR description, and again once the pipeline is green, which is when it actually has to be run.
|
|
191
191
|
|
|
192
|
+
**Automate first — a hand-run script is the fallback.** When a change needs existing data corrected, backfilled or renamed, Claude plans it through the project's own run-once migration mechanism if it has one: a seeder that records finished migrations (COMPASS's `DataSeeder` and its `dataMigrations` collection), EF Core migrations applied at startup, DbUp, a migration step the pipeline already runs. Those run by themselves on every environment's deploy, after the new code is live, with the app's own connection string — nothing to remember, nothing to attach. A hand-run script is right only when the change can't live there, and the plan names which reason applies:
|
|
193
|
+
|
|
194
|
+
- the project has no such mechanism — building one is its own work item, never folded into this one;
|
|
195
|
+
- the script creates the database or tenant the app would run in (provisioning);
|
|
196
|
+
- it touches something outside the app's own data stores (Azure resources, another system);
|
|
197
|
+
- a person has to check the result before it is applied.
|
|
198
|
+
|
|
199
|
+
**Claude always attaches the hand-run script it writes.** Committing it to the repo is not enough: the promotion commands look for scripts on the work item, never in the repo, so an unattached script is reported as `No deployment scripts attached` and goes unrun in staging or prod. Whenever Claude writes one — in `/implement`, `/rework`, or any other session — or tells someone to run one that isn't attached yet, it attaches it before finishing:
|
|
200
|
+
|
|
201
|
+
- **Which files.** A file in the change that a person runs by hand, once per environment: `.sql`, a Mongo script, a `.sh` / `.ps1` / `.py` / `.js` data fix. The test: if the UAT checklist, the PR, or Claude's report tells someone to run it, it gets attached. Not app code, not tests or build tooling, not a migration the app or the pipeline applies by itself.
|
|
202
|
+
- **Which work item.** The one whose change needs it. In a Feature run, the child story — never the Feature.
|
|
203
|
+
- **The comment says how to run it.** The attachment comment carries the repo path and the exact command, with the environment as a placeholder (e.g. `scripts/tenant-provisioning/rename-manager-roles.sh — after each environment's deploy: RMR_CONFIRM='apply <Env>' scripts/…/rename-manager-roles.sh apply <Env>`). Whoever deploys to prod next month won't have this session.
|
|
204
|
+
- **No secrets in the file.** Never attach a script with a connection string, key, password, or sensitive field value in it — the script reads those from the environment. If it can't, stop and tell the user instead of attaching.
|
|
205
|
+
- **Replace, don't duplicate.** If an attachment with the same filename is already on the item, compare it with the repo copy (`curl` the attachment's `url` into `diff`). Identical → leave it. Different → swap it in one PATCH (`remove` the old relation by its index, then `add` the new one), so a promotion never lists two versions of one script.
|
|
206
|
+
|
|
207
|
+
The Azure DevOps MCP server can only *download* attachments, so the upload goes through the REST API with an `az` token. The org and project GUID come from the work item's own `url` (`https://dev.azure.com/{org}/{projectId}/_apis/wit/workItems/{id}`):
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
TOKEN=$(az account get-access-token --resource 499b84ac-1321-427f-aa17-267ca6975798 --query accessToken -o tsv)
|
|
211
|
+
BASE="https://dev.azure.com/{org}/{projectId}/_apis/wit"
|
|
212
|
+
|
|
213
|
+
# 1. Upload the bytes — the response JSON carries the attachment "url"
|
|
214
|
+
curl -sS -X POST "$BASE/attachments?fileName={file name}&api-version=7.1" \
|
|
215
|
+
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/octet-stream" \
|
|
216
|
+
--data-binary @"{repo path}"
|
|
217
|
+
|
|
218
|
+
# 2. Link it to the work item. The body goes in a scratch file, because the run command
|
|
219
|
+
# in the comment usually has quotes that break inline JSON:
|
|
220
|
+
# [{"op":"test","path":"/rev","value":{rev from a fresh get}},
|
|
221
|
+
# {"op":"add","path":"/relations/-","value":{"rel":"AttachedFile","url":"{attachment url}",
|
|
222
|
+
# "attributes":{"comment":"{repo path} — {how to run}"}}}]
|
|
223
|
+
curl -sS -X PATCH "$BASE/workitems/{id}?api-version=7.1" \
|
|
224
|
+
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json-patch+json" \
|
|
225
|
+
--data-binary @"{scratch dir}/attach-patch.json"
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
Never print the token. If `az` has no session, swap the bearer header for `-u ":$AZURE_DEVOPS_PAT"`; if neither works, ask the user to run `! az login`. A failed attachment never blocks the PR, and it is never skipped quietly — the summary says `⚠️ NOT attached: {file} → AB#{id}` so it can be fixed before the first promotion.
|
|
229
|
+
|
|
192
230
|
**Reported, never enforced.** A script never blocks a promotion and never changes the gate check — it may already have been run, or be a reference copy. The person deploying decides; the commands only make sure nobody finds out afterwards.
|
|
193
231
|
|
|
194
232
|
#### Verifier Assignment
|