@1aboveio/skills 0.11.0 → 0.12.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.
Files changed (22) hide show
  1. package/package.json +1 -1
  2. package/runtime/skills/distribution/generated/recipes.json +13 -13
  3. package/skills/backend/pyspark/SKILL.md +1 -1
  4. package/skills/cicd-pipeline/mergify/SKILL.md +1 -0
  5. package/skills/cicd-pipeline/mergify/references/configuration.md +12 -6
  6. package/skills/cicd-pipeline/mergify/references/traps.md +28 -0
  7. package/skills/engineering/engineering-runtime/coherence/workflow.json +17 -17
  8. package/skills/engineering/engineering-runtime/scripts/workflow-policy.mjs +1 -1
  9. package/skills/engineering/implement-and-pr/SKILL.md +4 -3
  10. package/skills/engineering/implement-and-pr/agents/openai.yaml +9 -0
  11. package/skills/engineering/resolve-issues/SKILL.md +4 -3
  12. package/skills/engineering/resolve-issues/agents/openai.yaml +9 -0
  13. package/skills/engineering/resolve-issues/generated/workflow-repair-policy.json +11 -11
  14. package/skills/engineering/resolve-issues/references/pre-flight-model-slots.md +2 -2
  15. package/skills/engineering/resolve-issues/references/pre-flight-recording-and-checkout.md +1 -1
  16. package/skills/engineering/resolve-issues/references/pre-flight.md +1 -1
  17. package/skills/engineering/resolve-issues/scripts/preflight-questions.mjs +32 -9
  18. package/skills/engineering/resolve-issues/scripts/run-state.mjs +1 -1
  19. package/skills/engineering/resolve-release/references/preflight.md +3 -2
  20. package/skills/engineering/resolve-release/scripts/preflight-probes.mjs +13 -1
  21. package/skills/engineering/review-pr/SKILL.md +2 -1
  22. package/skills/engineering/review-pr/agents/openai.yaml +9 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@1aboveio/skills",
3
- "version": "0.11.0",
3
+ "version": "0.12.0",
4
4
  "description": "Install the 1AboveIO first-party skill groups through the native Skills CLI.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -8,7 +8,7 @@
8
8
  "id": "first-party",
9
9
  "type": "first-party",
10
10
  "package": "@1aboveio/skills",
11
- "version": "0.11.0",
11
+ "version": "0.12.0",
12
12
  "updatePolicy": "pinned-npm-version",
