@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.
- package/CHANGELOG.md +28 -1
- package/README.md +81 -22
- package/THIRD_PARTY_NOTICES.md +15 -11
- package/dist/cli.js +2 -0
- package/dist/cli.js.map +1 -1
- package/dist/config/verification-policy.d.ts +20 -0
- package/dist/config/verification-policy.d.ts.map +1 -0
- package/dist/config/verification-policy.js +59 -0
- package/dist/config/verification-policy.js.map +1 -0
- package/dist/doctor/installation.d.ts.map +1 -1
- package/dist/doctor/installation.js +46 -3
- package/dist/doctor/installation.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/installer/adaptive-templates.d.ts +9 -6
- package/dist/installer/adaptive-templates.d.ts.map +1 -1
- package/dist/installer/adaptive-templates.js +13 -0
- package/dist/installer/adaptive-templates.js.map +1 -1
- package/dist/installer/index.d.ts +1 -1
- package/dist/installer/index.d.ts.map +1 -1
- package/dist/installer/index.js +1 -1
- package/dist/installer/index.js.map +1 -1
- package/dist/installer/init.d.ts +1 -1
- package/dist/installer/init.d.ts.map +1 -1
- package/dist/installer/init.js.map +1 -1
- package/dist/installer/install-manifest.d.ts.map +1 -1
- package/dist/installer/install-manifest.js +13 -1
- package/dist/installer/install-manifest.js.map +1 -1
- package/dist/installer/opencode-config.d.ts +3 -4
- package/dist/installer/opencode-config.d.ts.map +1 -1
- package/dist/installer/opencode-config.js +1 -3
- package/dist/installer/opencode-config.js.map +1 -1
- package/dist/installer/upgrade.d.ts.map +1 -1
- package/dist/installer/upgrade.js +34 -2
- package/dist/installer/upgrade.js.map +1 -1
- package/dist/plugin/index.d.ts +2 -0
- package/dist/plugin/index.d.ts.map +1 -1
- package/dist/plugin/index.js +32 -0
- package/dist/plugin/index.js.map +1 -1
- package/docs/MIGRATION.md +27 -10
- package/docs/SECURITY.md +24 -7
- package/docs/TROUBLESHOOTING.md +13 -6
- package/package.json +3 -1
- package/resources/third-party/superpowers-v6.2.0/LICENSE +21 -0
- package/resources/third-party/superpowers-v6.2.0/PROVENANCE.md +21 -0
- package/resources/third-party/superpowers-v6.2.0/skills/android-orchestrator-brainstorming/SKILL.md +43 -0
- package/resources/third-party/superpowers-v6.2.0/skills/android-orchestrator-systematic-debugging/SKILL.md +288 -0
- package/resources/third-party/superpowers-v6.2.0/skills/android-orchestrator-systematic-debugging/references/condition-based-waiting-example.ts +158 -0
- package/resources/third-party/superpowers-v6.2.0/skills/android-orchestrator-systematic-debugging/references/condition-based-waiting.md +115 -0
- package/resources/third-party/superpowers-v6.2.0/skills/android-orchestrator-systematic-debugging/references/defense-in-depth.md +122 -0
- package/resources/third-party/superpowers-v6.2.0/skills/android-orchestrator-systematic-debugging/references/root-cause-tracing.md +169 -0
- package/resources/third-party/superpowers-v6.2.0/skills/android-orchestrator-systematic-debugging/scripts/find-polluter.sh +72 -0
- package/resources/third-party/superpowers-v6.2.0/skills/android-orchestrator-test-driven-development/SKILL.md +327 -0
- package/resources/third-party/superpowers-v6.2.0/skills/android-orchestrator-test-driven-development/references/writing-good-tests.md +197 -0
- package/resources/third-party/superpowers-v6.2.0/skills/android-orchestrator-verification-before-completion/SKILL.md +125 -0
- package/resources/third-party/superpowers-v6.2.0/skills/android-orchestrator-writing-plans/SKILL.md +50 -0
- package/templates/.opencode/agents/scheduled-coder.md +3 -4
- package/templates/.opencode/agents/scheduled-planner.md +5 -5
- package/templates/.opencode/agents/scheduled-reviewer.md +1 -2
- package/templates/.opencode/skills/scheduled-quality-coder/SKILL.md +11 -9
- package/templates/.opencode/skills/scheduled-quality-orchestrator/SKILL.md +2 -1
- package/templates/.opencode/skills/scheduled-quality-reviewer/SKILL.md +4 -3
- package/templates/README.md +10 -3
- package/templates/automation/config.json +8 -9
- package/templates/automation/config.schema.json +6 -11
- package/templates/automation/task-contract.schema.json +7 -7
- package/templates/automation/tasks/TASK-TEMPLATE.json.example +6 -6
- package/templates/scripts/automation/claim-task.sh +23 -8
- package/templates/scripts/automation/lib.sh +37 -3
- package/templates/scripts/automation/orchestrate-task.sh +1 -1
- package/templates/scripts/automation/preflight.sh +0 -3
- package/templates/scripts/automation/tests/run-tests.sh +36 -15
- package/templates/scripts/automation/validate-contract.sh +7 -2
- package/templates/scripts/automation/verify-integration.sh +2 -9
- 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:
|
|
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
|
-
"
|
|
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":
|
|
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
|
-
"
|
|
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":
|
|
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
|
-
"
|
|
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
|
-
"
|
|
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
|
-
|
|
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
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 ==
|
|
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
|
|
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:
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
(.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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"
|