@1aboveio/skills 1.0.7 → 1.0.9
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/.codex-plugin/plugin.json +13 -0
- package/.codex-plugin/resources.json +1827 -0
- package/README.md +22 -0
- package/package.json +9 -2
- package/skills/app-dev/airflow/SKILL.md +1 -1
- package/skills/app-dev/airflow/release-check.mjs +3 -1
- package/skills/app-dev/android-foundation/SKILL.md +92 -34
- package/skills/app-dev/android-foundation/assets/android-ci-job.yml +13 -7
- package/skills/app-dev/android-foundation/references/ci.md +23 -13
- package/skills/app-dev/android-foundation/references/delivery-focus.md +29 -0
- package/skills/app-dev/android-foundation/references/diagnosis.md +136 -0
- package/skills/app-dev/android-foundation/references/gotchas.md +20 -11
- package/skills/app-dev/android-foundation/references/setup.md +15 -6
- package/skills/app-dev/android-foundation/release-check.mjs +3 -1
- package/skills/app-dev/android-foundation/scripts/device-run.sh +148 -42
- package/skills/app-dev/app-debug/SKILL.md +1 -1
- package/skills/app-dev/app-debug/release-check.mjs +3 -1
- package/skills/app-dev/better-auth/SKILL.md +1 -1
- package/skills/app-dev/better-auth/release-check.mjs +3 -1
- package/skills/app-dev/data-catalog/SKILL.md +1 -1
- package/skills/app-dev/data-catalog/release-check.mjs +3 -1
- package/skills/app-dev/data-quality/SKILL.md +1 -1
- package/skills/app-dev/data-quality/release-check.mjs +3 -1
- package/skills/app-dev/ios-foundation/SKILL.md +1 -1
- package/skills/app-dev/ios-foundation/release-check.mjs +3 -1
- package/skills/app-dev/monorepo/SKILL.md +1 -1
- package/skills/app-dev/monorepo/release-check.mjs +3 -1
- package/skills/app-dev/nextjs-fullstack/SKILL.md +1 -1
- package/skills/app-dev/nextjs-fullstack/release-check.mjs +3 -1
- package/skills/app-dev/prisma-setup/SKILL.md +1 -1
- package/skills/app-dev/prisma-setup/release-check.mjs +3 -1
- package/skills/app-dev/pyspark/SKILL.md +1 -1
- package/skills/app-dev/pyspark/release-check.mjs +3 -1
- package/skills/app-dev/python-backend/SKILL.md +1 -1
- package/skills/app-dev/python-backend/release-check.mjs +3 -1
- package/skills/app-dev/shadcn/SKILL.md +1 -1
- package/skills/app-dev/shadcn/release-check.mjs +3 -1
- package/skills/app-dev/zod-v4/SKILL.md +1 -1
- package/skills/app-dev/zod-v4/release-check.mjs +3 -1
- package/skills/cicd/cloud-build/SKILL.md +1 -1
- package/skills/cicd/cloud-build/release-check.mjs +3 -1
- package/skills/cicd/cloud-debug/SKILL.md +1 -1
- package/skills/cicd/cloud-debug/release-check.mjs +3 -1
- package/skills/cicd/cloud-deploy/SKILL.md +1 -1
- package/skills/cicd/cloud-deploy/release-check.mjs +3 -1
- package/skills/cicd/docker/SKILL.md +1 -1
- package/skills/cicd/docker/release-check.mjs +3 -1
- package/skills/cicd/github-actions/SKILL.md +1 -1
- package/skills/cicd/github-actions/release-check.mjs +3 -1
- package/skills/cicd/github-flow/SKILL.md +1 -1
- package/skills/cicd/github-flow/release-check.mjs +3 -1
- package/skills/cicd/google-cloud/SKILL.md +1 -1
- package/skills/cicd/google-cloud/release-check.mjs +3 -1
- package/skills/cicd/mergify/SKILL.md +1 -1
- package/skills/cicd/mergify/release-check.mjs +3 -1
- package/skills/cicd/podman/SKILL.md +1 -1
- package/skills/cicd/podman/release-check.mjs +3 -1
- package/skills/content/article-review/SKILL.md +1 -1
- package/skills/content/article-review/release-check.mjs +3 -1
- package/skills/content/article-to-image/SKILL.md +1 -1
- package/skills/content/article-to-image/release-check.mjs +3 -1
- package/skills/content/flowchart-svg/SKILL.md +1 -1
- package/skills/content/flowchart-svg/release-check.mjs +3 -1
- package/skills/content/image-gen/SKILL.md +1 -1
- package/skills/content/image-gen/release-check.mjs +3 -1
- package/skills/content/mermaid/SKILL.md +1 -1
- package/skills/content/mermaid/release-check.mjs +3 -1
- package/skills/content/wechat-article-writer/SKILL.md +1 -1
- package/skills/content/wechat-article-writer/release-check.mjs +3 -1
- package/skills/content/wechat-publisher/SKILL.md +1 -1
- package/skills/content/wechat-publisher/release-check.mjs +3 -1
- package/skills/content/wechat-search/SKILL.md +1 -1
- package/skills/content/wechat-search/release-check.mjs +3 -1
- package/skills/content/xai-search/SKILL.md +88 -13
- package/skills/content/xai-search/release-check.mjs +3 -1
- package/skills/content/xai-search/scripts/xai_search.sh +125 -149
- package/skills/core/distill-writing/SKILL.md +1 -1
- package/skills/core/distill-writing/release-check.mjs +3 -1
- package/skills/core/doc-to-md/SKILL.md +1 -1
- package/skills/core/doc-to-md/release-check.mjs +3 -1
- package/skills/core/editorial-review/SKILL.md +1 -1
- package/skills/core/editorial-review/release-check.mjs +3 -1
- package/skills/core/house-style/SKILL.md +1 -1
- package/skills/core/house-style/release-check.mjs +3 -1
- package/skills/core/plain-language/SKILL.md +1 -1
- package/skills/core/plain-language/release-check.mjs +3 -1
- package/skills/core/polish-cn/SKILL.md +1 -1
- package/skills/core/polish-cn/release-check.mjs +3 -1
- package/skills/core/reg-parser/SKILL.md +1 -1
- package/skills/core/reg-parser/release-check.mjs +3 -1
- package/skills/core/terminology/SKILL.md +1 -1
- package/skills/core/terminology/release-check.mjs +3 -1
- package/skills/core/write-doc/SKILL.md +1 -1
- package/skills/core/write-doc/release-check.mjs +3 -1
- package/skills/engineering/better-review/SKILL.md +1 -1
- package/skills/engineering/better-review/release-check.mjs +3 -1
- package/skills/engineering/contributing/SKILL.md +1 -1
- package/skills/engineering/contributing/release-check.mjs +3 -1
- package/skills/engineering/e2e-test/SKILL.md +1 -1
- package/skills/engineering/e2e-test/release-check.mjs +3 -1
- package/skills/engineering/engineering-runtime/SKILL.md +1 -1
- package/skills/engineering/engineering-runtime/coherence/workflow.json +13 -13
- package/skills/engineering/engineering-runtime/release-check.mjs +3 -1
- package/skills/engineering/engineering-runtime/scripts/installation-resolver.mjs +191 -0
- package/skills/engineering/engineering-runtime/scripts/workflow-coherence.mjs +51 -10
- package/skills/engineering/ensure-coverage/SKILL.md +1 -1
- package/skills/engineering/ensure-coverage/release-check.mjs +3 -1
- package/skills/engineering/golden-path/SKILL.md +1 -1
- package/skills/engineering/golden-path/release-check.mjs +3 -1
- package/skills/engineering/harness-runtime/SKILL.md +1 -1
- package/skills/engineering/harness-runtime/release-check.mjs +3 -1
- package/skills/engineering/resolve-issues/SKILL.md +11 -20
- package/skills/engineering/resolve-issues/references/delivery-progress.md +63 -0
- package/skills/engineering/resolve-issues/references/expire.md +24 -11
- package/skills/engineering/resolve-issues/references/implementation.md +9 -1
- package/skills/engineering/resolve-issues/references/preflight.md +7 -0
- package/skills/engineering/resolve-issues/references/shared-modules.md +27 -0
- package/skills/engineering/resolve-issues/references/task-plan.md +12 -5
- package/skills/engineering/resolve-issues/release-check.mjs +3 -1
- package/skills/engineering/resolve-issues/scripts/active-installation.mjs +32 -0
- package/skills/engineering/resolve-issues/scripts/install-hooks.mjs +3 -0
- package/skills/engineering/resolve-issues/scripts/rehydrate.mjs +17 -1
- package/skills/engineering/resolve-release/SKILL.md +1 -1
- package/skills/engineering/resolve-release/release-check.mjs +3 -1
- package/skills/engineering/rush-issues/SKILL.md +5 -2
- package/skills/engineering/rush-issues/release-check.mjs +3 -1
- package/skills/engineering/rush-release/SKILL.md +1 -1
- package/skills/engineering/rush-release/release-check.mjs +3 -1
- package/skills/engineering/test-quality/SKILL.md +1 -1
- package/skills/engineering/test-quality/release-check.mjs +3 -1
- package/skills/risk-compliance/compliance-audit/SKILL.md +1 -1
- package/skills/risk-compliance/compliance-audit/release-check.mjs +3 -1
- package/skills/risk-compliance/contract-compare/SKILL.md +1 -1
- package/skills/risk-compliance/contract-compare/release-check.mjs +3 -1
- package/skills/risk-compliance/contract-review/SKILL.md +1 -1
- package/skills/risk-compliance/contract-review/release-check.mjs +3 -1
- package/skills/risk-compliance/doc-authenticity/SKILL.md +1 -1
- package/skills/risk-compliance/doc-authenticity/release-check.mjs +3 -1
- package/skills/risk-compliance/fraud-analysis/SKILL.md +1 -1
- package/skills/risk-compliance/fraud-analysis/release-check.mjs +3 -1
- package/skills/risk-compliance/payment-analysis/SKILL.md +1 -1
- package/skills/risk-compliance/payment-analysis/release-check.mjs +3 -1
- package/skills/risk-compliance/similar-domain/SKILL.md +1 -1
- package/skills/risk-compliance/similar-domain/release-check.mjs +3 -1
- package/skills/risk-compliance/tld-detection/SKILL.md +1 -1
- package/skills/risk-compliance/tld-detection/release-check.mjs +3 -1
- package/skills/app-dev/android-foundation/scripts/device-run.test.mjs +0 -172
- package/skills/app-dev/data-catalog/scripts/data-catalog.test.mjs +0 -36
- package/skills/app-dev/data-quality/scripts/data-quality.test.mjs +0 -12
- package/skills/cicd/github-actions/scripts/ci-run-audit.test.mjs +0 -637
- package/skills/cicd/github-flow/scripts/flow.test.mjs +0 -114
- package/skills/cicd/github-flow/scripts/persist-conventions.test.mjs +0 -108
- package/skills/cicd/mergify/scripts/audit.test.mjs +0 -201
- package/skills/cicd/mergify/scripts/entrypoints.test.mjs +0 -106
- package/skills/cicd/mergify/scripts/pr-620-mergify-comments.fixture.json +0 -30
- package/skills/cicd/mergify/scripts/stack-push.test.mjs +0 -233
- package/skills/cicd/mergify/scripts/watch-pr-delivery.test.mjs +0 -1826
- package/skills/content/image-gen/scripts/credentials.test.mjs +0 -212
- package/skills/content/image-gen/scripts/options.test.mjs +0 -245
- package/skills/content/xai-search/tests/smoke_test.sh +0 -36
- package/skills/core/polish-cn/scripts/polish-cn.test.mjs +0 -244
- package/skills/core/reg-parser/scripts/reg-parser.test.mjs +0 -165
- package/skills/engineering/better-review/scripts/pr-context.test.mjs +0 -168
- package/skills/engineering/better-review/scripts/rereview-scope.test.mjs +0 -587
- package/skills/engineering/better-review/scripts/scan-diff.test.mjs +0 -414
- package/skills/engineering/better-review/scripts/vendor-sync.test.mjs +0 -96
- package/skills/engineering/contributing/scripts/persist-conventions.test.mjs +0 -118
- package/skills/engineering/e2e-test/scripts/presentation-checks.test.mjs +0 -106
- package/skills/engineering/e2e-test/scripts/presentation-perceivability.test.mjs +0 -117
- package/skills/engineering/e2e-test/scripts/presentation-reachability.test.mjs +0 -69
- package/skills/engineering/e2e-test/scripts/presentation-render-health.test.mjs +0 -98
- package/skills/engineering/e2e-test/scripts/presentation-sweep.test.mjs +0 -71
- package/skills/engineering/e2e-test/scripts/presentation-temporal.test.mjs +0 -59
- package/skills/engineering/e2e-test/scripts/project-route-manifest.test.mjs +0 -76
- package/skills/engineering/engineering-runtime/engineering-runtime.test.mjs +0 -68
- package/skills/engineering/engineering-runtime/scripts/invocation-policy.test.mjs +0 -95
- package/skills/engineering/engineering-runtime/scripts/main-module.test.mjs +0 -288
- package/skills/engineering/engineering-runtime/scripts/required-check-plan.test.mjs +0 -96
- package/skills/engineering/ensure-coverage/scripts/adapters/nextjs-inventory.test.mjs +0 -96
- package/skills/engineering/ensure-coverage/scripts/check-quarantine-expiry.test.mjs +0 -47
- package/skills/engineering/ensure-coverage/scripts/ci-audit.test.mjs +0 -86
- package/skills/engineering/ensure-coverage/scripts/coverage-ledger.test.mjs +0 -447
- package/skills/engineering/ensure-coverage/scripts/design-parity.test.mjs +0 -552
- package/skills/engineering/ensure-coverage/scripts/lint-tests.test.mjs +0 -289
- package/skills/engineering/ensure-coverage/scripts/mock-policy-config.test.mjs +0 -119
- package/skills/engineering/golden-path/scripts/golden-path.test.mjs +0 -1457
- package/skills/engineering/harness-runtime/discover-models.test.mjs +0 -363
- package/skills/engineering/harness-runtime/harness-runtime.test.mjs +0 -967
- package/skills/engineering/harness-runtime/model-catalog-seed.test.mjs +0 -829
- package/skills/engineering/harness-runtime/model-catalog.test.mjs +0 -366
- package/skills/engineering/resolve-issues/scripts/cleanup-runs.test.mjs +0 -280
- package/skills/engineering/resolve-issues/scripts/dropbox.test.mjs +0 -346
- package/skills/engineering/resolve-issues/scripts/findings-reuse.test.mjs +0 -88
- package/skills/engineering/resolve-issues/scripts/github-reviews.test.mjs +0 -264
- package/skills/engineering/resolve-issues/scripts/install-hooks.test.mjs +0 -79
- package/skills/engineering/resolve-issues/scripts/issue-tree.test.mjs +0 -107
- package/skills/engineering/resolve-issues/scripts/manual-invocation.test.mjs +0 -14
- package/skills/engineering/resolve-issues/scripts/next-actions-capacity.test.mjs +0 -149
- package/skills/engineering/resolve-issues/scripts/next-actions.test.mjs +0 -915
- package/skills/engineering/resolve-issues/scripts/plan-sync.test.mjs +0 -156
- package/skills/engineering/resolve-issues/scripts/preflight-models.test.mjs +0 -448
- package/skills/engineering/resolve-issues/scripts/ready-check.test.mjs +0 -217
- package/skills/engineering/resolve-issues/scripts/rehydrate.test.mjs +0 -91
- package/skills/engineering/resolve-issues/scripts/review-verdict.test.mjs +0 -1060
- package/skills/engineering/resolve-issues/scripts/size-check.test.mjs +0 -458
- package/skills/engineering/resolve-release/scripts/apply.test.mjs +0 -99
- package/skills/engineering/resolve-release/scripts/dark-flags.test.mjs +0 -100
- package/skills/engineering/resolve-release/scripts/flow.test.mjs +0 -340
- package/skills/engineering/resolve-release/scripts/green-head.test.mjs +0 -101
- package/skills/engineering/resolve-release/scripts/npm-version-absence.test.mjs +0 -426
- package/skills/engineering/resolve-release/scripts/plan-npm.test.mjs +0 -659
- package/skills/engineering/resolve-release/scripts/plan-toml-boundary.test.mjs +0 -317
- package/skills/engineering/resolve-release/scripts/plan-uv.test.mjs +0 -291
- package/skills/engineering/resolve-release/scripts/plan.test.mjs +0 -428
- package/skills/engineering/test-quality/scripts/lint-tests.test.mjs +0 -591
- package/skills/engineering/test-quality/scripts/mock-policy-config.test.mjs +0 -119
- package/skills/engineering/test-quality/scripts/persist-conventions.test.mjs +0 -104
- package/skills/risk-compliance/compliance-audit/scripts/compliance-audit.test.mjs +0 -14
- package/skills/risk-compliance/doc-authenticity/manual-invocation.test.mjs +0 -12
- package/skills/risk-compliance/doc-authenticity/scripts/validate_verdict.test.mjs +0 -212
- package/skills/risk-compliance/tld-detection/scripts/detect_ladders.test.mjs +0 -14
- package/skills/risk-compliance/tld-detection/scripts/detect_streams.test.mjs +0 -14
- package/skills/risk-compliance/tld-detection/tests/test_detect_ladders.py +0 -134
- package/skills/risk-compliance/tld-detection/tests/test_detect_streams.py +0 -520
|
@@ -1,156 +0,0 @@
|
|
|
1
|
-
import { test } from 'node:test'
|
|
2
|
-
import assert from 'node:assert/strict'
|
|
3
|
-
import { spawnSync } from 'node:child_process'
|
|
4
|
-
import { mkdirSync, mkdtempSync, readFileSync, utimesSync, writeFileSync } from 'node:fs'
|
|
5
|
-
import { tmpdir } from 'node:os'
|
|
6
|
-
import { dirname, join } from 'node:path'
|
|
7
|
-
import { fileURLToPath } from 'node:url'
|
|
8
|
-
|
|
9
|
-
import { SNAPSHOT, classify, findRun, parseCliArgs, PlanSyncError, planSync, syncRun } from './plan-sync.mjs'
|
|
10
|
-
|
|
11
|
-
const script = join(dirname(fileURLToPath(import.meta.url)), 'plan-sync.mjs')
|
|
12
|
-
|
|
13
|
-
// A tree in issue-tree.mjs's shape from { "n": { state, children: [n], blockedBy: [n] } } in o/r.
|
|
14
|
-
function tree(spec, issues, { complete = true } = {}) {
|
|
15
|
-
const nodes = {}
|
|
16
|
-
const key = (n) => (String(n).includes('#') ? String(n) : `o/r#${n}`)
|
|
17
|
-
for (const [n, i] of Object.entries(issues)) {
|
|
18
|
-
nodes[key(n)] = { key: key(n), repo: 'o/r', number: Number(n), title: `t${n}`, state: i.state ?? 'open', labels: [], blockedBy: (i.blockedBy ?? []).map((b) => ({ key: key(b), state: issues[b]?.state ?? i.blockerState ?? 'open' })), children: (i.children ?? []).map(key), parent: null }
|
|
19
|
-
}
|
|
20
|
-
for (const node of Object.values(nodes)) for (const c of node.children) if (nodes[c]) nodes[c].parent = node.key
|
|
21
|
-
return { root: key(spec), complete, errors: complete ? [] : [{ key: key(spec), error: 'HTTP 502' }], nodes }
|
|
22
|
-
}
|
|
23
|
-
const plan = (units, extra = {}) => ({ spec: 'o/r#1', units, ...extra })
|
|
24
|
-
const actionsOf = (result) => result.actions.map((a) => `${a.action} ${a.unit}`)
|
|
25
|
-
|
|
26
|
-
test('a held issue whose filed prerequisite closed stays a unit, and a new open issue is added', () => {
|
|
27
|
-
// fmm #1343: its prerequisite #1659 was filed under it and closed; the old check dropped #1343.
|
|
28
|
-
const t = tree(1, { 1: { children: [1343, 1142, 1700] }, 1343: { children: [1659] }, 1659: { state: 'closed' }, 1142: { blockedBy: [1343] }, 1700: {} })
|
|
29
|
-
assert.equal(classify(t)['o/r#1343'], 'unit')
|
|
30
|
-
const result = planSync(plan([{ id: '1343', status: 'blocked' }, { id: '1142', status: 'pending', dependsOn: ['1343'] }]), t)
|
|
31
|
-
assert.deepEqual(actionsOf(result), ['add-unit 1700'])
|
|
32
|
-
})
|
|
33
|
-
|
|
34
|
-
test('add-unit carries blockedBy, expanding a blocking container into its open leaves', () => {
|
|
35
|
-
const t = tree(1, { 1: { children: [2, 5] }, 2: { children: [3, 4] }, 3: {}, 4: { state: 'closed' }, 5: { blockedBy: [2] } })
|
|
36
|
-
const result = planSync(plan([{ id: '3', status: 'pending' }]), t)
|
|
37
|
-
assert.deepEqual(result.actions.map((a) => [a.action, a.unit, a.dependsOn]), [['add-unit', '5', ['3']]])
|
|
38
|
-
})
|
|
39
|
-
|
|
40
|
-
test('a container\'s link is never inherited: move-link asks for it on the sub-issues that wait', () => {
|
|
41
|
-
// A link on a split issue fanned out to all five of its slices, though two used the blocker.
|
|
42
|
-
const t = tree(1, { 1: { children: [2, 9] }, 2: { children: [3, 4], blockedBy: [9] }, 3: {}, 4: {}, 9: {} })
|
|
43
|
-
const result = planSync(plan([{ id: '3', status: 'pending', dependsOn: ['7'] }, { id: '4', status: 'pending' }, { id: '9', status: 'pending' }]), t)
|
|
44
|
-
assert.deepEqual(result.actions.map((a) => [a.action, a.unit]), [['move-link', '2']])
|
|
45
|
-
assert.match(result.actions[0].detail, /o\/r#2 has 2 open sub-issues \(3, 4\) and is blocked by o\/r#9/)
|
|
46
|
-
const moved = tree(1, { 1: { children: [2, 9] }, 2: { children: [3, 4] }, 3: { blockedBy: [9] }, 4: {}, 9: {} })
|
|
47
|
-
const after = planSync(plan([{ id: '3', status: 'pending', dependsOn: ['7'] }, { id: '4', status: 'pending' }, { id: '9', status: 'pending' }]), moved)
|
|
48
|
-
assert.deepEqual(after.actions.map((a) => [a.action, a.unit, a.dependsOn]), [['set-deps', '3', ['7', '9']]], 'only the linked sub-issue waits; set-deps keeps the explorer-recorded 7')
|
|
49
|
-
const done = tree(1, { 1: { children: [2, 9] }, 2: { children: [3], blockedBy: [9] }, 3: {}, 9: { state: 'closed' } })
|
|
50
|
-
assert.deepEqual(planSync(plan([{ id: '3', status: 'pending' }]), done).actions, [], 'a closed blocker needs no move')
|
|
51
|
-
})
|
|
52
|
-
|
|
53
|
-
test('closed, split, and moved-out issues drop their units; done units are left alone', () => {
|
|
54
|
-
const t = tree(1, { 1: { children: [2, 3, 5] }, 2: { state: 'closed' }, 3: { children: [4] }, 4: {}, 5: { state: 'closed' } })
|
|
55
|
-
const result = planSync(plan([
|
|
56
|
-
{ id: '2', status: 'in-flight' }, { id: '3', status: 'pending' }, { id: '4', status: 'pending' },
|
|
57
|
-
{ id: '5', status: 'succeeded' }, { id: '8', status: 'pending' },
|
|
58
|
-
]), t)
|
|
59
|
-
assert.deepEqual(actionsOf(result), ['drop-unit 2', 'drop-unit 3', 'drop-unit 8'])
|
|
60
|
-
})
|
|
61
|
-
|
|
62
|
-
test('a partial tree never drops a unit or changes dependencies', () => {
|
|
63
|
-
const t = tree(1, { 1: { children: [3, 5] }, 3: { blockedBy: [5] }, 5: {} }, { complete: false })
|
|
64
|
-
const result = planSync(plan([{ id: '3', status: 'pending' }, { id: '8', status: 'pending' }]), t)
|
|
65
|
-
assert.equal(result.partial, true)
|
|
66
|
-
assert.deepEqual(actionsOf(result), ['add-unit 5'])
|
|
67
|
-
})
|
|
68
|
-
|
|
69
|
-
test('an open blocker outside the tree is reported; a closed one is satisfied', () => {
|
|
70
|
-
const t = tree(1, { 1: { children: [3, 4] }, 3: { blockedBy: ['x/y#9'] }, 4: { blockedBy: ['x/y#10'], blockerState: 'closed' } })
|
|
71
|
-
const result = planSync(plan([{ id: '3', status: 'pending' }, { id: '4', status: 'pending' }]), t)
|
|
72
|
-
assert.deepEqual(result.actions.map((a) => [a.action, a.unit, a.blocker]), [['blocked-outside', '3', 'x/y#9']])
|
|
73
|
-
})
|
|
74
|
-
|
|
75
|
-
test('excluded issues and earlier merges are known; every other open leaf joins the run; a local spec has nothing to sync', () => {
|
|
76
|
-
const t = tree(1, { 1: { children: [2, 3, 4, 5] }, 2: {}, 3: {}, 4: {}, 5: {} })
|
|
77
|
-
const result = planSync(plan([{ id: '2', status: 'pending' }], { excluded: [{ issue: 'o/r#3', reason: 'release gate' }], merged: ['4'] }), t)
|
|
78
|
-
assert.deepEqual(result.actions.map((a) => `${a.action} ${a.unit}`), ['add-unit 5'], 'no wave keeps an open issue out of the run')
|
|
79
|
-
assert.equal(planSync({ spec: 'docs/spec.md', units: [{ id: 'one' }] }, t).synced, false)
|
|
80
|
-
})
|
|
81
|
-
|
|
82
|
-
function runDir(planBody, snapshot) {
|
|
83
|
-
const dir = mkdtempSync(join(tmpdir(), 'plan-sync-'))
|
|
84
|
-
writeFileSync(join(dir, 'task-plan.json'), JSON.stringify(planBody))
|
|
85
|
-
if (snapshot) writeFileSync(join(dir, SNAPSHOT), JSON.stringify(snapshot))
|
|
86
|
-
return dir
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
test('a live sync saves a complete tree; a failed fetch falls back to the snapshot and saves nothing', () => {
|
|
90
|
-
const saved = tree(1, { 1: { children: [2] }, 2: {} })
|
|
91
|
-
const dir = runDir(plan([{ id: '2', status: 'pending' }]), saved)
|
|
92
|
-
const fresh = tree(1, { 1: { children: [2, 3] }, 2: {}, 3: {} })
|
|
93
|
-
const live = syncRun(dir, { live: true, fetch: () => fresh, now: () => new Date('2026-10-12T00:00:00Z') })
|
|
94
|
-
assert.equal(live.source, 'live')
|
|
95
|
-
assert.deepEqual(actionsOf(live), ['add-unit 3'])
|
|
96
|
-
assert.equal(JSON.parse(readFileSync(join(dir, SNAPSHOT), 'utf8')).fetchedAt, '2026-10-12T00:00:00.000Z')
|
|
97
|
-
const down = syncRun(dir, { live: true, fetch: () => ({ root: 'o/r#1', complete: false, errors: [{ key: 'o/r#1', error: 'HTTP 502' }], nodes: {} }) })
|
|
98
|
-
assert.equal(down.source, 'snapshot')
|
|
99
|
-
assert.match(down.fetchError[0].error, /502/)
|
|
100
|
-
assert.deepEqual(actionsOf(down), ['add-unit 3'])
|
|
101
|
-
const offline = syncRun(dir, { fetch: () => { throw new Error('no call without --live') } })
|
|
102
|
-
assert.equal(offline.source, 'snapshot')
|
|
103
|
-
})
|
|
104
|
-
|
|
105
|
-
test('find-run picks the newest run whose spec or saved tree holds the issue', () => {
|
|
106
|
-
const runs = mkdtempSync(join(tmpdir(), 'plan-sync-runs-'))
|
|
107
|
-
const make = (name, body, snap, mtime) => {
|
|
108
|
-
mkdirSync(join(runs, name))
|
|
109
|
-
writeFileSync(join(runs, name, 'task-plan.json'), JSON.stringify(body))
|
|
110
|
-
if (snap) writeFileSync(join(runs, name, SNAPSHOT), JSON.stringify(snap))
|
|
111
|
-
utimesSync(join(runs, name, 'task-plan.json'), mtime, mtime)
|
|
112
|
-
}
|
|
113
|
-
make('old', plan([]), null, 1000)
|
|
114
|
-
make('followup', { spec: 'o/r#1512', units: [] }, tree(1512, { 1512: { children: [1343] }, 1343: {} }), 2000)
|
|
115
|
-
make('other', { spec: 'o/r#9', units: [] }, null, 3000)
|
|
116
|
-
assert.equal(findRun(runs, { repo: 'o/r', number: 1 }), join(runs, 'old'))
|
|
117
|
-
assert.equal(findRun(runs, { repo: 'o/r', number: 1343 }), join(runs, 'followup'))
|
|
118
|
-
assert.equal(findRun(runs, { repo: 'o/r', number: 77 }), null)
|
|
119
|
-
})
|
|
120
|
-
|
|
121
|
-
test('CLI exits 0 with or without actions and without a tree, 2 on bad input; --exit-actions restores the old codes', () => {
|
|
122
|
-
const dir = runDir(plan([{ id: '2', status: 'pending' }]), tree(1, { 1: { children: [2, 3] }, 2: {}, 3: {} }))
|
|
123
|
-
const due = spawnSync(process.execPath, [script, '--run', dir], { encoding: 'utf8' })
|
|
124
|
-
assert.equal(due.status, 0, due.stderr)
|
|
125
|
-
assert.match(due.stdout, /^add-unit +add unit 3/m)
|
|
126
|
-
assert.equal(JSON.parse(spawnSync(process.execPath, [script, '--run', dir, '--json'], { encoding: 'utf8' }).stdout).actions[0].action, 'add-unit')
|
|
127
|
-
assert.equal(spawnSync(process.execPath, [script, '--run', dir, '--exit-actions'], { encoding: 'utf8' }).status, 1)
|
|
128
|
-
const inSync = runDir(plan([{ id: '2', status: 'pending' }]), tree(1, { 1: { children: [2] }, 2: {} }))
|
|
129
|
-
assert.equal(spawnSync(process.execPath, [script, '--run', inSync], { encoding: 'utf8' }).status, 0)
|
|
130
|
-
assert.equal(spawnSync(process.execPath, [script, '--run', inSync, '--exit-actions'], { encoding: 'utf8' }).status, 0)
|
|
131
|
-
const noTree = runDir(plan([]))
|
|
132
|
-
const missing = spawnSync(process.execPath, [script, '--run', noTree], { encoding: 'utf8' })
|
|
133
|
-
assert.equal(missing.status, 0, missing.stderr)
|
|
134
|
-
assert.match(missing.stdout, /no issue tree available/)
|
|
135
|
-
assert.equal(JSON.parse(spawnSync(process.execPath, [script, '--run', noTree, '--json'], { encoding: 'utf8' }).stdout).missingTree, true)
|
|
136
|
-
assert.equal(spawnSync(process.execPath, [script, '--run', noTree, '--exit-actions'], { encoding: 'utf8' }).status, 2)
|
|
137
|
-
assert.equal(spawnSync(process.execPath, [script, '--run', join(noTree, 'nope')], { encoding: 'utf8' }).status, 2)
|
|
138
|
-
assert.equal(spawnSync(process.execPath, [script], { encoding: 'utf8' }).status, 2)
|
|
139
|
-
assert.throws(() => parseCliArgs(['--find-run', '--runs', 'x']), PlanSyncError)
|
|
140
|
-
})
|
|
141
|
-
|
|
142
|
-
test('--find-run exits 0 whether or not a run is found; --json and --exit-actions say which', () => {
|
|
143
|
-
const runs = mkdtempSync(join(tmpdir(), 'plan-sync-find-'))
|
|
144
|
-
const empty = (...extra) => spawnSync(process.execPath, [script, '--find-run', '--runs', runs, '--issue', 'o/r#77', ...extra], { encoding: 'utf8' })
|
|
145
|
-
const none = empty()
|
|
146
|
-
assert.equal(none.status, 0, none.stderr)
|
|
147
|
-
assert.equal(none.stdout, '', 'nothing on stdout when no run is found')
|
|
148
|
-
assert.deepEqual(JSON.parse(empty('--json').stdout), { found: false, dir: null })
|
|
149
|
-
assert.equal(empty('--exit-actions').status, 1)
|
|
150
|
-
mkdirSync(join(runs, 'one'))
|
|
151
|
-
writeFileSync(join(runs, 'one', 'task-plan.json'), JSON.stringify(plan([], { spec: 'o/r#77' })))
|
|
152
|
-
const found = empty('--json')
|
|
153
|
-
assert.equal(found.status, 0, found.stderr)
|
|
154
|
-
assert.deepEqual(JSON.parse(found.stdout), { found: true, dir: join(runs, 'one') })
|
|
155
|
-
assert.equal(empty('--exit-actions').status, 0)
|
|
156
|
-
})
|
|
@@ -1,448 +0,0 @@
|
|
|
1
|
-
import { test } from 'node:test'
|
|
2
|
-
import assert from 'node:assert/strict'
|
|
3
|
-
import { spawnSync } from 'node:child_process'
|
|
4
|
-
import { fileURLToPath } from 'node:url'
|
|
5
|
-
|
|
6
|
-
import {
|
|
7
|
-
recommendImplementer,
|
|
8
|
-
rankReviewers,
|
|
9
|
-
fillExplorer,
|
|
10
|
-
fillDiagnoser,
|
|
11
|
-
slotPoints,
|
|
12
|
-
buildAsk,
|
|
13
|
-
buildPreflightModels,
|
|
14
|
-
TEAM_REVIEWER_POLICY,
|
|
15
|
-
} from './preflight-models.mjs'
|
|
16
|
-
|
|
17
|
-
const points = [
|
|
18
|
-
{ id: 'openai/gpt-6-astra', effort: 'high', tier: 'frontier', family: 'openai', key: 'openai/gpt-6-astra@high' },
|
|
19
|
-
{ id: 'openai/gpt-5.6-sol', effort: 'high', tier: 'frontier', family: 'openai', key: 'openai/gpt-5.6-sol@high' },
|
|
20
|
-
{ id: 'openai/gpt-6.1-sol', effort: 'high', tier: 'frontier', family: 'openai', key: 'openai/gpt-6.1-sol@high' },
|
|
21
|
-
{ id: 'openai/gpt-5.5', effort: 'high', tier: 'deep-reasoner', family: 'openai', key: 'openai/gpt-5.5@high' },
|
|
22
|
-
{ id: 'openai/gpt-5.6-terra', effort: 'high', tier: 'balanced-coder', family: 'openai', key: 'openai/gpt-5.6-terra@high' },
|
|
23
|
-
{ id: 'openai/gpt-6-luna', effort: 'high', tier: 'balanced-coder', family: 'openai', key: 'openai/gpt-6-luna@high' },
|
|
24
|
-
{ id: 'xiaomi/mimo-v2.6-pro', effort: 'high', tier: 'frontier', family: 'xiaomi', key: 'xiaomi/mimo-v2.6-pro@high' },
|
|
25
|
-
{ id: 'xai/grok-4.7', effort: 'high', tier: 'frontier', family: 'xai', key: 'xai/grok-4.7@high' },
|
|
26
|
-
{ id: 'xai/grok-4.6', effort: 'high', tier: 'deep-reasoner', family: 'xai', key: 'xai/grok-4.6@high' },
|
|
27
|
-
{ id: 'xai/grok-4.5', effort: 'high', tier: 'balanced-coder', family: 'xai', key: 'xai/grok-4.5@high' },
|
|
28
|
-
{ id: 'anthropic/claude-opus', effort: 'high', tier: 'frontier', family: 'anthropic', key: 'anthropic/claude-opus@high' },
|
|
29
|
-
]
|
|
30
|
-
|
|
31
|
-
test('routine risk recommends a balanced-coder, not frontier', () => {
|
|
32
|
-
const pick = recommendImplementer(points, 'routine')
|
|
33
|
-
assert.equal(pick.tier, 'balanced-coder')
|
|
34
|
-
assert.ok(['xai/grok-4.5', 'openai/gpt-5.6-terra'].includes(pick.id))
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
test('routine risk walks the team ladder: gpt-6.1-sol@high, gpt-6-luna@high, grok-4.6@high, then mimo-v2.6-pro@high', () => {
|
|
38
|
-
const pick = recommendImplementer(points, 'routine', 'pi')
|
|
39
|
-
assert.equal(pick.key, 'openai/gpt-6.1-sol@high')
|
|
40
|
-
assert.equal(pick.tier, 'frontier')
|
|
41
|
-
assert.equal(rankReviewers(points, pick, 'pi').fill.key, 'openai/gpt-6-astra@medium')
|
|
42
|
-
const withoutSol = points.filter((p) => p.id !== 'openai/gpt-6.1-sol')
|
|
43
|
-
const second = recommendImplementer(withoutSol, 'routine', 'pi')
|
|
44
|
-
assert.equal(second.key, 'openai/gpt-6-luna@high')
|
|
45
|
-
assert.equal(second.tier, 'balanced-coder')
|
|
46
|
-
assert.equal(rankReviewers(points, second, 'pi').fill.key, 'openai/gpt-6-astra@medium')
|
|
47
|
-
const withoutLuna = withoutSol.filter((p) => p.id !== 'openai/gpt-6-luna')
|
|
48
|
-
const third = recommendImplementer(withoutLuna, 'routine', 'pi')
|
|
49
|
-
assert.equal(third.key, 'xai/grok-4.6@high')
|
|
50
|
-
// a cross-family implementation is still reviewed by the team primary, a distinct id and family
|
|
51
|
-
const grokReview = rankReviewers(points, third, 'pi')
|
|
52
|
-
assert.equal(grokReview.fill.key, 'openai/gpt-6-astra@medium')
|
|
53
|
-
assert.equal(grokReview.reducedDiversity, false)
|
|
54
|
-
const withoutGrok46 = withoutLuna.filter((p) => p.id !== 'xai/grok-4.6')
|
|
55
|
-
const fourth = recommendImplementer(withoutGrok46, 'routine', 'pi')
|
|
56
|
-
assert.equal(fourth.key, 'xiaomi/mimo-v2.6-pro@high')
|
|
57
|
-
assert.equal(rankReviewers(points, fourth, 'pi').fill.key, 'openai/gpt-6-astra@medium')
|
|
58
|
-
// past the ladder, the tier order picks a balanced-coder
|
|
59
|
-
const withoutMimo = withoutGrok46.filter((p) => p.id !== 'xiaomi/mimo-v2.6-pro')
|
|
60
|
-
assert.equal(recommendImplementer(withoutMimo, 'routine', 'pi').tier, 'balanced-coder')
|
|
61
|
-
})
|
|
62
|
-
|
|
63
|
-
test('codex routine ladder is gpt-6.1-sol@high, then gpt-6-luna@high', () => {
|
|
64
|
-
const codex = [
|
|
65
|
-
{ id: 'gpt-6.1-sol', effort: 'high', tier: 'frontier', family: 'openai', key: 'gpt-6.1-sol@high' },
|
|
66
|
-
{ id: 'gpt-6-luna', effort: 'high', tier: 'balanced-coder', family: 'openai', key: 'gpt-6-luna@high' },
|
|
67
|
-
]
|
|
68
|
-
assert.equal(recommendImplementer(codex, 'routine', 'codex').key, 'gpt-6.1-sol@high')
|
|
69
|
-
assert.equal(recommendImplementer(codex.slice(1), 'routine', 'codex').key, 'gpt-6-luna@high')
|
|
70
|
-
})
|
|
71
|
-
|
|
72
|
-
test('escalation fix workers walk the high-risk ladder', () => {
|
|
73
|
-
assert.equal(fillDiagnoser(points, 'pi').fill.key, 'openai/gpt-6.1-sol@high')
|
|
74
|
-
const withoutSol61 = points.filter((p) => p.id !== 'openai/gpt-6.1-sol')
|
|
75
|
-
assert.equal(fillDiagnoser(withoutSol61, 'pi').fill.key, 'openai/gpt-6-astra@high')
|
|
76
|
-
const withoutAstra = withoutSol61.filter((p) => p.id !== 'openai/gpt-6-astra')
|
|
77
|
-
assert.equal(fillDiagnoser(withoutAstra, 'pi').fill.key, 'openai/gpt-5.6-sol@high')
|
|
78
|
-
const withoutSol56 = withoutAstra.filter((p) => p.id !== 'openai/gpt-5.6-sol')
|
|
79
|
-
assert.equal(fillDiagnoser(withoutSol56, 'pi').fill.key, 'xai/grok-4.7@high')
|
|
80
|
-
})
|
|
81
|
-
|
|
82
|
-
test('explorer takes gpt-6.1-sol@medium first, then gpt-6-luna, grok-4.6, mimo-v2.6-pro (all @high), then the balanced-coder tier', () => {
|
|
83
|
-
const explorer = fillExplorer(points, 'pi')
|
|
84
|
-
assert.equal(explorer.reason, 'team-default')
|
|
85
|
-
assert.equal(explorer.fill.key, 'openai/gpt-6.1-sol@medium')
|
|
86
|
-
assert.equal(explorer.fill.effort, 'medium')
|
|
87
|
-
assert.equal(explorer.fill.source, 'team-explorer-policy')
|
|
88
|
-
const withoutSol = points.filter((p) => p.id !== 'openai/gpt-6.1-sol')
|
|
89
|
-
const second = fillExplorer(withoutSol, 'pi')
|
|
90
|
-
assert.equal(second.reason, 'team-default')
|
|
91
|
-
assert.equal(second.fill.key, 'openai/gpt-6-luna@high')
|
|
92
|
-
const withoutLuna = withoutSol.filter((p) => p.id !== 'openai/gpt-6-luna')
|
|
93
|
-
assert.equal(fillExplorer(withoutLuna, 'pi').fill.key, 'xai/grok-4.6@high')
|
|
94
|
-
const withoutGrok46 = withoutLuna.filter((p) => p.id !== 'xai/grok-4.6')
|
|
95
|
-
assert.equal(fillExplorer(withoutGrok46, 'pi').fill.key, 'xiaomi/mimo-v2.6-pro@high')
|
|
96
|
-
const noLadder = withoutGrok46.filter((p) => p.id !== 'xiaomi/mimo-v2.6-pro')
|
|
97
|
-
const tierFill = fillExplorer(noLadder, 'pi')
|
|
98
|
-
assert.equal(tierFill.reason, 'balanced-coder')
|
|
99
|
-
assert.equal(tierFill.fill.tier, 'balanced-coder')
|
|
100
|
-
})
|
|
101
|
-
|
|
102
|
-
test('a discovered gpt-6.1-sol fills the explorer at medium, not at its @high implementer rung', () => {
|
|
103
|
-
const onlySolHigh = [points.find((p) => p.id === 'openai/gpt-6.1-sol'), points.find((p) => p.id === 'openai/gpt-5.6-terra')]
|
|
104
|
-
assert.equal(fillExplorer(onlySolHigh, 'pi').fill.key, 'openai/gpt-6.1-sol@medium')
|
|
105
|
-
})
|
|
106
|
-
|
|
107
|
-
test('the explorer takes gpt-6.1-sol@medium while the routine implementer takes gpt-6.1-sol@high', () => {
|
|
108
|
-
assert.equal(fillExplorer(points, 'pi').fill.key, 'openai/gpt-6.1-sol@medium')
|
|
109
|
-
assert.equal(recommendImplementer(points, 'routine', 'pi').key, 'openai/gpt-6.1-sol@high')
|
|
110
|
-
})
|
|
111
|
-
|
|
112
|
-
test('an undiscovered explorer rung falls through to the next discovered point', () => {
|
|
113
|
-
// Discovery yields neither gpt-6.1-sol nor gpt-6-luna, so the explorer lands on the balanced-coder tier.
|
|
114
|
-
const tiered = [
|
|
115
|
-
{ id: 'gpt-6-astra', tiers: { high: 'frontier' }, source: 'team-seed' },
|
|
116
|
-
{ id: 'gpt-5.6-sol', tiers: { high: 'frontier' }, source: 'team-seed' },
|
|
117
|
-
{ id: 'gpt-5.6-terra', tiers: { high: 'balanced-coder' }, source: 'team-seed' },
|
|
118
|
-
]
|
|
119
|
-
const result = buildPreflightModels({
|
|
120
|
-
harness: 'codex',
|
|
121
|
-
risk: 'routine',
|
|
122
|
-
discoverFn: () => ({
|
|
123
|
-
harness: 'codex',
|
|
124
|
-
completeness: 'full',
|
|
125
|
-
discovered: tiered.map(({ id }) => ({ id, source: 'current-turn' })),
|
|
126
|
-
notes: [],
|
|
127
|
-
}),
|
|
128
|
-
tierFn: () => ({ models: tiered, seedDisagreements: [], staleClassifications: [] }),
|
|
129
|
-
})
|
|
130
|
-
assert.equal(result.explorer.fill.key, 'gpt-5.6-terra@high')
|
|
131
|
-
assert.equal(result.explorer.reason, 'balanced-coder')
|
|
132
|
-
assert.equal(result.ask.explorerFill.id, 'gpt-5.6-terra@high')
|
|
133
|
-
// the same harness with gpt-6.1-sol discovered takes the medium rung
|
|
134
|
-
const withSol = [...tiered, { id: 'gpt-6.1-sol', tiers: { high: 'frontier' }, source: 'team-seed' }]
|
|
135
|
-
const sol = buildPreflightModels({
|
|
136
|
-
harness: 'codex',
|
|
137
|
-
risk: 'routine',
|
|
138
|
-
discoverFn: () => ({
|
|
139
|
-
harness: 'codex',
|
|
140
|
-
completeness: 'full',
|
|
141
|
-
discovered: withSol.map(({ id }) => ({ id, source: 'current-turn' })),
|
|
142
|
-
notes: [],
|
|
143
|
-
}),
|
|
144
|
-
tierFn: () => ({ models: withSol, seedDisagreements: [], staleClassifications: [] }),
|
|
145
|
-
})
|
|
146
|
-
assert.equal(sol.explorer.fill.key, 'gpt-6.1-sol@medium')
|
|
147
|
-
assert.equal(sol.implementer.key, 'gpt-6.1-sol@high', 'the routine implementer takes the @high rung')
|
|
148
|
-
})
|
|
149
|
-
|
|
150
|
-
test('high risk walks the team ladder: gpt-6.1-sol, gpt-6-astra, gpt-5.6-sol, grok-4.7 (all @high), then the deep-reasoner tier', () => {
|
|
151
|
-
const pick = recommendImplementer(points, 'high', 'pi')
|
|
152
|
-
assert.equal(pick.id, 'openai/gpt-6.1-sol')
|
|
153
|
-
assert.equal(pick.tier, 'frontier')
|
|
154
|
-
assert.equal(pick.effort, 'high')
|
|
155
|
-
// the gpt-6.1-sol implementation is reviewed by Astra (distinct id, same family)
|
|
156
|
-
const firstReview = rankReviewers(points, pick, 'pi')
|
|
157
|
-
assert.equal(firstReview.fill.key, 'openai/gpt-6-astra@medium')
|
|
158
|
-
assert.equal(firstReview.reason, 'team-default')
|
|
159
|
-
// without gpt-6.1-sol, Astra implements and is reviewed by the implementer-aware fallback
|
|
160
|
-
const withoutSol61 = points.filter((p) => p.id !== 'openai/gpt-6.1-sol')
|
|
161
|
-
const second = recommendImplementer(withoutSol61, 'high', 'pi')
|
|
162
|
-
assert.equal(second.key, 'openai/gpt-6-astra@high')
|
|
163
|
-
const secondReview = rankReviewers(points, second, 'pi')
|
|
164
|
-
assert.equal(secondReview.fill.key, 'openai/gpt-5.6-sol@medium')
|
|
165
|
-
assert.equal(secondReview.reason, 'implementer-aware-default')
|
|
166
|
-
// then gpt-5.6-sol and grok-4.7, each reviewed by gpt-6-astra@medium
|
|
167
|
-
const withoutAstra = withoutSol61.filter((p) => p.id !== 'openai/gpt-6-astra')
|
|
168
|
-
const third = recommendImplementer(withoutAstra, 'high', 'pi')
|
|
169
|
-
assert.equal(third.key, 'openai/gpt-5.6-sol@high')
|
|
170
|
-
assert.equal(rankReviewers(points, third, 'pi').fill.key, 'openai/gpt-6-astra@medium')
|
|
171
|
-
const withoutSol56 = withoutAstra.filter((p) => p.id !== 'openai/gpt-5.6-sol')
|
|
172
|
-
const fourth = recommendImplementer(withoutSol56, 'high', 'pi')
|
|
173
|
-
assert.equal(fourth.key, 'xai/grok-4.7@high')
|
|
174
|
-
assert.equal(rankReviewers(points, fourth, 'pi').fill.key, 'openai/gpt-6-astra@medium')
|
|
175
|
-
// without the harness (no team ladder) the tier order picks a deep-reasoner, never frontier
|
|
176
|
-
assert.equal(recommendImplementer(points, 'high').tier, 'deep-reasoner')
|
|
177
|
-
// without any ladder rung discovered, the tier order falls back to the other deep-reasoner
|
|
178
|
-
const withoutLadder = withoutSol56.filter((p) => !['xai/grok-4.7', 'xai/grok-4.6'].includes(p.id))
|
|
179
|
-
assert.equal(recommendImplementer(withoutLadder, 'high', 'pi').id, 'openai/gpt-5.5')
|
|
180
|
-
})
|
|
181
|
-
|
|
182
|
-
test('the recommended frontier implementer is labelled as the team preference, not an alternate', () => {
|
|
183
|
-
const implementer = recommendImplementer(points, 'high', 'pi')
|
|
184
|
-
const reviewer = rankReviewers(points, implementer, 'pi')
|
|
185
|
-
const ask = buildAsk(implementer, points, reviewer, { risk: 'high' })
|
|
186
|
-
assert.equal(ask.options[0].modelId, 'openai/gpt-6.1-sol')
|
|
187
|
-
assert.match(ask.options[0].description, /recommended · frontier — team implementer ladder preference/)
|
|
188
|
-
// without a harness there is no ladder to consult, so the other frontier point is a plain alternate
|
|
189
|
-
const otherFrontier = [...ask.options, ...ask.alternates].find((o) => o.modelId === 'openai/gpt-5.6-sol')
|
|
190
|
-
assert.match(otherFrontier.description, /alternate only/)
|
|
191
|
-
})
|
|
192
|
-
|
|
193
|
-
test('the ask lists the discovered ladder rungs first, in ladder order, before other points', () => {
|
|
194
|
-
// Real Pi discovery shape: deep-reasoners whose ids sort before the ladder rungs, plus a
|
|
195
|
-
// balanced-coder with a cheap id. Before the fix these pushed the rungs into `alternates`.
|
|
196
|
-
const many = [
|
|
197
|
-
...points,
|
|
198
|
-
{ id: 'deepseek/deepseek-v4-pro', effort: 'max', tier: 'deep-reasoner', family: 'deepseek', key: 'deepseek/deepseek-v4-pro@max' },
|
|
199
|
-
{ id: 'kimi-coding/k3', effort: 'high', tier: 'deep-reasoner', family: 'kimi', key: 'kimi-coding/k3@high' },
|
|
200
|
-
{ id: 'deepseek/deepseek-flash', effort: 'max', tier: 'balanced-coder', family: 'deepseek', key: 'deepseek/deepseek-flash@max' },
|
|
201
|
-
]
|
|
202
|
-
const high = recommendImplementer(many, 'high', 'pi')
|
|
203
|
-
const highAsk = buildAsk(many.find((p) => p.key === high.key), many, rankReviewers(many, high, 'pi'), { risk: 'high', harness: 'pi' })
|
|
204
|
-
assert.deepEqual(
|
|
205
|
-
highAsk.options.map((o) => o.id),
|
|
206
|
-
['openai/gpt-6.1-sol@high', 'openai/gpt-6-astra@high', 'openai/gpt-5.6-sol@high', 'xai/grok-4.7@high'],
|
|
207
|
-
'high-risk options are the ladder',
|
|
208
|
-
)
|
|
209
|
-
assert.match(highAsk.options[1].description, /team ladder rung 2/)
|
|
210
|
-
assert.ok(highAsk.alternates.some((o) => o.modelId === 'deepseek/deepseek-v4-pro'), 'non-ladder deep-reasoners become alternates')
|
|
211
|
-
|
|
212
|
-
const routine = recommendImplementer(many, 'routine', 'pi')
|
|
213
|
-
const routineAsk = buildAsk(routine, many, rankReviewers(many, routine, 'pi'), { risk: 'routine', harness: 'pi' })
|
|
214
|
-
assert.deepEqual(
|
|
215
|
-
routineAsk.options.map((o) => o.id),
|
|
216
|
-
['openai/gpt-6.1-sol@high', 'openai/gpt-6-luna@high', 'xai/grok-4.6@high', 'xiaomi/mimo-v2.6-pro@high'],
|
|
217
|
-
'routine options are the ladder',
|
|
218
|
-
)
|
|
219
|
-
// an undiscovered rung is skipped, not left as a hole: the next point fills the fourth slot
|
|
220
|
-
const withoutMimo = many.filter((p) => p.id !== 'xiaomi/mimo-v2.6-pro')
|
|
221
|
-
const routine2 = recommendImplementer(withoutMimo, 'routine', 'pi')
|
|
222
|
-
const ask2 = buildAsk(routine2, withoutMimo, rankReviewers(withoutMimo, routine2, 'pi'), { risk: 'routine', harness: 'pi' })
|
|
223
|
-
assert.deepEqual(ask2.options.slice(0, 3).map((o) => o.id), ['openai/gpt-6.1-sol@high', 'openai/gpt-6-luna@high', 'xai/grok-4.6@high'])
|
|
224
|
-
assert.equal(ask2.options.length, 4)
|
|
225
|
-
})
|
|
226
|
-
|
|
227
|
-
test('non-Astra implementation prefers the gpt-6-astra@medium policy review when discovered', () => {
|
|
228
|
-
const implementer = recommendImplementer(points, 'routine', 'pi')
|
|
229
|
-
const review = rankReviewers(points, implementer, 'pi')
|
|
230
|
-
assert.equal(review.reason, 'team-default')
|
|
231
|
-
assert.equal(review.fill.id, TEAM_REVIEWER_POLICY.pi.primary.id)
|
|
232
|
-
assert.equal(review.fill.effort, 'medium')
|
|
233
|
-
assert.equal(review.fill.tier, 'frontier')
|
|
234
|
-
assert.equal(review.fill.source, 'team-review-policy')
|
|
235
|
-
assert.equal(review.fill.citation, 'docs/research/2026-09-23-reviewer-benchmark-astra-vs-sol.md')
|
|
236
|
-
assert.notEqual(review.fill.id, implementer.id)
|
|
237
|
-
assert.equal(review.ranking[0].key, 'openai/gpt-6-astra@medium')
|
|
238
|
-
assert.equal(review.ranking[1].key, 'openai/gpt-5.6-sol@medium')
|
|
239
|
-
assert.ok(!review.ranking.some((candidate) => candidate.effort === 'high' && candidate.id === 'openai/gpt-6-astra'), 'the policy point replaces the catalog high point in the ranking')
|
|
240
|
-
})
|
|
241
|
-
|
|
242
|
-
test('Astra implementation uses the gpt-5.6-sol@medium implementer-aware default', () => {
|
|
243
|
-
const implementer = points.find((p) => p.id === 'openai/gpt-6-astra')
|
|
244
|
-
const review = rankReviewers(points, implementer, 'pi')
|
|
245
|
-
assert.equal(review.reason, 'implementer-aware-default')
|
|
246
|
-
assert.notEqual(review.fill.id, implementer.id)
|
|
247
|
-
assert.equal(review.fill.id, TEAM_REVIEWER_POLICY.pi.fallback.id)
|
|
248
|
-
assert.equal(review.fill.effort, 'medium')
|
|
249
|
-
assert.equal(review.fill.key, 'openai/gpt-5.6-sol@medium')
|
|
250
|
-
})
|
|
251
|
-
|
|
252
|
-
test('another Astra effort is still the same implementer model id', () => {
|
|
253
|
-
const implementer = {
|
|
254
|
-
...points.find((p) => p.id === 'openai/gpt-6-astra'),
|
|
255
|
-
effort: 'xhigh',
|
|
256
|
-
key: 'openai/gpt-6-astra@xhigh',
|
|
257
|
-
}
|
|
258
|
-
const review = rankReviewers(points, implementer, 'pi')
|
|
259
|
-
assert.equal(review.fill.id, 'openai/gpt-5.6-sol')
|
|
260
|
-
assert.notEqual(review.fill.id, implementer.id)
|
|
261
|
-
})
|
|
262
|
-
|
|
263
|
-
test('a gpt-6.1-sol implementation still gets the Astra reviewer (distinct id, same family)', () => {
|
|
264
|
-
const implementer = points.find((p) => p.id === 'openai/gpt-6.1-sol')
|
|
265
|
-
const review = rankReviewers(points, implementer, 'pi')
|
|
266
|
-
assert.equal(review.reason, 'team-default')
|
|
267
|
-
assert.equal(review.fill.id, 'openai/gpt-6-astra')
|
|
268
|
-
assert.equal(review.reducedDiversity, true, 'same family is flagged, not forbidden')
|
|
269
|
-
})
|
|
270
|
-
|
|
271
|
-
test('missing implementer-aware fallback uses the distinct-model ladder', () => {
|
|
272
|
-
const withoutSol56 = points.filter((p) => p.id !== 'openai/gpt-5.6-sol')
|
|
273
|
-
const implementer = withoutSol56.find((p) => p.id === 'openai/gpt-6-astra')
|
|
274
|
-
const review = rankReviewers(withoutSol56, implementer, 'pi')
|
|
275
|
-
assert.equal(review.reason, 'ladder')
|
|
276
|
-
// diversity-first: a cross-family deep-reasoner (grok-4.6) outranks cross-family frontier points
|
|
277
|
-
assert.equal(review.fill.id, 'xai/grok-4.6')
|
|
278
|
-
const withoutGrok = withoutSol56.filter((p) => p.family !== 'xai' && p.family !== 'xiaomi')
|
|
279
|
-
assert.equal(rankReviewers(withoutGrok, implementer, 'pi').fill.id, 'anthropic/claude-opus')
|
|
280
|
-
})
|
|
281
|
-
|
|
282
|
-
test('missing Astra primary uses the distinct-model ladder even when gpt-5.6-sol is available', () => {
|
|
283
|
-
const withoutAstra = points.filter((p) => p.id !== 'openai/gpt-6-astra')
|
|
284
|
-
const implementer = withoutAstra.find((p) => p.id === 'xai/grok-4.5')
|
|
285
|
-
const review = rankReviewers(withoutAstra, implementer, 'pi')
|
|
286
|
-
assert.equal(review.reason, 'ladder')
|
|
287
|
-
assert.equal(review.fill.id, 'openai/gpt-5.5', 'a cross-family deep-reasoner leads the ladder')
|
|
288
|
-
assert.equal(review.ranking[0].id, 'openai/gpt-5.6-sol', 'the fallback frontier point stays first in the ranking for a later Astra override')
|
|
289
|
-
})
|
|
290
|
-
|
|
291
|
-
test('scoped-coder points never enter slotPoints', () => {
|
|
292
|
-
const tiered = [
|
|
293
|
-
{ id: 'scoped/x', tiers: { high: 'scoped-coder' }, source: 'banked' },
|
|
294
|
-
{ id: 'ok/y', tiers: { high: 'balanced-coder' }, source: 'banked' },
|
|
295
|
-
]
|
|
296
|
-
const out = slotPoints(tiered, { harness: 'pi' })
|
|
297
|
-
assert.deepEqual(out.map((p) => p.id), ['ok/y'])
|
|
298
|
-
})
|
|
299
|
-
|
|
300
|
-
test('ask lists recommended implementer first, caps at 4, keeps frontier visible', () => {
|
|
301
|
-
const many = [
|
|
302
|
-
...points,
|
|
303
|
-
{ id: 'a/balanced', effort: 'high', tier: 'balanced-coder', family: 'a', key: 'a/balanced@high' },
|
|
304
|
-
{ id: 'b/balanced', effort: 'high', tier: 'balanced-coder', family: 'b', key: 'b/balanced@high' },
|
|
305
|
-
{ id: 'c/deep', effort: 'high', tier: 'deep-reasoner', family: 'c', key: 'c/deep@high' },
|
|
306
|
-
]
|
|
307
|
-
const implementer = recommendImplementer(many, 'routine')
|
|
308
|
-
const explorer = fillExplorer(many, 'pi')
|
|
309
|
-
const reviewer = rankReviewers(many, implementer, 'pi')
|
|
310
|
-
const ask = buildAsk(implementer, many, reviewer, { risk: 'routine', explorer })
|
|
311
|
-
assert.equal(ask.options[0].modelId, implementer.id)
|
|
312
|
-
assert.equal(ask.recommended, implementer.key)
|
|
313
|
-
assert.ok(ask.options.length <= 4)
|
|
314
|
-
assert.equal(ask.reviewerFill.modelId, reviewer.fill.id)
|
|
315
|
-
assert.equal(ask.explorerFill.modelId, explorer.fill.id)
|
|
316
|
-
assert.ok(
|
|
317
|
-
ask.options.some((o) => o.tier === 'frontier') || ask.alternates.some((o) => o.tier === 'frontier'),
|
|
318
|
-
'frontier stays visible',
|
|
319
|
-
)
|
|
320
|
-
})
|
|
321
|
-
|
|
322
|
-
test('buildPreflightModels is injectable and defers sync/bank', () => {
|
|
323
|
-
const result = buildPreflightModels({
|
|
324
|
-
harness: 'pi',
|
|
325
|
-
risk: 'routine',
|
|
326
|
-
available: ['openai/gpt-5.5', 'xai/grok-4.5', 'openai/gpt-5.6-sol', 'openai/gpt-5.6-terra', 'openai/gpt-6-astra'],
|
|
327
|
-
discoverFn: () => ({
|
|
328
|
-
harness: 'pi',
|
|
329
|
-
completeness: 'full',
|
|
330
|
-
discovered: [
|
|
331
|
-
{ id: 'openai/gpt-6-astra', source: 'current-turn' },
|
|
332
|
-
{ id: 'openai/gpt-5.5', source: 'current-turn' },
|
|
333
|
-
{ id: 'xai/grok-4.5', source: 'current-turn' },
|
|
334
|
-
{ id: 'openai/gpt-5.6-sol', source: 'current-turn' },
|
|
335
|
-
{ id: 'openai/gpt-5.6-terra', source: 'current-turn' },
|
|
336
|
-
],
|
|
337
|
-
notes: [],
|
|
338
|
-
}),
|
|
339
|
-
tierFn: () => ({
|
|
340
|
-
models: [
|
|
341
|
-
{ id: 'openai/gpt-6-astra', tiers: { high: 'frontier' }, source: 'team-seed', citation: null },
|
|
342
|
-
{ id: 'openai/gpt-5.5', tiers: { high: 'deep-reasoner' }, source: 'team-seed', citation: null },
|
|
343
|
-
{ id: 'xai/grok-4.5', tiers: { high: 'balanced-coder' }, source: 'team-seed', citation: null },
|
|
344
|
-
{ id: 'openai/gpt-5.6-sol', tiers: { high: 'frontier' }, source: 'team-seed', citation: null },
|
|
345
|
-
{ id: 'openai/gpt-5.6-terra', tiers: { high: 'balanced-coder' }, source: 'team-seed', citation: null },
|
|
346
|
-
],
|
|
347
|
-
seedDisagreements: [],
|
|
348
|
-
staleClassifications: [],
|
|
349
|
-
}),
|
|
350
|
-
})
|
|
351
|
-
assert.equal(result.ok, true)
|
|
352
|
-
assert.equal(result.implementer.tier, 'balanced-coder')
|
|
353
|
-
assert.equal(result.explorer.reason, 'balanced-coder')
|
|
354
|
-
assert.equal(result.explorer.fill.id, 'openai/gpt-5.6-terra')
|
|
355
|
-
assert.equal(result.reviewer.reason, 'team-default')
|
|
356
|
-
assert.equal(result.reviewer.fill.id, TEAM_REVIEWER_POLICY.pi.primary.id)
|
|
357
|
-
assert.equal(result.reviewer.fill.effort, 'medium')
|
|
358
|
-
assert.ok(result.deferred.afterConfirm.some((s) => s.includes('sync')))
|
|
359
|
-
assert.ok(result.deferred.doNotReadBeforeAsk.length >= 1)
|
|
360
|
-
assert.equal(result.ask.options[0].modelId, result.implementer.id)
|
|
361
|
-
assert.equal(result.ask.explorerFill.modelId, 'openai/gpt-5.6-terra')
|
|
362
|
-
assert.equal(result.diagnoser.fill.key, 'openai/gpt-6-astra@high')
|
|
363
|
-
assert.equal(result.ask.diagnoserFill.id, 'openai/gpt-6-astra@high')
|
|
364
|
-
})
|
|
365
|
-
|
|
366
|
-
test('CLI --ask-only prints only the ask block', () => {
|
|
367
|
-
const script = fileURLToPath(new URL('./preflight-models.mjs', import.meta.url))
|
|
368
|
-
const run = spawnSync(process.execPath, [
|
|
369
|
-
script,
|
|
370
|
-
'--harness', 'pi',
|
|
371
|
-
'--risk', 'routine',
|
|
372
|
-
'--available', 'openai/gpt-5.5,xai/grok-4.5,openai/gpt-5.6-sol,openai/gpt-5.6-terra,openai/gpt-6-astra',
|
|
373
|
-
'--ask-only',
|
|
374
|
-
], { encoding: 'utf8' })
|
|
375
|
-
assert.equal(run.status, 0, run.stderr)
|
|
376
|
-
const ask = JSON.parse(run.stdout)
|
|
377
|
-
assert.ok(ask.question)
|
|
378
|
-
assert.ok(Array.isArray(ask.options))
|
|
379
|
-
assert.ok(ask.reviewerFill)
|
|
380
|
-
assert.ok(ask.explorerFill)
|
|
381
|
-
assert.equal(ask.options[0].description.includes('recommended'), true)
|
|
382
|
-
})
|
|
383
|
-
|
|
384
|
-
const pinTiered = [
|
|
385
|
-
{ id: 'gpt-6-astra', tiers: { high: 'frontier' }, source: 'team-seed' },
|
|
386
|
-
{ id: 'gpt-6.1-sol', tiers: { high: 'frontier' }, source: 'team-seed' },
|
|
387
|
-
{ id: 'gpt-5.6-terra', tiers: { high: 'balanced-coder' }, source: 'team-seed' },
|
|
388
|
-
]
|
|
389
|
-
const pinRun = (implementer, tiered = pinTiered) => buildPreflightModels({
|
|
390
|
-
harness: 'codex',
|
|
391
|
-
risk: 'routine',
|
|
392
|
-
implementer,
|
|
393
|
-
discoverFn: () => ({
|
|
394
|
-
harness: 'codex',
|
|
395
|
-
completeness: 'full',
|
|
396
|
-
discovered: tiered.map(({ id }) => ({ id, source: 'current-turn' })),
|
|
397
|
-
notes: [],
|
|
398
|
-
}),
|
|
399
|
-
tierFn: () => ({ models: tiered, seedDisagreements: [], staleClassifications: [] }),
|
|
400
|
-
})
|
|
401
|
-
|
|
402
|
-
test('a pinned implementer is kept over the recommendation and is the only option', () => {
|
|
403
|
-
const result = pinRun('gpt-5.6-terra')
|
|
404
|
-
assert.equal(result.ok, true)
|
|
405
|
-
assert.equal(result.pinned, 'gpt-5.6-terra')
|
|
406
|
-
assert.equal(result.implementer.key, 'gpt-5.6-terra@high', 'the ladder would have picked gpt-6.1-sol@high')
|
|
407
|
-
assert.deepEqual(result.ask.options.map((o) => o.id), ['gpt-5.6-terra@high'])
|
|
408
|
-
assert.deepEqual(result.ask.alternates, [])
|
|
409
|
-
assert.equal(result.ask.pinned, true)
|
|
410
|
-
assert.notEqual(result.reviewer.fill.id, 'gpt-5.6-terra', 'the reviewer still differs from the pinned implementer')
|
|
411
|
-
})
|
|
412
|
-
|
|
413
|
-
test('a pin with an effort matches that operating point only', () => {
|
|
414
|
-
assert.equal(pinRun('gpt-6-astra@high').implementer.key, 'gpt-6-astra@high')
|
|
415
|
-
const wrongEffort = pinRun('gpt-6-astra@max')
|
|
416
|
-
assert.equal(wrongEffort.ok, false)
|
|
417
|
-
assert.equal(wrongEffort.code, 'pinned-implementer-unavailable')
|
|
418
|
-
})
|
|
419
|
-
|
|
420
|
-
test('an unavailable pinned implementer blocks instead of falling back', () => {
|
|
421
|
-
const result = pinRun('cory-model')
|
|
422
|
-
assert.equal(result.ok, false)
|
|
423
|
-
assert.equal(result.code, 'pinned-implementer-unavailable')
|
|
424
|
-
assert.equal(result.implementer, null)
|
|
425
|
-
assert.equal(result.ask, null)
|
|
426
|
-
assert.match(result.reason, /never substitute/)
|
|
427
|
-
})
|
|
428
|
-
|
|
429
|
-
test('no pin keeps the recommendation and the full option list', () => {
|
|
430
|
-
const result = pinRun(null)
|
|
431
|
-
assert.equal(result.pinned, undefined)
|
|
432
|
-
assert.equal(result.implementer.key, 'gpt-6.1-sol@high')
|
|
433
|
-
assert.ok(result.ask.options.length > 1)
|
|
434
|
-
assert.equal(result.ask.pinned, undefined)
|
|
435
|
-
})
|
|
436
|
-
|
|
437
|
-
test('CLI exits 0 with the unavailable pin in the output and rejects an empty one with 2', () => {
|
|
438
|
-
const script = fileURLToPath(new URL('./preflight-models.mjs', import.meta.url))
|
|
439
|
-
const run = (extra) => spawnSync(process.execPath, [
|
|
440
|
-
script, '--harness', 'pi', '--available', 'openai/gpt-5.6-terra', ...extra,
|
|
441
|
-
], { encoding: 'utf8' })
|
|
442
|
-
const missing = run(['--implementer', 'openai/not-a-model'])
|
|
443
|
-
assert.equal(missing.status, 0, missing.stderr)
|
|
444
|
-
assert.equal(JSON.parse(missing.stdout).ok, false)
|
|
445
|
-
assert.equal(JSON.parse(missing.stdout).code, 'pinned-implementer-unavailable')
|
|
446
|
-
assert.equal(run(['--implementer=']).status, 2)
|
|
447
|
-
assert.equal(run(['--implementer']).status, 2, 'a flag with no value never falls back to the recommendation')
|
|
448
|
-
})
|