13
13
  "members": [
14
14
  {
@@ -454,7 +454,7 @@
454
454
  "sourceId": "first-party",
455
455
  "sourceType": "first-party",
456
456
  "package": "@1aboveio/skills",
457
- "version": "0.11.0",
457
+ "version": "0.12.0",
458
458
  "installPath": null,
459
459
  "members": [
460
460
  "harness-runtime",
@@ -526,7 +526,7 @@
526
526
  "sourceId": "first-party",
527
527
  "sourceType": "first-party",
528
528
  "package": "@1aboveio/skills",
529
- "version": "0.11.0",
529
+ "version": "0.12.0",
530
530
  "installPath": null,
531
531
  "members": [
532
532
  "harness-runtime",
@@ -570,7 +570,7 @@
570
570
  "sourceId": "first-party",
571
571
  "sourceType": "first-party",
572
572
  "package": "@1aboveio/skills",
573
- "version": "0.11.0",
573
+ "version": "0.12.0",
574
574
  "installPath": null,
575
575
  "members": [
576
576
  "harness-runtime",
@@ -603,7 +603,7 @@
603
603
  "sourceId": "first-party",
604
604
  "sourceType": "first-party",
605
605
  "package": "@1aboveio/skills",
606
- "version": "0.11.0",
606
+ "version": "0.12.0",
607
607
  "installPath": null,
608
608
  "members": [
609
609
  "harness-runtime",
@@ -646,7 +646,7 @@
646
646
  "sourceId": "first-party",
647
647
  "sourceType": "first-party",
648
648
  "package": "@1aboveio/skills",
649
- "version": "0.11.0",
649
+ "version": "0.12.0",
650
650
  "installPath": null,
651
651
  "members": [
652
652
  "harness-runtime",
@@ -676,7 +676,7 @@
676
676
  "sourceId": "first-party",
677
677
  "sourceType": "first-party",
678
678
  "package": "@1aboveio/skills",
679
- "version": "0.11.0",
679
+ "version": "0.12.0",
680
680
  "installPath": null,
681
681
  "members": [
682
682
  "harness-runtime",
@@ -716,7 +716,7 @@
716
716
  "sourceId": "first-party",
717
717
  "sourceType": "first-party",
718
718
  "package": "@1aboveio/skills",
719
- "version": "0.11.0",
719
+ "version": "0.12.0",
720
720
  "installPath": null,
721
721
  "members": [
722
722
  "harness-runtime",
@@ -768,7 +768,7 @@
768
768
  "sourceId": "first-party",
769
769
  "sourceType": "first-party",
770
770
  "package": "@1aboveio/skills",
771
- "version": "0.11.0",
771
+ "version": "0.12.0",
772
772
  "installPath": null,
773
773
  "members": [
774
774
  "harness-runtime",
@@ -924,7 +924,7 @@
924
924
  "sourceId": "first-party",
925
925
  "sourceType": "first-party",
926
926
  "package": "@1aboveio/skills",
927
- "version": "0.11.0",
927
+ "version": "0.12.0",
928
928
  "installPath": null,
929
929
  "members": [
930
930
  "harness-runtime"
@@ -950,7 +950,7 @@
950
950
  "sourceId": "first-party",
951
951
  "sourceType": "first-party",
952
952
  "package": "@1aboveio/skills",
953
- "version": "0.11.0",
953
+ "version": "0.12.0",
954
954
  "installPath": null,
955
955
  "members": [
956
956
  "harness-runtime"
@@ -1020,7 +1020,7 @@
1020
1020
  "sourceId": "first-party",
1021
1021
  "sourceType": "first-party",
1022
1022
  "package": "@1aboveio/skills",
1023
- "version": "0.11.0",
1023
+ "version": "0.12.0",
1024
1024
  "installPath": null,
1025
1025
  "members": [
1026
1026
  "harness-runtime",
@@ -1129,7 +1129,7 @@
1129
1129
  "sourceId": "first-party",
1130
1130
  "sourceType": "first-party",
1131
1131
  "package": "@1aboveio/skills",
1132
- "version": "0.11.0",
1132
+ "version": "0.12.0",
1133
1133
  "installPath": null,
1134
1134
  "members": [
1135
1135
  "harness-runtime",
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: pyspark
3
- description: Implement, debug, review, and optimize Apache Spark or PySpark batch jobs, ETL pipelines, feature calculations, and warehouse writes. Use whenever work involves Spark DataFrames or SQL, joins, windows, grouped state, UDFs, shuffle, skew, spill, slow stages, Spark Connect, spark-submit, Hudi publication, backfills, semantic parity, or production canaries, even when the request is framed only as a warehouse timeout or performance regression.
3
+ description: Implement, debug, review, and optimize Apache Spark or PySpark batch jobs, ETL pipelines, feature calculations, and Hudi/warehouse writes. Use whenever the task involves Spark DataFrames or Spark SQL, joins, windows, grouped state, UDFs, shuffle, skew, spill, slow stages, driver/executor OOM, Spark Connect, spark-submit, Hudi commits, backfills, bidirectional parity tests, validate-only canaries, or Spark event-log profiling — including when the user only mentions a warehouse job timeout, empty Hudi write, or performance regression on an EMR/Dataproc job.
4
4
  ---
5
5
 
6
6
  # PySpark
@@ -27,6 +27,7 @@ page alone — it deliberately does not contain enough to act on.
27
27
  |---|---|---|
28
28
  | **Get an open or just-pushed PR merged** | [`references/watch-contract.md`](references/watch-contract.md#enqueue-before-you-watch) | Enqueue, *then* watch — the watch never enqueues, so a watch started on a PR nothing will enqueue can only end `STALLED`. A push to an already-queued PR dequeues it (`pull-request-updated`): the verdict is stale, re-validate before re-enqueuing. Several ready at once? Enqueue them together — next row. |
29
29
  | **Deliver several ready PRs at once (a stack, an epic's units, a burst)** | [`references/watch-contract.md`](references/watch-contract.md#batch-delivery--enqueue-the-whole-ready-set-together) | Enqueue the whole ready set **together**, then watch: PRs riding one batch cost one CI run, and a red batch bisects to the culprit while the rest carry on. "If possible" is the point — a lone PR, or stragglers still waiting on review/CI/conflict, never hold the batch window open. |
30
+ | Stacked PR dequeued: "could not be retargeted onto … `main`" | [`references/traps.md`](references/traps.md) | Not a `batch_size` bug — enable GitHub `delete_branch_on_merge` (auto-delete head branches). Then `mergify stack push --force-rebase` for the stuck tip. |
30
31
  | Author or change `.mergify.yml` | [`references/configuration.md`](references/configuration.md) | [Rule 1](#rule-1--fetch-the-docs-before-writing-config): never write config from memory; finish with `validate` **and** `simulate`. |
31
32
  | **Watch a PR through the queue** | [`references/watch-contract.md`](references/watch-contract.md) | **[Rule 2](#rule-2--never-hand-roll-a-watcher): run the bundled watcher, never hand-roll one.** A watch observes a *progression*, not one state. |
32
33
  | Check status — "where is my PR?", "why is it stuck?" | [`references/diagnosis.md`](references/diagnosis.md#querying-pr-and-queue-status) | `mergify queue show <PR> -v` names the single blocking condition; nothing else in the toolchain does. `gh pr checks` is CI truth, never queue truth — and a one-off read of the `queued`/`dequeued` labels is neither. |
@@ -161,23 +161,29 @@ prefer on-demand unless you have a reason.
161
161
  "fine." `--json` for machine output; exits non-zero on any warn (`--allow-warn` to
162
162
  downgrade). Runs on the committed `.mergify.yml`, so it fits a pre-merge check.
163
163
  7. Confirm Mergify's app id: `gh api /apps/mergify --jq .id`.
164
- 8. `gh ruleset list` if a ruleset already covers this branch, fold these rules
164
+ 8. **Enable GitHub "Automatically delete head branches"** before relying on
165
+ stacked PRs in the merge queue:
166
+ `gh api repos/<owner>/<repo> -X PATCH -f delete_branch_on_merge=true`.
167
+ With this off, survivors of a stack dequeue with "could not be retargeted
168
+ onto the queue base branch" after a parent merges — see
169
+ [`traps.md`](traps.md). Confirm: `gh api repos/<owner>/<repo> --jq .delete_branch_on_merge`.
170
+ 9. `gh ruleset list` — if a ruleset already covers this branch, fold these rules
165
171
  into it (**PUT**) rather than stacking a second one. Overlapping rulesets are
166
172
  additive and the most restrictive wins, which is a confusing way to be blocked.
167
- 9. Inventory anything that pushes to the protected branch — the `update` rule
173
+ 10. Inventory anything that pushes to the protected branch — the `update` rule
168
174
  will block it. Add each as a bypass actor (GitHub Actions = `15368`):
169
175
  `grep -rnE 'git push|create-pull-request|github-script' .github/workflows/`
170
- 10. Apply `assets/templates/ruleset.json`. Dry-run with
176
+ 11. Apply `assets/templates/ruleset.json`. Dry-run with
171
177
  `"enforcement": "evaluate"` first if you want to see what it would block —
172
178
  read the results from `rule-suites`.
173
- 11. Prove the allowed path **before** the blocked one: enqueue a PR with
179
+ 12. Prove the allowed path **before** the blocked one: enqueue a PR with
174
180
  `@mergifyio queue`, confirm the 👍, and watch `mergify queue show <PR> -v`
175
181
  through to merge. A ruleset strict enough to block humans can also block
176
182
  Mergify if a bypass id is wrong, and you would rather learn that while you
177
183
  can still merge the fix.
178
- 12. Now prove the blocked path: open a throwaway PR and try to merge it without
184
+ 13. Now prove the blocked path: open a throwaway PR and try to merge it without
179
185
  enqueuing, as a non-bypass user. GitHub must refuse, naming the ruleset.
180
- 13. Decide the escape hatches: keep `priority_rules` (jump the line), and either
186
+ 14. Decide the escape hatches: keep `priority_rules` (jump the line), and either
181
187
  keep or delete the `emergency-merge` rule (skips CI, cannot be limited to
182
188
  admins). Keep the `OrganizationAdmin` bypass either way — it is the only way
183
189
  back in if Mergify has an outage.
@@ -76,3 +76,31 @@ The default (`queue`) injects ruleset requirements into entry conditions too, an
76
76
  a Mergify check that deliberately fails pre-queue then blocks the enqueue that
77
77
  would make it pass.
78
78
 
79
+ **Stacked PRs dequeue with "could not be retargeted onto the queue base
80
+ branch" when head branches survive merge.** This is not a `.mergify.yml`
81
+ `batch_size` / `merge-batch` bug. Mergify *can* land a stack when members are
82
+ queued together (stack-aware base + batching), but after a lower member merges
83
+ GitHub must restack the survivors onto `main`. That retarget happens when the
84
+ merged PR's **head branch is deleted**. If the repository has
85
+ `delete_branch_on_merge: false`, parent stack refs stay on the remote, GitHub
86
+ never moves the next PR's base from `parent-head` → `main`, and Mergify dequeues
87
+ with `base-ref-alignment-timeout` / "stacked on another whose head branch still
88
+ exists after merging" — even while the tip was already in the queue and draft
89
+ batch CI was green. Hit on skyee-ai-risk ADR 0044 stack (#2108 after #2107;
90
+ #2110 after #2108/#2109). Fix the repo setting, not the queue rule:
91
+
92
+ ```bash
93
+ gh api repos/<owner>/<repo> -X PATCH -f delete_branch_on_merge=true \
94
+ --jq .delete_branch_on_merge
95
+ ```
96
+
97
+ Verify with `gh api repos/<owner>/<repo> --jq .delete_branch_on_merge` (must be
98
+ `true`). If a tip is already stuck, `mergify stack push --force-rebase` (or a
99
+ manual base edit onto `main`) unblocks that incident; auto-delete prevents the
100
+ next one. Keep the full `Depends-On: #N` chain on every stack member — without
101
+ it Mergify may not treat the chain as a stack and keeps literal bases, which
102
+ collides with `queue_conditions: base = main`. Do not merge unrelated `main` PRs
103
+ through the middle of an open stack unless you expect another rebase cycle.
104
+ For GitHub-native stacks, Mergify's ruleset bypass should be **`exempt`** (not
105
+ only `always`); see [Stacked Pull Requests](https://docs.mergify.com/merge-queue/stacks/).
106
+
@@ -360,7 +360,7 @@
360
360
  "id": "first-party",
361
361
  "type": "first-party",
362
362
  "package": "@1aboveio/skills",
363
- "version": "0.11.0"
363
+ "version": "0.12.0"
364
364
  },
365
365
  "contentDigest": "eff6c7b5931bce5b2265a619bccddd371a89df6ce7bc2edc74f11d00060a71dd",
366
366
  "digestExcludes": []
@@ -373,7 +373,7 @@
373
373
  "id": "first-party",
374
374
  "type": "first-party",
375
375
  "package": "@1aboveio/skills",
376
- "version": "0.11.0"
376
+ "version": "0.12.0"
377
377
  },
378
378
  "contentDigest": "08230dc57a53d6526692b50138038abbd80abce1a067e01c52ad6acc182caf7e",
379
379
  "digestExcludes": []
@@ -386,7 +386,7 @@
386
386
  "id": "first-party",
387
387
  "type": "first-party",
388
388
  "package": "@1aboveio/skills",
389
- "version": "0.11.0"
389
+ "version": "0.12.0"
390
390
  },
391
391
  "contentDigest": "9eea7bfba348ddaea1b934c9a7fabdd9b101df8a146e1c93e947da4d335f1d98",
392
392
  "digestExcludes": []
@@ -399,9 +399,9 @@
399
399
  "id": "first-party",
400
400
  "type": "first-party",
401
401
  "package": "@1aboveio/skills",
402
- "version": "0.11.0"
402
+ "version": "0.12.0"
403
403
  },
404
- "contentDigest": "8e379be5d9412d5784c1286a55fc612af4b6479c2247bc1d53f4fb0183fecd98",
404
+ "contentDigest": "58b0556228a9271cf9e33727a05fc08a4fdfd29512ec0936b169f0a55d60e6ef",
405
405
  "digestExcludes": []
406
406
  },
407
407
  {
@@ -412,9 +412,9 @@
412
412
  "id": "first-party",
413
413
  "type": "first-party",
414
414
  "package": "@1aboveio/skills",
415
- "version": "0.11.0"
415
+ "version": "0.12.0"
416
416
  },
417
- "contentDigest": "430b29b6b95e5cba5b06d365254ae5abd680684b7f053b1ca1694319c1b7f9fb",
417
+ "contentDigest": "5351b88d73d56c27b25ff09c72ab6029fe0805bf7c459648424747108433c175",
418
418
  "digestExcludes": []
419
419
  },
420
420
  {
@@ -425,9 +425,9 @@
425
425
  "id": "first-party",
426
426
  "type": "first-party",
427
427
  "package": "@1aboveio/skills",
428
- "version": "0.11.0"
428
+ "version": "0.12.0"
429
429
  },
430
- "contentDigest": "b9b918b357b78f3c5d8f5110b66418b3b62a94825dc7f1905dcc5691a9476e86",
430
+ "contentDigest": "b5af4dccf703362d4f41cac4fdff48305f652a00338d85975a2e5c35ec6bc61c",
431
431
  "digestExcludes": []
432
432
  },
433
433
  {
@@ -438,9 +438,9 @@
438
438
  "id": "first-party",
439
439
  "type": "first-party",
440
440
  "package": "@1aboveio/skills",
441
- "version": "0.11.0"
441
+ "version": "0.12.0"
442
442
  },
443
- "contentDigest": "9cc85e87f5bfbb5570770692f14a95959aac6ade2d5364e827fc39b08871d346",
443
+ "contentDigest": "f048fd00c69f2dc666fc7a3096cfeee6dfba73933bfb69602f3f0e26159798cc",
444
444
  "digestExcludes": []
445
445
  },
446
446
  {
@@ -451,7 +451,7 @@
451
451
  "id": "first-party",
452
452
  "type": "first-party",
453
453
  "package": "@1aboveio/skills",
454
- "version": "0.11.0"
454
+ "version": "0.12.0"
455
455
  },
456
456
  "contentDigest": "90a7c4e1ad6da1e632ea2c5259e4967ffebb84353adccbca8dfc5d6bc50b60c1",
457
457
  "digestExcludes": []
@@ -464,15 +464,15 @@
464
464
  "id": "first-party",
465
465
  "type": "first-party",
466
466
  "package": "@1aboveio/skills",
467
- "version": "0.11.0"
467
+ "version": "0.12.0"
468
468
  },
469
- "contentDigest": "0b24d6220d6d2577f2c838ef2c4fa165384594cf4c626960d2e707fd7cd0a228",
469
+ "contentDigest": "e9bfbdfcbca59efce2c530a8a68f66466b0333dcb046760aab4eaee53ec7e559",
470
470
  "digestExcludes": [
471
471
  "coherence/workflow.json"
472
472
  ]
473
473
  }
474
474
  ],
475
- "releaseIdentity": "2e943acd0d8493f82146b6bd7e2dc769a4f876f2587155913f314b0a5efc120c",
475
+ "releaseIdentity": "559141ff07a7aa2b7e20884c7a3a636c4b23207993d25b7ba00b8a872def0517",
476
476
  "lifecycleAuthority": "native-skills-cli",
477
477
  "repairRecipe": {
478
478
  "id": "engineering-workflow-dependency-first",
@@ -524,7 +524,7 @@
524
524
  "sourceId": "first-party",
525
525
  "sourceType": "first-party",
526
526
  "package": "@1aboveio/skills",
527
- "version": "0.11.0",
527
+ "version": "0.12.0",
528
528
  "installPath": null,
529
529
  "members": [
530
530
  "harness-runtime",
@@ -540,7 +540,7 @@
540
540
  "commands": [
541
541
  {
542
542
  "transport": "npm",
543
- "command": "npx @1aboveio/skills@0.11.0 install --group engineering-workflow"
543
+ "command": "npx @1aboveio/skills@0.12.0 install --group engineering-workflow"
544
544
  }
545
545
  ],
546
546
  "onFailure": {
@@ -93,7 +93,7 @@ export const WORKFLOW_TRUSTED_SOURCES = deepFreeze({
93
93
  id: 'first-party',
94
94
  type: 'first-party',
95
95
  package: '@1aboveio/skills',
96
- version: '0.11.0',
96
+ version: '0.12.0',
97
97
  },
98
98
  matt: {
99
99
  id: 'matt-pocock',
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  name: implement-and-pr
3
- description: "Implement a GitHub issue, PRD, design doc, or approved plan and open the pull request the single produce step: TDD for criteria-backed work, tests from criteria, evidence, and a Review Contract on the PR. NOT the full issue-to-merge-ready loop (resolve-issues)."
3
+ description: "Slash-command only (/implement-and-pr). Produce step: implement an approved issue/PRD/plan with TDD + tests + evidence and open a PR with a Review Contract. Do not auto-select only on explicit user/orchestrator invoke. NOT the full issuemerge-ready loop (resolve-issues / rush-issues)."
4
+ disable-model-invocation: true
4
5
  dependencies:
5
6
  - ensure-coverage
6
7
  - tdd
@@ -9,13 +10,13 @@ dependencies:
9
10
 
10
11
  # Implement and PR
11
12
 
12
- Use this skill to turn an approved source work item into a tested pull request with clear review evidence.
13
+ Turn an approved source work item into a tested pull request with clear review evidence.
13
14
 
14
15
  ## Related Skills
15
16
 
16
17
  This is the *produce* step in the PR chain; it consumes the skills below by name rather than re-deriving their doctrine:
17
18
 
18
- - `resolve-issues` — the **orchestrator** that owns the issue→merge-ready loop and calls this skill as its implement step; reach for this skill directly only for a one-off "implement and open a PR, no review loop" request.
19
+ - `resolve-issues` / `rush-issues` orchestrators that call this as the implement step; use standalone only for a one-off "implement and open a PR, no review loop" request.
19
20
  - `ensure-coverage` — coverage doctrine you implement against: its create-mode criteria are your input (approved **first/upstream**), its `coverage-ledger.mjs` gate is your self-check; source of truth for required levels, the Surface Baseline Contract, and mock/depth rules.
20
21
  - `tdd` — the red-green-refactor loop used in TDD Mode.
21
22
  - `e2e-test` — Playwright structure + route coverage for browser/journey tests; its render-health tier + presentation sweep is step 6's per-surface render check (distinct from the curated golden-path `smoke` gate step 6 runs when a critical journey is touched).
@@ -0,0 +1,9 @@
1
+ interface:
2
+ display_name: "Implement and PR"
3
+ short_description: "Slash/explicit-only produce step: implement + open a PR with a Review Contract"
4
+
5
+ policy:
6
+ # Codex counterpart to SKILL.md disable-model-invocation: true
7
+ # (Claude Code / Pi). Keeps $implement-and-pr / explicit invoke; blocks
8
+ # description-based auto-selection.
9
+ allow_implicit_invocation: false
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  name: resolve-issues
3
- description: "Drive GitHub issues (single or epic) to merge-ready PRs: implement → e2e → independent review on a different model ∥ CI → fix, looped until the review passes; an epic is assembled, integration-verified, and delivered one PR per independently-shippable component. Orchestrates implement-and-pr, e2e-test, ensure-coverage, review-pr, smoke. NOT one implement+PR alone, review alone, or releasing to production (resolve-release)."
3
+ description: "Slash-command only (/resolve-issues). Drive GitHub issues (single or epic) to merge-ready PRs: implement → e2e → independent review on a different model ∥ CI → fix, looped until PASS; epics assemble one PR per shippable component. Orchestrates implement-and-pr, e2e-test, ensure-coverage, review-pr, smoke. Do not auto-select — only on explicit user/orchestrator invoke. NOT one implement+PR alone, review alone, rush-issues, or production release (resolve-release)."
4
+ disable-model-invocation: true
4
5
  dependencies:
5
6
  - implement-and-pr
6
7
  - e2e-test
@@ -52,7 +53,7 @@ A step that serves none of these does not belong in this skill — see [The remo
52
53
 
53
54
  - **Both model slots are filled individually by the human**, each as an operating point (a model *and* its banked effort), with alternates shown. **`reviewer ≠ implementer`** is hard — it is what makes guarantee 2 an independent review rather than a second opinion from the same blind spots.
54
55
  - **Probe, never assume, the merge path** — `deliveryMode`, `queueProvider`, and above all **`enqueueTrigger`**: on a repo that auto-merges once conditions hold, *posting the review verdict as an approval **is** the merge*. Ask [`run-state.mjs approval-gate <slug> [componentId]`](scripts/run-state.mjs) before any verdict reaches GitHub. → [why](references/why.md#the-enqueue-trigger)
55
- - **`autonomy` is one ask that subsumes `mergeShippable`** (guarantee 4). Ask the manifest what it resolved to — `run-state.mjs autonomy <slug>` — never re-derive it from prose. No level lifts the design gate, the breaker's `descope`, or its round ceiling.
56
+ - **`autonomy` is filled as `autonomous` by default** (subsumes `mergeShippable`; guarantee 4). It is **not** a pre-flight question — stated in the summary; a human may override to `supervised`. Ask the manifest what it resolved to — `run-state.mjs autonomy <slug>` — never re-derive it from prose. No level lifts the design gate, the breaker's `descope`, or its round ceiling.
56
57
  - **No silent fallback:** read back the model every spawn actually ran on and record it per unit. A reviewer read-back ≠ the confirmed review model means the verdict does not count.
57
58
 
58
59
  ## Routing (read this first)
@@ -111,7 +112,7 @@ A step that serves none of these does not belong in this skill ([the removal pat
111
112
  Read [references/pre-flight.md](references/pre-flight.md) and run its seven steps (0-6) — **once**, before intake, never mid-run. One neutral question batch through [`scripts/preflight-questions.mjs`](scripts/preflight-questions.mjs); invoke only the calls it plans; record the completed patch atomically (a cancelled gate records nothing). The non-negotiables it elaborates rather than replaces:
112
113
 
113
114
  - **Models** — the **implementer** is asked with alternates shown; the **reviewer is filled from the ranking, never asked**, and stated in the gate. **Reviewer ≠ implementer** is hard; a slot is an **operating point** (model + banked `models.<slot>Effort`). **No silent fallback:** read back the model each spawn ran on (`units[].implementationModel` when it differs) — a reviewer read-back ≠ the confirmed model voids the verdict for guarantee 2.
114
- - **Everything else is probed, never assumed** — `targetBranch` from fetched remote heads; `deliveryMode` + `queueProvider` + `enqueueTrigger` from [`detect-delivery-mode.mjs`](scripts/detect-delivery-mode.mjs), UNKNOWN being a human ask; `autonomy` one ask recommending `autonomous`, subsuming `mergeShippable`, lifting neither the design gate nor the breaker's `descope` or ceiling. Where a repo auto-merges on its conditions, **posting the verdict as an approval *is* the merge** — ask [`run-state.mjs approval-gate <slug> [componentId]`](scripts/run-state.mjs) first.
115
+ - **Everything else is probed or filled, never assumed mid-run** — `targetBranch` from fetched remote heads; `deliveryMode` + `queueProvider` + `enqueueTrigger` from [`detect-delivery-mode.mjs`](scripts/detect-delivery-mode.mjs), UNKNOWN being a human ask; `autonomy` **filled** as `autonomous` by [`preflight-questions.mjs`](scripts/preflight-questions.mjs) (stated, overridable to `supervised`), subsuming `mergeShippable`, lifting neither the design gate nor the breaker's `descope` or ceiling. Where a repo auto-merges on its conditions, **posting the verdict as an approval *is* the merge** — ask [`run-state.mjs approval-gate <slug> [componentId]`](scripts/run-state.mjs) first.
115
116
  - **Design first** — pre-flight **skims for units that already owe a design and hands them back** before anything else is settled.
116
117
 
117
118
  An outer orchestrator that already ran an equivalent gate → inherit, don't re-prompt.
@@ -0,0 +1,9 @@
1
+ interface:
2
+ display_name: "Resolve Issues"
3
+ short_description: "Slash/explicit-only orchestrator: issues/epic → merge-ready PR(s)"
4
+
5
+ policy:
6
+ # Codex counterpart to SKILL.md disable-model-invocation: true
7
+ # (Claude Code / Pi). Keeps $resolve-issues / explicit invoke; blocks
8
+ # description-based auto-selection.
9
+ allow_implicit_invocation: false
@@ -236,7 +236,7 @@
236
236
  "id": "first-party",
237
237
  "type": "first-party",
238
238
  "package": "@1aboveio/skills",
239
- "version": "0.11.0"
239
+ "version": "0.12.0"
240
240
  }
241
241
  },
242
242
  {
@@ -247,7 +247,7 @@
247
247
  "id": "first-party",
248
248
  "type": "first-party",
249
249
  "package": "@1aboveio/skills",
250
- "version": "0.11.0"
250
+ "version": "0.12.0"
251
251
  }
252
252
  },
253
253
  {
@@ -258,7 +258,7 @@
258
258
  "id": "first-party",
259
259
  "type": "first-party",
260
260
  "package": "@1aboveio/skills",
261
- "version": "0.11.0"
261
+ "version": "0.12.0"
262
262
  }
263
263
  },
264
264
  {
@@ -269,7 +269,7 @@
269
269
  "id": "first-party",
270
270
  "type": "first-party",
271
271
  "package": "@1aboveio/skills",
272
- "version": "0.11.0"
272
+ "version": "0.12.0"
273
273
  }
274
274
  },
275
275
  {
@@ -280,7 +280,7 @@
280
280
  "id": "first-party",
281
281
  "type": "first-party",
282
282
  "package": "@1aboveio/skills",
283
- "version": "0.11.0"
283
+ "version": "0.12.0"
284
284
  }
285
285
  },
286
286
  {
@@ -291,7 +291,7 @@
291
291
  "id": "first-party",
292
292
  "type": "first-party",
293
293
  "package": "@1aboveio/skills",
294
- "version": "0.11.0"
294
+ "version": "0.12.0"
295
295
  }
296
296
  },
297
297
  {
@@ -302,7 +302,7 @@
302
302
  "id": "first-party",
303
303
  "type": "first-party",
304
304
  "package": "@1aboveio/skills",
305
- "version": "0.11.0"
305
+ "version": "0.12.0"
306
306
  }
307
307
  },
308
308
  {
@@ -313,7 +313,7 @@
313
313
  "id": "first-party",
314
314
  "type": "first-party",
315
315
  "package": "@1aboveio/skills",
316
- "version": "0.11.0"
316
+ "version": "0.12.0"
317
317
  }
318
318
  },
319
319
  {
@@ -324,7 +324,7 @@
324
324
  "id": "first-party",
325
325
  "type": "first-party",
326
326
  "package": "@1aboveio/skills",
327
- "version": "0.11.0"
327
+ "version": "0.12.0"
328
328
  }
329
329
  }
330
330
  ],
@@ -419,7 +419,7 @@
419
419
  "sourceId": "first-party",
420
420
  "sourceType": "first-party",
421
421
  "package": "@1aboveio/skills",
422
- "version": "0.11.0",
422
+ "version": "0.12.0",
423
423
  "installPath": null,
424
424
  "members": [
425
425
  "harness-runtime",
@@ -435,7 +435,7 @@
435
435
  "commands": [
436
436
  {
437
437
  "transport": "npm",
438
- "command": "npx @1aboveio/skills@0.11.0 install --group engineering-workflow"
438
+ "command": "npx @1aboveio/skills@0.12.0 install --group engineering-workflow"
439
439
  }
440
440
  ],
441
441
  "onFailure": {
@@ -19,7 +19,7 @@ Read this when pre-flight reaches step 1. The other steps stay in the index.
19
19
  - **Propose only models that appeared in a discovery source or that the user named.** If discovery yields nothing, the proposal block must contain the *question* — "list the models available here" — with those slots left empty, not filled with plausible names: a guessed model (e.g. a Claude model in a harness that only runs one provider) is worse than no suggestion, because a confirmed-but-unrunnable model resurfaces mid-run as the silent-fallback failure the [no-silent-fallback guard](../SKILL.md#pre-flight-once-before-intake--never-mid-run) exists to catch. Your training-data knowledge of what models exist is not a discovery source.
20
20
 
21
21
 
22
- 2. **Classify the discovered models into capability tiers, then settle both slots in this gate.** The slots are **implementer · reviewer**. The **implementer is always asked** — the strength call, made per run against the run's risk profile; there is no pre-packaged profile. **The reviewer is never asked:** it is filled from a ranking (team default, then the diversity ladder), resolved against the answered implementer — `reviewer ≠ implementer` is the only possible collision and the ranking just moves down one. So the gate is **three questions on every run**: implementer, target branch, autonomy. A harness that discovered a single model is still not asked (nothing to pick); it takes that id, recorded `NOT INDEPENDENT`. **Filled is not silent** — state the reviewer, its operating point, its rank and any `reduced diversity` flag in the pre-flight summary, as with `workspaceMode` and `deliveryMode`, so an override costs one message. → [why](why.md#the-reviewer-slot-is-filled-not-asked)
22
+ 2. **Classify the discovered models into capability tiers, then settle both slots in this gate.** The slots are **implementer · reviewer**. The **implementer is always asked** — the strength call, made per run against the run's risk profile; there is no pre-packaged profile. **The reviewer is never asked:** it is filled from a ranking (team default, then the diversity ladder), resolved against the answered implementer — `reviewer ≠ implementer` is the only possible collision and the ranking just moves down one. So the gate is **two questions on every run**: implementer and target branch. **Autonomy is filled as `autonomous`** (stated; overridable to `supervised`) — same “filled, not asked” shape as the reviewer. A harness that discovered a single model is still not asked (nothing to pick); it takes that id, recorded `NOT INDEPENDENT`. **Filled is not silent** — state the reviewer, autonomy, operating points, rank and any `reduced diversity` flag in the pre-flight summary, as with `workspaceMode` and `deliveryMode`, so an override costs one message. → [why](why.md#the-reviewer-slot-is-filled-not-asked)
23
23
 
24
24
  **Mechanized, not described:** `preflight-questions.mjs` plans no `review` question in any shape it accepts and resolves the fill at `record`, reporting `reviewFill: { id, reason }` (`team-default` · `ladder` · `human-named` · `no-distinct-candidate`). Asking the reviewer is off-contract, not judgment.
25
25
 
@@ -38,4 +38,4 @@ Read this when pre-flight reaches step 1. The other steps stay in the index.
38
38
  - **A slot is a model *and its operating point*** — each banked point is offered as its own slot candidate (`example-coder-2 @ high (balanced-coder)` · `example-coder-2 @ max (deep-reasoner)`), and the effort is **read from the catalog, never asked per run** (the effort rule and `high`-is-the-floor doctrine live in [model-catalog.md](model-catalog.md)). Record the picked effort next to the picked id (`models.<slot>Effort`) so a resume spawns at the same point.
39
39
  - **Hard rules hold whatever the human picks:** reviewer **≠** implementer; the family preference never licenses an undiscovered model — a **single-provider harness** (e.g. Codex with only GPT-family models) picks a different model *within* the family and flags `reduced diversity — same family`; only one model available → the review is *not* independent, say so. A selection that would break a hard rule is **bounced back to the human with the conflict named — never silently repaired.** A model the human names that discovery didn't yield is taken as the human's own discovery source.
40
40
  - **What the recommendation is based on (pre-intake):** a quick skim of the named issue(s) — title, labels, body — is enough to tell an auth/money/migration-heavy run or a declared refactor from routine feature work; cheap, and it doesn't move this gate after intake. If full intake later contradicts the confirmed implementer tier (a run confirmed on a balanced-coder implementer turns out predominantly high-risk once the sub-issues are enumerated), **surface a one-time re-confirm of the implementer slot then** — don't silently proceed on the wrong pick, and don't silently upgrade either; re-confirmation is the only strength lever, so a mis-called run gets exactly one deliberate correction.
41
- - **Build one neutral question batch and let the shared runtime plan it.** Use [`scripts/preflight-questions.mjs`](../scripts/preflight-questions.mjs): the implementer question listing every eligible discovered **operating point**, followed by target branch and autonomy three questions, on every run and every adapter, in one call. The reviewer ranking rides the same input (`review: { default?, candidates: [...] }`) and produces **no** question; the planner returns `reviewRanking` and `defaulted.review` for the summary, and `record` returns the resolved `reviewFill`. Pass the exact `currentTurnCapabilities` from step 0; invoke only the native payload call(s) the returned `interaction.calls` plans, in order, and normalize the responses before recording. Recommended options stay first with one-line rationales. **Listing the alternates is load-bearing** — without them the human cannot see what discovery found and can only rubber-stamp; for the filled reviewer the alternates are the ranking, printed in the summary rather than as choices. Never drop or combine a slot to hide overflow.
41
+ - **Build one neutral question batch and let the shared runtime plan it.** Use [`scripts/preflight-questions.mjs`](../scripts/preflight-questions.mjs): the implementer question listing every eligible discovered **operating point**, followed by target branch — **two questions**, on every run and every adapter, in one call. The reviewer ranking rides the same input (`review: { default?, candidates: [...] }`) and produces **no** question; autonomy is likewise filled (`defaulted.autonomy = autonomous`) with no question. The planner returns `reviewRanking`, `defaulted.review`, and `defaulted.autonomy` for the summary; `record` returns `reviewFill` and `autonomyFill`. Pass the exact `currentTurnCapabilities` from step 0; invoke only the native payload call(s) the returned `interaction.calls` plans, in order, and normalize the responses before recording. Recommended options stay first with one-line rationales. **Listing the alternates is load-bearing** — without them the human cannot see what discovery found and can only rubber-stamp; for the filled reviewer the alternates are the ranking, printed in the summary rather than as choices. Never drop or combine a slot to hide overflow.
@@ -6,7 +6,7 @@ what each `autonomy` level pre-authorizes, and the checkout/`workspaceMode` prep
6
6
  happen before intake.
7
7
 
8
8
 
9
- 4. **Normalize, confirm or override, then record atomically** to the **run manifest** via `run-state.mjs merge` using `recordPreflightAnswers(...).manifestPatch` — `currentTurnCapabilities`, both model slots and their explicit families (plus each non-`high` effort), `targetBranch`, and `autonomy` — then add step 3a's `deliveryMode` (+ `queueProvider` in queue mode). Read back the manifest; do not hand-roll or partially bank the answer. Cancellation yields no patch and records nothing. A resumed run inherits the completed pre-flight instead of re-prompting. Identical model ids remain `NOT INDEPENDENT`; different ids in the same explicit family remain independent but are recorded as `reduced diversity`. **`autonomy`** is one question that pre-authorizes as much of the loop's stop-and-ask surface as the human wants to spend up front, when they have the context, instead of mid-run when they don't. Two levels, and **`autonomous` is the recommended pick** present it first and marked "(Recommended)":
9
+ 4. **Normalize, confirm or override, then record atomically** to the **run manifest** via `run-state.mjs merge` using `recordPreflightAnswers(...).manifestPatch` — `currentTurnCapabilities`, both model slots and their explicit families (plus each non-`high` effort), `targetBranch`, and `autonomy` — then add step 3a's `deliveryMode` (+ `queueProvider` in queue mode). Read back the manifest; do not hand-roll or partially bank the answer. Cancellation yields no patch and records nothing. A resumed run inherits the completed pre-flight instead of re-prompting. Identical model ids remain `NOT INDEPENDENT`; different ids in the same explicit family remain independent but are recorded as `reduced diversity`. **`autonomy` is filled, not asked** — `preflight-questions.mjs` defaults it to **`autonomous`** (stated in the summary; a human may override to `supervised` without a planned question). Completing pre-flight therefore records an authorization; an *unset* field on a manifest that never ran pre-flight still resolves to supervised elsewhere. Two levels:
10
10
 
11
11
  | level | pre-authorizes | still stops and asks |
12
12
  |---|---|---|
@@ -29,7 +29,7 @@ short probes the whole run rests on.
29
29
  **Why this is step 0 rather than an assumption.** `SKILL.md`'s leaf-spawn contract requires every spawn to read `<skillsRoot>/<skill>/SKILL.md` at an absolute path, precisely because a relative `skills/engineering/...` path resolves to nothing once this skill is installed into a consumer repo by symlink — and the spawn then reconstructs a plausible-looking lookalike from memory instead of failing loudly. That contract had no step that ever produced the value: until 2026-07-20 `skillsRoot` appeared nowhere in this file, so every inline spawn's "absolute path" was aspirational and the orchestrator substituted the only path it had seen — the repo-relative one. The fan-out workflow hard-fails a relative path (`independent-review.workflow.js`); the inline path had no such guard, and the inline path is the default for single-unit runs.
30
30
 
31
31
 
32
- 3. **Detect and confirm the source (target/base) branch** in the same neutral batch. Settle it here, not at the first PR: every unit rests on this one branch — independent units open their PR against it directly, a [stacked dependent unit](intake.md#intake--scheduling) rests on it transitively, and the [epic integration gate](deliverables.md#deliverables-the-shippable-component-not-the-whole-epic) forks its integration branch off it. **Run `scripts/detect-target-branch.mjs`.** It fetches `origin` and recommends the branch that holds the current development head — applying, internally, the GitFlow-`dev`-vs-trunk-`main` choice and a *content* check (`git cherry`, not commit counts, so a GitFlow repo's nominal merge-commit divergence isn't mistaken for a conflict), and picking **nothing** on a genuine conflict. So the agent's job is only: **confirm its recommendation in this gate; on a `conflict` result, present the candidates it lists (each with ahead/behind + last-commit date) and let the human name the branch** — the script never picks on a genuine conflict, so a `conflict` always routes to the human. See `scripts/detect-target-branch.mjs --help` for flags and exit codes (`0` = recommendation, `1` = conflict/human chooses, `2` = usage / no long-lived branches). Implementer, branch, and autonomy are answered individually inside the same planned batch, never as a defaulted bundle. The reviewer slot is filled rather than asked, so every run has exactly three questions there is no worst case with four. `autonomy` remains one question precisely because it **subsumes** `mergeShippable` rather than joining it.
32
+ 3. **Detect and confirm the source (target/base) branch** in the same neutral batch. Settle it here, not at the first PR: every unit rests on this one branch — independent units open their PR against it directly, a [stacked dependent unit](intake.md#intake--scheduling) rests on it transitively, and the [epic integration gate](deliverables.md#deliverables-the-shippable-component-not-the-whole-epic) forks its integration branch off it. **Run `scripts/detect-target-branch.mjs`.** It fetches `origin` and recommends the branch that holds the current development head — applying, internally, the GitFlow-`dev`-vs-trunk-`main` choice and a *content* check (`git cherry`, not commit counts, so a GitFlow repo's nominal merge-commit divergence isn't mistaken for a conflict), and picking **nothing** on a genuine conflict. So the agent's job is only: **confirm its recommendation in this gate; on a `conflict` result, present the candidates it lists (each with ahead/behind + last-commit date) and let the human name the branch** — the script never picks on a genuine conflict, so a `conflict` always routes to the human. See `scripts/detect-target-branch.mjs --help` for flags and exit codes (`0` = recommendation, `1` = conflict/human chooses, `2` = usage / no long-lived branches). Implementer and branch are answered in the planned batch. The **reviewer** and **`autonomy`** slots are **filled rather than asked** reviewer from the ranking / team default; autonomy defaults to `autonomous` (subsumes `mergeShippable`) and is stated in the summary, overridable to `supervised`. Every run therefore has exactly **two** questions there is no worst case with three or four.
33
33
 
34
34
  3a. **Probe the merge path — `scripts/detect-delivery-mode.mjs` — and record what it answers.** This is a **probe, not a fourth ask**: it costs no question budget and does not touch the one-interruption property step 3 just described. It settles two fields, because a queue is two different things: **`deliveryMode`** (`direct` | `queue`) picks the state machine that delivers a merge-ready unit, and **`queueProvider`** (`mergify` | `github`) picks the mechanics — the enqueue command, where queue state is read, what a dequeue reason is called, whether a re-evaluation nudge or an acknowledgement exists at all. Both fail silently in both directions when wrong, which is why they are probed rather than assumed and why the probe fails closed: **exit 2 is UNDETERMINED** — no probe could run, only file probes ran and were negative, or a queue whose provider is unknown/ambiguous — and *that* is the one case that becomes a human question, an exception path rather than a standing ask. A queue is a **runtime** fact whose config commonly lives dashboard-side, so never read either field off repo files.
35
35
 
@@ -118,12 +118,16 @@ export function planPreflightQuestions(value) {
118
118
  const implementation = defineChoiceSet(value.implementation, 'implementation')
119
119
  const target = defineChoiceSet(value.target, 'target branch')
120
120
  const review = defineReviewRanking(value.review, 'review')
121
+ // Autonomy is FILLED, not asked — same shape as the reviewer slot. Completing
122
+ // pre-flight records `autonomous` (and therefore mergeShippable-on) unless the
123
+ // human overrides in the answer batch or prompt. An unset field on a manifest
124
+ // that never ran pre-flight still resolves to supervised elsewhere; this fill
125
+ // is what makes a completed pre-flight a recorded authorization.
121
126
  const autonomy = Object.freeze({ recommended: 'autonomous', options: AUTONOMY_OPTIONS })
122
127
 
123
128
  const questions = [
124
129
  question('implementation', 'Implement', 'Which model should implement every unit in this run?', implementation),
125
130
  question('target_branch', 'Target', 'Which fetched remote branch should every unit target?', target),
126
- question('autonomy', 'Autonomy', 'How much reversible run activity should pre-flight authorize?', autonomy),
127
131
  ]
128
132
  const interaction = planStructuredQuestions(capabilities, questions)
129
133
  const metadata = Object.freeze(Object.fromEntries([
@@ -135,9 +139,11 @@ export function planPreflightQuestions(value) {
135
139
  capabilities,
136
140
  questions: Object.freeze(questions),
137
141
  interaction,
138
- // The top of the ranking, i.e. the fill unless the answered implementer
139
- // collides with it; `record` resolves the final id and reports why.
140
- defaulted: Object.freeze({ review: review.candidates[0].id }),
142
+ // Filled slots stated in the pre-flight summary; `record` may honour overrides.
143
+ defaulted: Object.freeze({
144
+ review: review.candidates[0].id,
145
+ autonomy: autonomy.recommended,
146
+ }),
141
147
  reviewRanking: Object.freeze(review.candidates.map((option) => option.id)),
142
148
  freeTextQuestions: Object.freeze(interaction.kind === 'fallback'
143
149
  ? questions.map(({ id, prompt }) => Object.freeze({ questionId: id, prompt }))
@@ -226,13 +232,19 @@ export function recordPreflightAnswers(session, answerValue, { allowHumanNamed =
226
232
  if (!isRecord(session) || !isRecord(session.selections)) invalid('question session is malformed')
227
233
  const answers = defineQuestionAnswers(answerValue)
228
234
  if (Object.keys(answers).length === 0) {
229
- return Object.freeze({ cancelled: true, manifestPatch: null, diversity: null, reviewFill: null })
235
+ return Object.freeze({
236
+ cancelled: true,
237
+ manifestPatch: null,
238
+ diversity: null,
239
+ reviewFill: null,
240
+ autonomyFill: null,
241
+ })
230
242
  }
231
243
 
232
244
  const expectedIds = session.questions.map((item) => item.id)
233
- // `review` is never a planned question, but a human who named the reviewer
245
+ // `review` and `autonomy` are never planned questions; a human who names either
234
246
  // outright is honoured as an override rather than bounced.
235
- const acceptedIds = [...expectedIds, 'review']
247
+ const acceptedIds = [...expectedIds, 'review', 'autonomy']
236
248
  if (expectedIds.some((id) => !Object.hasOwn(answers, id))
237
249
  || Object.keys(answers).some((id) => !acceptedIds.includes(id))) {
238
250
  invalid('answers must complete exactly the planned question batch')
@@ -250,8 +262,18 @@ export function recordPreflightAnswers(session, answerValue, { allowHumanNamed =
250
262
 
251
263
  const targetId = singleAnswer(answers, 'target_branch')
252
264
  selectedOption(session.selections.target, targetId, { allowCustom: customAllowed })
253
- const autonomy = singleAnswer(answers, 'autonomy')
254
- selectedOption(session.selections.autonomy, autonomy)
265
+
266
+ let autonomy
267
+ let autonomyFill
268
+ if (Object.hasOwn(answers, 'autonomy')) {
269
+ autonomy = singleAnswer(answers, 'autonomy')
270
+ selectedOption(session.selections.autonomy, autonomy)
271
+ autonomyFill = Object.freeze({ id: autonomy, reason: 'human-named' })
272
+ } else {
273
+ autonomy = session.defaulted?.autonomy || session.selections.autonomy.recommended
274
+ selectedOption(session.selections.autonomy, autonomy)
275
+ autonomyFill = Object.freeze({ id: autonomy, reason: 'default' })
276
+ }
255
277
 
256
278
  const models = {}
257
279
  modelPoint(models, 'implementation', implementation)
@@ -267,6 +289,7 @@ export function recordPreflightAnswers(session, answerValue, { allowHumanNamed =
267
289
  }),
268
290
  diversity,
269
291
  reviewFill: Object.freeze({ id: review.id, reason: reviewFill.reason }),
292
+ autonomyFill,
270
293
  })
271
294
  }
272
295
 
@@ -3412,7 +3412,7 @@ export const WORKFLOW_PREFLIGHT_COMMANDS = Object.freeze([
3412
3412
 
3413
3413
  const WORKFLOW_VERIFIER_URL = new URL('../../engineering-runtime/scripts/workflow-coherence.mjs', import.meta.url)
3414
3414
  const WORKFLOW_FALLBACK_POLICY_URL = new URL('../generated/workflow-repair-policy.json', import.meta.url)
3415
- export const WORKFLOW_TRUSTED_FALLBACK_POLICY_SHA256 = 'b8b3b30d3509ec8c74c4d42b88e53a5958fc17e0066fc18b07fa4b9cd7eb343a'
3415
+ export const WORKFLOW_TRUSTED_FALLBACK_POLICY_SHA256 = 'c6bde1d0b0e4c2bca363e396c5f0d1892996aa61e0531ae188626ebc6c971f3f'
3416
3416
  const WORKFLOW_REPAIR_RECIPE_REFERENCE = Object.freeze({
3417
3417
  id: 'engineering-workflow-dependency-first',
3418
3418
  generatedFrom: 'skills/distribution/generated/recipes.json',
@@ -10,7 +10,8 @@ the human has confirmed this block. Indexed from
10
10
  node <resolve-release>/scripts/preflight-probes.mjs check \
11
11
  --repo <owner/name> --target-branch <prod-branch> \
12
12
  --exposure-gate-probe '<the repo own check that its exposure profile can produce a verdict>' \
13
- --topology-probe '<read-only command emitting the Cloud Build TAG_NAME substitution record>' \
13
+ [--topology-probe '<read-only command emitting the Cloud Build TAG_NAME substitution record>' | \
14
+ --deploy-trigger no-deploy] \
14
15
  [--smoke-manifest <smoke.manifest.json> --smoke-secrets-command '<optional per-secret dry-fetch>'] \
15
16
  [--gate '<a check-run that must be present and green on the target head>']
16
17
  ```
@@ -26,7 +27,7 @@ Exit **0** ready, **1** not ready (each probe naming its own remedy), **2** usag
26
27
  | `rc-tag-topology` | The actual production path was a `TAG_NAME` Cloud Build trigger, while `_DEPLOYED_VERSION` had only been passed through a controller-submitted `gcloud builds submit`. The read-only command emits one representative RC record: `prodBuildTrigger`, `versionSource`, `candidateTagSource`, and `substitutions.TAG_NAME` / `_DEPLOYED_VERSION` / `_CANDIDATE_TAG`. It passes only for `tag-trigger` / `TAG_NAME` / `TAG_NAME`, with the final SemVer and RC candidate tag both derived from the RC `TAG_NAME`. |
27
28
  | `smoke-secrets` *(optional)* | A smoke secret env var held the resource-name string instead of the secret value, so 4a would have returned `CANNOT-RUN` after the candidate was built. Caught before the rc tag when the exposure executor is this skill (#823). |
28
29
 
29
- **`unknown` is not `ok`, and an absent `--exposure-gate-probe` or `--topology-probe` is `unknown`.** An unasked readiness question is [principle 13](principles.md#non-negotiable-principles)'s shape — an applicable gate that cannot run is a failure, not an absence — so a probe that was never supplied blocks the attempt exactly as a failing one does. A repo that never answers cannot silently release on the weaker path, which is the same rule item 3 applies to the candidate identity legs.
30
+ **`unknown` is not `ok`, and an absent `--exposure-gate-probe` or applicable `--topology-probe` is `unknown`.** An unasked readiness question is [principle 13](principles.md#non-negotiable-principles)'s shape — an applicable gate that cannot run is a failure, not an absence — so a probe that was never supplied blocks the attempt exactly as a failing one does. A repo that never answers cannot silently release on the weaker path, which is the same rule item 3 applies to the candidate identity legs. The explicit `--deploy-trigger no-deploy` shape is the sole exception to the RC topology read: it records `rc-tag-topology` as decided non-applicable because that shape mints no RC. Omitting the shape does not infer `no-deploy`, and supplying it does not waive credential, tag-divergence, target-gate, or exposure-capability probes.
30
31
 
31
32
  **The topology probe is a pre-RC artifact, not a controller convenience.** Persist `preflight-probes.mjs check --json` and pass that file to `version.mjs rc --topology-probe <file>`; the mint refuses unless the artifact is ready and carries exactly `prodBuildTrigger: "tag-trigger"`, `versionSource: "TAG_NAME"`, and `candidateTagSource: "TAG_NAME"`. A controller-submitted build may pass `_DEPLOYED_VERSION`, but that does not prove a tag-triggered production build receives it. Likewise, a dev image keyed only by source SHA is informational: it does not satisfy candidate evidence before the RC tag/build/revision/tag binding exists.
32
33
 
@@ -167,7 +167,15 @@ export function classifyTargetGate({ checks, readable = true, gates = [] } = {})
167
167
  // for this evidence.
168
168
  const RC_TAG_RE = /^v?(\d+\.\d+\.\d+)-rc\.[1-9]\d*$/
169
169
 
170
- export function classifyTagTopology({ topology = null, readable = true } = {}) {
170
+ export function classifyTagTopology({ topology = null, readable = true, deployTrigger = null } = {}) {
171
+ if (deployTrigger === 'no-deploy') {
172
+ return {
173
+ ...probe('rc-tag-topology', PROBE_STATES.OK,
174
+ 'no RC tag is minted for the explicitly declared no-deploy release shape'),
175
+ applicable: false,
176
+ deployTrigger,
177
+ }
178
+ }
171
179
  if (!readable || topology == null || typeof topology !== 'object' || Array.isArray(topology)) {
172
180
  return probe('rc-tag-topology', PROBE_STATES.UNKNOWN,
173
181
  'the production build topology could not be read as a Cloud Build substitution record',
@@ -329,6 +337,7 @@ export function parseArgs(argv) {
329
337
  if (a === '--repo') args.repo = argv[++i]
330
338
  else if (a === '--target-branch') args.targetBranch = argv[++i]
331
339
  else if (a === '--credential-command') args.credentialCommand = argv[++i]
340
+ else if (a === '--deploy-trigger') args.deployTrigger = argv[++i]
332
341
  else if (a === '--exposure-gate-probe') args.exposureGateProbe = argv[++i]
333
342
  else if (a === '--topology-probe') args.topologyProbe = argv[++i]
334
343
  else if (a === '--smoke-manifest') args.smokeManifest = argv[++i]
@@ -371,6 +380,8 @@ a candidate is built (#823).
371
380
 
372
381
  Options:
373
382
  --credential-command <cmd> liveness check, default: ${DEFAULT_CREDENTIAL_COMMAND}
383
+ --deploy-trigger <shape> explicit release shape. no-deploy records RC topology as decided
384
+ not-applicable; omitting it retains the fail-closed RC topology read.
374
385
  --exposure-gate-probe <cmd> the repo's own check that its exposure profile can produce a
375
386
  verdict. ABSENT is "unknown", which is NOT ready.
376
387
  --topology-probe <cmd> read-only repository command that prints JSON for one representative
@@ -434,6 +445,7 @@ export async function runCli(argv) {
434
445
  probes.push(classifyTagTopology({
435
446
  topology: topologyRead.ok ? safeJson(topologyRead.stdout) : null,
436
447
  readable: Boolean(args.topologyProbe) && topologyRead.ok,
448
+ deployTrigger: args.deployTrigger || null,
437
449
  }))
438
450
 
439
451
  const exposure = args.exposureGateProbe ? sh(args.exposureGateProbe, 300_000) : {}
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  name: review-pr
3
- description: "Adversarially review a pull request before merge verify claimed coverage and behavior against the code, optionally post to GitHub; ends in PASS / NEEDS_CHANGES / FAIL / BLOCKED with inline findings. Two modes: with a spec (Review Contract, ACs, PRD, test criteria) it also verifies spec compliance against every acceptance criterion; with no spec it reviews the code, its tests, and any coverage baseline the repo wires, and never blocks on the missing paperwork. Not code-review (working-tree diff), review (standards/spec summary), or ensure-coverage (coverage doctrine)."
3
+ description: "Slash-command only (/review-pr). Adversarial pre-merge PR review PASS / NEEDS_CHANGES / FAIL / BLOCKED with inline findings (spec'd or code-only). Do not auto-select only on explicit user/orchestrator invoke. Not code-review (working-tree Standards∥Spec), and not ensure-coverage."
4
+ disable-model-invocation: true
4
5
  dependencies:
5
6
  - ensure-coverage
6
7
  - e2e-test
@@ -0,0 +1,9 @@
1
+ interface:
2
+ display_name: "Review PR"
3
+ short_description: "Slash/explicit-only adversarial pre-merge PR review"
4
+
5
+ policy:
6
+ # Codex counterpart to SKILL.md disable-model-invocation: true
7
+ # (Claude Code / Pi). Keeps $review-pr / explicit invoke; blocks
8
+ # description-based auto-selection.
9
+ allow_implicit_invocation: false