@frankzhang2026/opencode-android-orchestrator 0.6.1 → 0.8.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 (77) hide show
  1. package/CHANGELOG.md +28 -1
  2. package/README.md +81 -22
  3. package/THIRD_PARTY_NOTICES.md +15 -11
  4. package/dist/cli.js +2 -0
  5. package/dist/cli.js.map +1 -1
  6. package/dist/config/verification-policy.d.ts +20 -0
  7. package/dist/config/verification-policy.d.ts.map +1 -0
  8. package/dist/config/verification-policy.js +59 -0
  9. package/dist/config/verification-policy.js.map +1 -0
  10. package/dist/doctor/installation.d.ts.map +1 -1
  11. package/dist/doctor/installation.js +46 -3
  12. package/dist/doctor/installation.js.map +1 -1
  13. package/dist/index.d.ts +2 -2
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +2 -2
  16. package/dist/index.js.map +1 -1
  17. package/dist/installer/adaptive-templates.d.ts +9 -6
  18. package/dist/installer/adaptive-templates.d.ts.map +1 -1
  19. package/dist/installer/adaptive-templates.js +13 -0
  20. package/dist/installer/adaptive-templates.js.map +1 -1
  21. package/dist/installer/index.d.ts +1 -1
  22. package/dist/installer/index.d.ts.map +1 -1
  23. package/dist/installer/index.js +1 -1
  24. package/dist/installer/index.js.map +1 -1
  25. package/dist/installer/init.d.ts +1 -1
  26. package/dist/installer/init.d.ts.map +1 -1
  27. package/dist/installer/init.js.map +1 -1
  28. package/dist/installer/install-manifest.d.ts.map +1 -1
  29. package/dist/installer/install-manifest.js +13 -1
  30. package/dist/installer/install-manifest.js.map +1 -1
  31. package/dist/installer/opencode-config.d.ts +3 -4
  32. package/dist/installer/opencode-config.d.ts.map +1 -1
  33. package/dist/installer/opencode-config.js +1 -3
  34. package/dist/installer/opencode-config.js.map +1 -1
  35. package/dist/installer/upgrade.d.ts.map +1 -1
  36. package/dist/installer/upgrade.js +34 -2
  37. package/dist/installer/upgrade.js.map +1 -1
  38. package/dist/plugin/index.d.ts +2 -0
  39. package/dist/plugin/index.d.ts.map +1 -1
  40. package/dist/plugin/index.js +32 -0
  41. package/dist/plugin/index.js.map +1 -1
  42. package/docs/MIGRATION.md +27 -10
  43. package/docs/SECURITY.md +24 -7
  44. package/docs/TROUBLESHOOTING.md +13 -6
  45. package/package.json +3 -1
  46. package/resources/third-party/superpowers-v6.2.0/LICENSE +21 -0
  47. package/resources/third-party/superpowers-v6.2.0/PROVENANCE.md +21 -0
  48. package/resources/third-party/superpowers-v6.2.0/skills/android-orchestrator-brainstorming/SKILL.md +43 -0
  49. package/resources/third-party/superpowers-v6.2.0/skills/android-orchestrator-systematic-debugging/SKILL.md +288 -0
  50. package/resources/third-party/superpowers-v6.2.0/skills/android-orchestrator-systematic-debugging/references/condition-based-waiting-example.ts +158 -0
  51. package/resources/third-party/superpowers-v6.2.0/skills/android-orchestrator-systematic-debugging/references/condition-based-waiting.md +115 -0
  52. package/resources/third-party/superpowers-v6.2.0/skills/android-orchestrator-systematic-debugging/references/defense-in-depth.md +122 -0
  53. package/resources/third-party/superpowers-v6.2.0/skills/android-orchestrator-systematic-debugging/references/root-cause-tracing.md +169 -0
  54. package/resources/third-party/superpowers-v6.2.0/skills/android-orchestrator-systematic-debugging/scripts/find-polluter.sh +72 -0
  55. package/resources/third-party/superpowers-v6.2.0/skills/android-orchestrator-test-driven-development/SKILL.md +327 -0
  56. package/resources/third-party/superpowers-v6.2.0/skills/android-orchestrator-test-driven-development/references/writing-good-tests.md +197 -0
  57. package/resources/third-party/superpowers-v6.2.0/skills/android-orchestrator-verification-before-completion/SKILL.md +125 -0
  58. package/resources/third-party/superpowers-v6.2.0/skills/android-orchestrator-writing-plans/SKILL.md +50 -0
  59. package/templates/.opencode/agents/scheduled-coder.md +3 -4
  60. package/templates/.opencode/agents/scheduled-planner.md +5 -5
  61. package/templates/.opencode/agents/scheduled-reviewer.md +1 -2
  62. package/templates/.opencode/skills/scheduled-quality-coder/SKILL.md +11 -9
  63. package/templates/.opencode/skills/scheduled-quality-orchestrator/SKILL.md +2 -1
  64. package/templates/.opencode/skills/scheduled-quality-reviewer/SKILL.md +4 -3
  65. package/templates/README.md +10 -3
  66. package/templates/automation/config.json +8 -9
  67. package/templates/automation/config.schema.json +6 -11
  68. package/templates/automation/task-contract.schema.json +7 -7
  69. package/templates/automation/tasks/TASK-TEMPLATE.json.example +6 -6
  70. package/templates/scripts/automation/claim-task.sh +23 -8
  71. package/templates/scripts/automation/lib.sh +37 -3
  72. package/templates/scripts/automation/orchestrate-task.sh +1 -1
  73. package/templates/scripts/automation/preflight.sh +0 -3
  74. package/templates/scripts/automation/tests/run-tests.sh +36 -15
  75. package/templates/scripts/automation/validate-contract.sh +7 -2
  76. package/templates/scripts/automation/verify-integration.sh +2 -9
  77. package/templates/scripts/automation/verify-task.sh +2 -9
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$schema": "https://json-schema.org/draft/2020-12/schema",
3
- "$id": "urn:frankzhang2026:opencode-android-orchestrator:task-contract:v1",
3
+ "$id": "urn:frankzhang2026:opencode-android-orchestrator:task-contract:v2",
4
4
  "title": "Scheduled coding task contract",
5
5
  "type": "object",
6
6
  "additionalProperties": false,
@@ -27,7 +27,7 @@
27
27
  "maxChangedFiles",
28
28
  "allowedPaths",
29
29
  "forbiddenPaths",
30
- "allowedSuperpowers",
30
+ "allowedWorkflowSkills",
31
31
  "acceptanceCriteria",
32
32
  "nonGoals",
33
33
  "targetTests",
@@ -35,7 +35,7 @@
35
35
  "testPolicy"
36
36
  ],
37
37
  "properties": {
38
- "schemaVersion": { "const": 1 },
38
+ "schemaVersion": { "const": 2 },
39
39
  "id": { "type": "string", "pattern": "^TASK-[A-Z0-9-]+$" },
40
40
  "title": { "type": "string", "minLength": 1 },
41
41
  "designApproved": { "const": true },
@@ -53,12 +53,12 @@
53
53
  "minItems": 1,
54
54
  "items": { "type": "string", "minLength": 1 }
55
55
  },
56
- "allowedSuperpowers": {
56
+ "allowedWorkflowSkills": {
57
57
  "type": "array",
58
58
  "const": [
59
- "test-driven-development",
60
- "systematic-debugging",
61
- "verification-before-completion"
59
+ "android-orchestrator-test-driven-development",
60
+ "android-orchestrator-systematic-debugging",
61
+ "android-orchestrator-verification-before-completion"
62
62
  ]
63
63
  },
64
64
  "acceptanceCriteria": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "schemaVersion": 1,
2
+ "schemaVersion": 2,
3
3
  "id": "TASK-EXAMPLE-001",
4
4
  "title": "Replace with one small, observable behavior change",
5
5
  "designApproved": true,
@@ -31,15 +31,15 @@
31
31
  "**/build.gradle",
32
32
  "**/build.gradle.kts"
33
33
  ],
34
- "allowedSuperpowers": [
35
- "test-driven-development",
36
- "systematic-debugging",
37
- "verification-before-completion"
34
+ "allowedWorkflowSkills": [
35
+ "android-orchestrator-test-driven-development",
36
+ "android-orchestrator-systematic-debugging",
37
+ "android-orchestrator-verification-before-completion"
38
38
  ],
39
39
  "acceptanceCriteria": [
40
40
  "Replace with an observable input/output or UI behavior",
41
41
  "A focused test demonstrates the behavior and is captured RED before implementation",
42
- "Unit tests, debug build, and lint all pass"
42
+ "Debug build passes; unit tests and Android lint also pass when their configuration flags are enabled"
43
43
  ],
44
44
  "nonGoals": [
45
45
  "Do not refactor unrelated screens",
@@ -30,12 +30,21 @@ baseline_meta="$evidence_dir/baseline.json"
30
30
  protected_hashes="$evidence_dir/protected.sha256"
31
31
  started_at="$(automation_now)"
32
32
  head_commit="$(git -C "$AUTOMATION_ROOT" rev-parse HEAD)"
33
- baseline_command="$(automation_gradle_group_command_json "fullUnitTestTasks")"
33
+ unit_tests_enabled="$(automation_config_value '.unitTestsEnabled')"
34
+ baseline_command='[]'
35
+ if [[ "$unit_tests_enabled" == "true" ]]; then
36
+ baseline_command="$(automation_gradle_group_command_json "fullUnitTestTasks")"
37
+ fi
34
38
 
35
- set +e
36
- automation_run_gradle_group "fullUnitTestTasks" "$AUTOMATION_ROOT" 2>&1 | tee "$baseline_log"
37
- baseline_status=${PIPESTATUS[0]}
38
- set -e
39
+ if [[ "$unit_tests_enabled" == "true" ]]; then
40
+ set +e
41
+ automation_run_gradle_group "fullUnitTestTasks" "$AUTOMATION_ROOT" 2>&1 | tee "$baseline_log"
42
+ baseline_status=${PIPESTATUS[0]}
43
+ set -e
44
+ else
45
+ automation_info "skipping baseline unit tests (unitTestsEnabled=false)" | tee "$baseline_log"
46
+ baseline_status=0
47
+ fi
39
48
 
40
49
  if [[ "$baseline_status" -ne 0 ]]; then
41
50
  jq -n \
@@ -44,8 +53,9 @@ if [[ "$baseline_status" -ne 0 ]]; then
44
53
  --arg finishedAt "$(automation_now)" \
45
54
  --arg head "$head_commit" \
46
55
  --argjson command "$baseline_command" \
56
+ --argjson unitTestsEnabled "$unit_tests_enabled" \
47
57
  --argjson exitCode "$baseline_status" \
48
- '{taskId: $taskId, startedAt: $startedAt, finishedAt: $finishedAt, head: $head, command: $command, exitCode: $exitCode}' \
58
+ '{taskId: $taskId, startedAt: $startedAt, finishedAt: $finishedAt, head: $head, command: $command, unitTestsEnabled: $unitTestsEnabled, exitCode: $exitCode}' \
49
59
  | automation_record_json "$baseline_meta"
50
60
  automation_transition_state "$task_id" "CODING" "BLOCKED" "preflight" "baseline unit tests failed"
51
61
  automation_die "baseline unit tests failed"
@@ -68,7 +78,12 @@ jq -n \
68
78
  --arg head "$head_commit" \
69
79
  --arg worktree "$AUTOMATION_ROOT" \
70
80
  --argjson command "$baseline_command" \
71
- '{taskId: $taskId, startedAt: $startedAt, finishedAt: $finishedAt, head: $head, worktree: $worktree, command: $command, exitCode: 0}' \
81
+ --argjson unitTestsEnabled "$unit_tests_enabled" \
82
+ '{taskId: $taskId, startedAt: $startedAt, finishedAt: $finishedAt, head: $head, worktree: $worktree, command: $command, unitTestsEnabled: $unitTestsEnabled, exitCode: 0}' \
72
83
  | automation_record_json "$baseline_meta"
73
84
 
74
- automation_info "$task_id claimed; baseline is green"
85
+ if [[ "$unit_tests_enabled" == "true" ]]; then
86
+ automation_info "$task_id claimed; baseline is green"
87
+ else
88
+ automation_info "$task_id claimed; baseline unit tests were disabled by configuration"
89
+ fi
@@ -111,7 +111,7 @@ automation_validate_config() {
111
111
  length > 0 and
112
112
  length == (unique | length) and
113
113
  all(.[]; gradle_task);
114
- .schemaVersion == 3 and
114
+ .schemaVersion == 4 and
115
115
  (.enabled | type == "boolean") and
116
116
  (.mode == "shadow" or .mode == "orchestrated") and
117
117
  (.workspaceStrategy == "inPlaceExclusive" or .workspaceStrategy == "isolatedWorktree") and
@@ -120,6 +120,8 @@ automation_validate_config() {
120
120
  (.maxFixLoops | type == "number" and . >= 0 and . <= 1 and floor == .) and
121
121
  (.maxReviewCycles | type == "number" and . >= 0 and . <= 2 and floor == .) and
122
122
  (.maxReviewerRestarts | type == "number" and . >= 0 and . <= 3 and floor == .) and
123
+ (.unitTestsEnabled | type == "boolean") and
124
+ (.lintEnabled | type == "boolean") and
123
125
  (.longCommandTimeoutMs | type == "number" and . >= 120000 and . <= 7200000 and floor == .) and
124
126
  (.autoCleanupWorktrees | type == "boolean") and
125
127
  .pushAfterAcceptance == false and
@@ -128,8 +130,6 @@ automation_validate_config() {
128
130
  (.approvalPhrases.acceptance | type == "string" and length >= 4) and
129
131
  (.approvalPhrases.abort | type == "string" and length >= 4) and
130
132
  (.approvalPhrases.resume | type == "string" and length >= 4) and
131
- (.plugins | type == "object" and keys == ["superpowers"]) and
132
- (.plugins.superpowers | type == "string" and length > 0) and
133
133
  (.requiredSkills | type == "array" and length >= 6) and
134
134
  (.gradleVerification as $verification |
135
135
  ($verification | type == "object") and
@@ -302,6 +302,40 @@ automation_run_gradle_group() {
302
302
  )
303
303
  }
304
304
 
305
+ automation_run_configured_unit_tests() {
306
+ local contract="${1:-}"
307
+ local root="${2:-$AUTOMATION_ROOT}"
308
+ local context="${3:-}"
309
+
310
+ [[ -n "$contract" && -f "$contract" ]] || automation_die "unit-test contract does not exist: $contract"
311
+ automation_validate_config || return 1
312
+ if [[ "$(automation_config_value '.unitTestsEnabled')" != "true" ]]; then
313
+ automation_info "skipping ${context}unit tests (unitTestsEnabled=false)"
314
+ return 0
315
+ fi
316
+
317
+ while IFS=$'\t' read -r gradle_task filter; do
318
+ automation_info "running ${context}focused test ($gradle_task): $filter"
319
+ automation_run_focused_test "$gradle_task" "$filter" "$root"
320
+ done < <(jq -r '.targetTests[] | [.gradleTask, .filter] | @tsv' "$contract")
321
+
322
+ automation_info "running ${context}full unit tests"
323
+ automation_run_gradle_group "fullUnitTestTasks" "$root"
324
+ }
325
+
326
+ automation_run_configured_lint() {
327
+ local root="${1:-$AUTOMATION_ROOT}"
328
+
329
+ automation_validate_config || return 1
330
+ if [[ "$(automation_config_value '.lintEnabled')" != "true" ]]; then
331
+ automation_info "skipping Android lint (lintEnabled=false)"
332
+ return 0
333
+ fi
334
+
335
+ automation_info "running configured Android lint tasks"
336
+ automation_run_gradle_group "lintTasks" "$root"
337
+ }
338
+
305
339
  automation_run_focused_test() {
306
340
  local task="$1"
307
341
  local filter="$2"
@@ -86,7 +86,7 @@ for _step in 1 2 3 4 5 6 7 8; do
86
86
  if [[ -f "$agent_runs" ]]; then
87
87
  review_attempt="$(jq -s --argjson cycle "$review_cycle" '[.[] | select(.role == "scheduled-reviewer" and .cycle == $cycle)] | length' "$agent_runs")"
88
88
  fi
89
- reviewer_prompt="Use \$scheduled-quality-reviewer with $task_id. This is fresh, non-interactive, read-only review attempt $review_attempt for sealed review cycle $review_cycle. Work within the step budget. Run exactly ./scripts/automation/status.sh $task_id once; its JSON already includes baseline, RED, ready, latest gate, current diff SHA, the sealed-SHA comparison, and runtime.effectiveWorktreeAllowlist, so do not browse the external evidence directory. Then inspect the approved contract and run exactly git diff, excluding the control file and every exact path in that effective list from review findings. Submit exactly one decision. Do not browse generated build reports, list the whole repository, retry denied command variants, or run Gradle commands separately before deciding: submit-review.sh performs and records the focused tests, full unit suite, assembleDebug, and lint for APPROVED. Reserve a tool call for submit-review.sh. Never edit, commit, merge, or push."
89
+ reviewer_prompt="Use \$scheduled-quality-reviewer with $task_id. This is fresh, non-interactive, read-only review attempt $review_attempt for sealed review cycle $review_cycle. Work within the step budget. Run exactly ./scripts/automation/status.sh $task_id once; its JSON already includes baseline, RED, ready, latest gate, current diff SHA, the sealed-SHA comparison, and runtime.effectiveWorktreeAllowlist, so do not browse the external evidence directory. Then inspect the approved contract and run exactly git diff, excluding the control file and every exact path in that effective list from review findings. Submit exactly one decision. Do not browse generated build reports, list the whole repository, retry denied command variants, or run Gradle commands separately before deciding: submit-review.sh performs and records focused and full unit tests when unitTestsEnabled is true, always runs assembleDebug, and runs Android lint when lintEnabled is true for APPROVED. Reserve a tool call for submit-review.sh. Never edit, commit, merge, or push."
90
90
  run_agent scheduled-reviewer "$reviewer_prompt" "$review_cycle" "$review_attempt" || true
91
91
  if [[ "$(automation_read_state "$task_id")" == "REVIEWING" ]]; then
92
92
  automation_transition_state "$task_id" "REVIEWING" "BLOCKED" "orchestrator" "reviewer exited without submitting a decision; sealed diff preserved for reviewer-only recovery"
@@ -127,9 +127,6 @@ else
127
127
  if ! automation_resolve_opencode_config "$discovery_dir/config.json" "$discovery_dir/config.err"; then
128
128
  automation_die "OpenCode resolved config failed; see $discovery_dir/config.err"
129
129
  fi
130
- superpowers_pin="$(jq -r '.plugins.superpowers' "$AUTOMATION_CONFIG")"
131
- rg -F "$superpowers_pin" "$discovery_dir/config.json" >/dev/null || automation_die "resolved OpenCode config is missing pinned Superpowers"
132
-
133
130
  if ! opencode debug skill > "$discovery_dir/skills.txt" 2> "$discovery_dir/skills.err"; then
134
131
  automation_die "OpenCode skill discovery failed; see $discovery_dir/skills.err"
135
132
  fi
@@ -110,7 +110,7 @@ printf '%s\n' \
110
110
  chmod +x "$fixture/gradlew"
111
111
 
112
112
  jq -n '{
113
- schemaVersion: 3,
113
+ schemaVersion: 4,
114
114
  enabled: true,
115
115
  mode: "orchestrated",
116
116
  workspaceStrategy: "inPlaceExclusive",
@@ -119,6 +119,8 @@ jq -n '{
119
119
  maxFixLoops: 1,
120
120
  maxReviewCycles: 1,
121
121
  maxReviewerRestarts: 2,
122
+ unitTestsEnabled: true,
123
+ lintEnabled: false,
122
124
  longCommandTimeoutMs: 1800000,
123
125
  autoCleanupWorktrees: true,
124
126
  pushAfterAcceptance: false,
@@ -129,18 +131,15 @@ jq -n '{
129
131
  abort: "中止任务,封存修改并恢复原分支。",
130
132
  resume: "恢复任务,重新捕获基线并继续自动执行。"
131
133
  },
132
- plugins: {
133
- superpowers: "superpowers@git+https://github.com/obra/superpowers.git#v6.2.0"
134
- },
135
134
  requiredSkills: [
136
- "brainstorming",
137
- "writing-plans",
135
+ "android-orchestrator-brainstorming",
136
+ "android-orchestrator-writing-plans",
138
137
  "scheduled-quality-orchestrator",
139
138
  "scheduled-quality-coder",
140
139
  "scheduled-quality-reviewer",
141
- "test-driven-development",
142
- "systematic-debugging",
143
- "verification-before-completion"
140
+ "android-orchestrator-test-driven-development",
141
+ "android-orchestrator-systematic-debugging",
142
+ "android-orchestrator-verification-before-completion"
144
143
  ],
145
144
  gradleVerification: {
146
145
  fullUnitTestTasks: ["testDebugUnitTest"],
@@ -193,7 +192,7 @@ jq -n '{
193
192
  }' > "$fixture/automation/config.json"
194
193
 
195
194
  jq -n '{
196
- schemaVersion: 1,
195
+ schemaVersion: 2,
197
196
  id: "TASK-TEST-001",
198
197
  title: "Add an observable greeting behavior",
199
198
  designApproved: true,
@@ -225,10 +224,10 @@ jq -n '{
225
224
  "**/build.gradle.kts",
226
225
  "mobile-client/build.gradle.kts"
227
226
  ],
228
- allowedSuperpowers: [
229
- "test-driven-development",
230
- "systematic-debugging",
231
- "verification-before-completion"
227
+ allowedWorkflowSkills: [
228
+ "android-orchestrator-test-driven-development",
229
+ "android-orchestrator-systematic-debugging",
230
+ "android-orchestrator-verification-before-completion"
232
231
  ],
233
232
  acceptanceCriteria: ["Greeting returns the approved value"],
234
233
  nonGoals: ["No unrelated refactoring"],
@@ -319,7 +318,29 @@ printf '%s\n' \
319
318
  pass 'invalid, duplicate, symbolic-link, patterned, and protected allowlist input fails closed'
320
319
 
321
320
  run_fixture ./scripts/automation/validate-contract.sh TASK-TEST-001 >/dev/null
322
- pass 'valid version-3 configuration and task contract are accepted'
321
+ verification_config_backup="$(mktemp "$runtime_root/config.json.XXXXXX")"
322
+ cp "$fixture/automation/config.json" "$verification_config_backup"
323
+
324
+ unit_enabled_output="$(run_fixture env AUTOMATION_FAKE_GREEN=1 bash -c 'source ./scripts/automation/lib.sh; automation_run_configured_unit_tests ./automation/tasks/TASK-TEST-001.json')"
325
+ [[ "$unit_enabled_output" == *"running focused test"* ]] || fail 'default unit-test policy did not run the focused test'
326
+ [[ "$unit_enabled_output" == *"running full unit tests"* ]] || fail 'default unit-test policy did not run the full unit-test group'
327
+ [[ "$unit_enabled_output" == *"BUILD SUCCESSFUL"* ]] || fail 'enabled unit-test policy did not execute configured tests'
328
+ jq '.unitTestsEnabled = false' "$verification_config_backup" > "$fixture/automation/config.json"
329
+ unit_disabled_output="$(run_fixture bash -c 'source ./scripts/automation/lib.sh; automation_run_configured_unit_tests ./automation/tasks/TASK-TEST-001.json')"
330
+ [[ "$unit_disabled_output" == *"skipping unit tests (unitTestsEnabled=false)"* ]] || fail 'disabled unit-test policy did not skip verification'
331
+ [[ "$unit_disabled_output" != *"BUILD SUCCESSFUL"* ]] || fail 'disabled unit-test policy executed a configured test'
332
+ cp "$verification_config_backup" "$fixture/automation/config.json"
333
+
334
+ lint_disabled_output="$(run_fixture bash -c 'source ./scripts/automation/lib.sh; automation_run_configured_lint')"
335
+ [[ "$lint_disabled_output" == *"skipping Android lint (lintEnabled=false)"* ]] || fail 'default lint policy did not skip Android lint'
336
+ jq '.lintEnabled = true' "$verification_config_backup" > "$fixture/automation/config.json"
337
+ lint_enabled_output="$(run_fixture bash -c 'source ./scripts/automation/lib.sh; automation_run_configured_lint')"
338
+ [[ "$lint_enabled_output" == *"running configured Android lint tasks"* ]] || fail 'enabled lint policy did not run Android lint'
339
+ [[ "$lint_enabled_output" == *"BUILD SUCCESSFUL"* ]] || fail 'enabled lint policy did not execute the configured lint task'
340
+ cp "$verification_config_backup" "$fixture/automation/config.json"
341
+ rm "$verification_config_backup"
342
+ run_fixture ./scripts/automation/validate-contract.sh TASK-TEST-001 >/dev/null
343
+ pass 'repository configuration defaults unit tests on and lint off and honors both switches'
323
344
 
324
345
  if run_fixture env AUTOMATION_HUMAN_APPROVED=0 ./scripts/automation/queue-task.sh TASK-TEST-001 >/dev/null 2>&1; then
325
346
  fail 'legacy queue accepted without explicit human approval'
@@ -27,7 +27,7 @@ fi
27
27
  jq -e . "$contract" >/dev/null || automation_die "contract is not valid JSON: $contract"
28
28
 
29
29
  jq -e '
30
- .schemaVersion == 1 and
30
+ (.schemaVersion == 1 or .schemaVersion == 2) and
31
31
  (.id | type == "string" and test("^TASK-[A-Z0-9-]+$")) and
32
32
  (.title | type == "string" and length > 0) and
33
33
  .designApproved == true and
@@ -37,7 +37,12 @@ jq -e '
37
37
  (.maxChangedFiles | type == "number" and . >= 1 and . <= 12 and floor == .) and
38
38
  (.allowedPaths | type == "array" and length > 0) and
39
39
  (.forbiddenPaths | type == "array" and length > 0) and
40
- (.allowedSuperpowers == ["test-driven-development", "systematic-debugging", "verification-before-completion"]) and
40
+ (if .schemaVersion == 1 then
41
+ .allowedSuperpowers == ["test-driven-development", "systematic-debugging", "verification-before-completion"]
42
+ else
43
+ .allowedWorkflowSkills == ["android-orchestrator-test-driven-development", "android-orchestrator-systematic-debugging", "android-orchestrator-verification-before-completion"] and
44
+ (has("allowedSuperpowers") | not)
45
+ end) and
41
46
  (.acceptanceCriteria | type == "array" and length > 0) and
42
47
  (.nonGoals | type == "array" and length > 0) and
43
48
  (.targetTests | type == "array" and length > 0 and all(.[];
@@ -16,19 +16,12 @@ contract="$(automation_contract_path "$task_id")"
16
16
 
17
17
  "$SCRIPT_DIR/integration-scope-gate.sh" "$task_id" "$base" "$head"
18
18
 
19
- while IFS=$'\t' read -r gradle_task filter; do
20
- automation_info "running integration focused test ($gradle_task): $filter"
21
- automation_run_focused_test "$gradle_task" "$filter" "$AUTOMATION_ROOT"
22
- done < <(jq -r '.targetTests[] | [.gradleTask, .filter] | @tsv' "$contract")
23
-
24
- automation_info "running integration full unit tests"
25
- automation_run_gradle_group "fullUnitTestTasks" "$AUTOMATION_ROOT"
19
+ automation_run_configured_unit_tests "$contract" "$AUTOMATION_ROOT" "integration "
26
20
 
27
21
  automation_info "running configured integration assemble tasks"
28
22
  automation_run_gradle_group "assembleTasks" "$AUTOMATION_ROOT"
29
23
 
30
- automation_info "running configured integration Android lint tasks"
31
- automation_run_gradle_group "lintTasks" "$AUTOMATION_ROOT"
24
+ automation_run_configured_lint "$AUTOMATION_ROOT"
32
25
 
33
26
  if [[ "$(jq -r '.deviceTestsRequired' "$contract")" == "true" ]]; then
34
27
  automation_info "running configured integration device tests"
@@ -17,19 +17,12 @@ evidence_dir="$(automation_evidence_path "$task_id")"
17
17
 
18
18
  "$SCRIPT_DIR/scope-gate.sh" "$task_id"
19
19
 
20
- while IFS=$'\t' read -r gradle_task filter; do
21
- automation_info "running focused test ($gradle_task): $filter"
22
- automation_run_focused_test "$gradle_task" "$filter" "$AUTOMATION_ROOT"
23
- done < <(jq -r '.targetTests[] | [.gradleTask, .filter] | @tsv' "$contract")
24
-
25
- automation_info "running full unit tests"
26
- automation_run_gradle_group "fullUnitTestTasks" "$AUTOMATION_ROOT"
20
+ automation_run_configured_unit_tests "$contract" "$AUTOMATION_ROOT"
27
21
 
28
22
  automation_info "running configured assemble tasks"
29
23
  automation_run_gradle_group "assembleTasks" "$AUTOMATION_ROOT"
30
24
 
31
- automation_info "running configured Android lint tasks"
32
- automation_run_gradle_group "lintTasks" "$AUTOMATION_ROOT"
25
+ automation_run_configured_lint "$AUTOMATION_ROOT"
33
26
 
34
27
  if [[ "$(jq -r '.deviceTestsRequired' "$contract")" == "true" ]]; then
35
28
  automation_info "running configured device tests"