@guilz-dev/sdlc-gh 0.1.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 (176) hide show
  1. package/.github/CODEOWNERS +5 -0
  2. package/.github/ISSUE_TEMPLATE/bug_report.yml +68 -0
  3. package/.github/ISSUE_TEMPLATE/config.yml +1 -0
  4. package/.github/ISSUE_TEMPLATE/feature_request.yml +39 -0
  5. package/.github/ISSUE_TEMPLATE/support.yml +56 -0
  6. package/.github/ISSUE_TEMPLATE/task.yml +89 -0
  7. package/.github/agents/implementer.agent.md +17 -0
  8. package/.github/agents/reviewer.agent.md +18 -0
  9. package/.github/agents/triager.agent.md +13 -0
  10. package/.github/aw/actions-lock.json +9 -0
  11. package/.github/copilot-instructions.md +35 -0
  12. package/.github/hooks/hooks.json +12 -0
  13. package/.github/instructions/core.instructions.md +11 -0
  14. package/.github/instructions/profiles/go.instructions.md +10 -0
  15. package/.github/instructions/profiles/php.instructions.md +11 -0
  16. package/.github/instructions/profiles/python.instructions.md +11 -0
  17. package/.github/instructions/profiles/ruby.instructions.md +11 -0
  18. package/.github/instructions/profiles/typescript.instructions.md +11 -0
  19. package/.github/labels.yml +55 -0
  20. package/.github/pull_request_template.md +33 -0
  21. package/.github/ruleset.example.json +33 -0
  22. package/.github/ruleset.harness-eval.example.json +29 -0
  23. package/.github/skills/quality-loop/SKILL.md +23 -0
  24. package/.github/workflows/agent-retry-orchestrator.yml +161 -0
  25. package/.github/workflows/copilot-setup-steps.yml +64 -0
  26. package/.github/workflows/eval-ci.yml +169 -0
  27. package/.github/workflows/eval-drift.yml +75 -0
  28. package/.github/workflows/gh-aw-dogfood-ci.yml +73 -0
  29. package/.github/workflows/harness-ci.yml +244 -0
  30. package/.github/workflows/harness-sync.yml +28 -0
  31. package/.github/workflows/l1-readiness-check.yml +45 -0
  32. package/.github/workflows/labels-sync.yml +24 -0
  33. package/.github/workflows/nightly-harness-review.lock.yml +1643 -0
  34. package/.github/workflows/nightly-harness-review.md +87 -0
  35. package/.github/workflows/nightly-harness-review.yml +63 -0
  36. package/.github/workflows/npm-publish.yml +49 -0
  37. package/.github/workflows/pr-context-comment.yml +138 -0
  38. package/.github/workflows/product-ci-go.yml +33 -0
  39. package/.github/workflows/product-ci-php.yml +39 -0
  40. package/.github/workflows/product-ci-python.yml +34 -0
  41. package/.github/workflows/product-ci-ruby.yml +35 -0
  42. package/.github/workflows/product-ci-ts.yml +37 -0
  43. package/.github/workflows/task-issue-label-sync.yml +50 -0
  44. package/.github/workflows/weekly-redteam.lock.yml +1571 -0
  45. package/.github/workflows/weekly-redteam.md +76 -0
  46. package/.github/zizmor.yml +11 -0
  47. package/AGENTS.md +54 -0
  48. package/LICENSE +21 -0
  49. package/README.md +366 -0
  50. package/config/stacks.json +55 -0
  51. package/docs/adoption.md +126 -0
  52. package/docs/arch.md +535 -0
  53. package/docs/auth-boundaries.md +16 -0
  54. package/docs/coding-agent-l1.md +152 -0
  55. package/docs/exceptions/README.md +25 -0
  56. package/docs/exceptions/TEMPLATE.md +8 -0
  57. package/docs/failure-taxonomy.md +23 -0
  58. package/docs/gh-aw-dogfood.md +109 -0
  59. package/docs/kpi-baseline.md +9 -0
  60. package/docs/nightly-harness-review.md +94 -0
  61. package/docs/operations.md +108 -0
  62. package/docs/publishing.md +79 -0
  63. package/docs/revert-playbook.md +44 -0
  64. package/docs/shared-config.md +30 -0
  65. package/docs/telemetry-artifacts.md +78 -0
  66. package/docs/telemetry-schema.md +60 -0
  67. package/evals/.score-baseline.json +6 -0
  68. package/evals/e2e-bench/README.md +28 -0
  69. package/evals/e2e-bench/manifest.json +16 -0
  70. package/evals/e2e-bench/tasks/e2e-001.yml +10 -0
  71. package/evals/e2e-bench/tasks/e2e-002.yml +11 -0
  72. package/evals/e2e-bench/tasks/e2e-003.yml +10 -0
  73. package/evals/e2e-bench/tasks/e2e-004.yml +14 -0
  74. package/evals/e2e-bench/tasks/e2e-005.yml +11 -0
  75. package/evals/e2e-bench/tasks/e2e-006.yml +10 -0
  76. package/evals/e2e-bench/tasks/e2e-007.yml +10 -0
  77. package/evals/e2e-bench/tasks/e2e-008.yml +10 -0
  78. package/evals/e2e-bench/tasks/e2e-009.yml +10 -0
  79. package/evals/trajectories/rubric.md +12 -0
  80. package/evals/trajectories/test_harness_conventions.py +271 -0
  81. package/infra/README.md +49 -0
  82. package/infra/langfuse/docker-compose.yml +25 -0
  83. package/infra/otel/collector-config.yml +24 -0
  84. package/infra/samples/gh-aw-dogfood-report.json +44 -0
  85. package/infra/samples/harness-review-routing-plan.json +19 -0
  86. package/infra/samples/harness-review-summary.json +61 -0
  87. package/infra/samples/telemetry-artifact.json +29 -0
  88. package/infra/samples/telemetry-payload.json +19 -0
  89. package/package.json +85 -0
  90. package/prompts/triager-classify.prompt.yml +10 -0
  91. package/sample/go/add.go +5 -0
  92. package/sample/go/add_test.go +9 -0
  93. package/sample/go/go.mod +3 -0
  94. package/sample/php/composer.json +26 -0
  95. package/sample/php/composer.lock +1881 -0
  96. package/sample/php/phpunit.xml +8 -0
  97. package/sample/php/src/Add.php +13 -0
  98. package/sample/php/tests/AddTest.php +16 -0
  99. package/sample/python/requirements-dev.txt +2 -0
  100. package/sample/python/src/__init__.py +0 -0
  101. package/sample/python/src/greet.py +3 -0
  102. package/sample/python/tests/conftest.py +4 -0
  103. package/sample/python/tests/test_greet.py +5 -0
  104. package/sample/ruby/.rubocop.yml +10 -0
  105. package/sample/ruby/Gemfile +6 -0
  106. package/sample/ruby/Gemfile.lock +58 -0
  107. package/sample/ruby/lib/add.rb +9 -0
  108. package/sample/ruby/spec/add_spec.rb +11 -0
  109. package/sample/ts/biome.json +6 -0
  110. package/sample/ts/package-lock.json +1763 -0
  111. package/sample/ts/package.json +15 -0
  112. package/sample/ts/src/add.ts +3 -0
  113. package/sample/ts/tests/add.test.ts +8 -0
  114. package/sample/ts/tsconfig.json +12 -0
  115. package/scripts/aggregate-harness-review.mjs +48 -0
  116. package/scripts/bootstrap-harness.sh +411 -0
  117. package/scripts/check-diff-size.mjs +46 -0
  118. package/scripts/check-e2e-manifest.mjs +35 -0
  119. package/scripts/check-eval-score-drift.mjs +31 -0
  120. package/scripts/check-gh-aw-dogfood-scope.mjs +51 -0
  121. package/scripts/check-issue-spec.mjs +215 -0
  122. package/scripts/check-l1-readiness.mjs +82 -0
  123. package/scripts/check-open-pr-limit.mjs +34 -0
  124. package/scripts/doctor.mjs +177 -0
  125. package/scripts/emit-gh-aw-dogfood-report.mjs +112 -0
  126. package/scripts/emit-telemetry-artifact.mjs +99 -0
  127. package/scripts/fetch-telemetry-artifacts.mjs +176 -0
  128. package/scripts/harness-drift-report.mjs +99 -0
  129. package/scripts/lib/bootstrap-copy.mjs +123 -0
  130. package/scripts/lib/ccsd-contract.mjs +212 -0
  131. package/scripts/lib/diff-size.mjs +103 -0
  132. package/scripts/lib/doctor-local.mjs +179 -0
  133. package/scripts/lib/e2e-manifest.mjs +76 -0
  134. package/scripts/lib/gh-aw-dogfood.mjs +293 -0
  135. package/scripts/lib/github-config.mjs +94 -0
  136. package/scripts/lib/harness-ci-fragments.mjs +98 -0
  137. package/scripts/lib/harness-review-routing.mjs +244 -0
  138. package/scripts/lib/harness-review.mjs +388 -0
  139. package/scripts/lib/issue-form-label-sync.mjs +56 -0
  140. package/scripts/lib/l1-readiness.mjs +258 -0
  141. package/scripts/lib/merge-harness-package.mjs +36 -0
  142. package/scripts/lib/npm-package.mjs +129 -0
  143. package/scripts/lib/setup-wizard.mjs +224 -0
  144. package/scripts/lib/stacks.mjs +138 -0
  145. package/scripts/lib/telemetry-artifact.mjs +253 -0
  146. package/scripts/lib/template-root.mjs +39 -0
  147. package/scripts/merge-harness-package.mjs +14 -0
  148. package/scripts/route-harness-review.mjs +168 -0
  149. package/scripts/run-e2e-bench.mjs +216 -0
  150. package/scripts/sdlc-gh-cli.mjs +91 -0
  151. package/scripts/select-eval-jobs.mjs +41 -0
  152. package/scripts/setup-github.mjs +242 -0
  153. package/scripts/setup-github.sh +4 -0
  154. package/scripts/setup-wizard.mjs +426 -0
  155. package/scripts/test-bootstrap-guidance-scenarios.mjs +94 -0
  156. package/scripts/test-diff-size-scenarios.mjs +88 -0
  157. package/scripts/test-doctor-scenarios.mjs +70 -0
  158. package/scripts/test-e2e-manifest-scenarios.mjs +65 -0
  159. package/scripts/test-gh-aw-dogfood-scenarios.mjs +74 -0
  160. package/scripts/test-harness-review-routing-scenarios.mjs +130 -0
  161. package/scripts/test-harness-review-scenarios.mjs +92 -0
  162. package/scripts/test-hooks-scenarios.mjs +44 -0
  163. package/scripts/test-issue-form-label-sync-scenarios.mjs +48 -0
  164. package/scripts/test-issue-spec-scenarios.mjs +258 -0
  165. package/scripts/test-l1-readiness-scenarios.mjs +204 -0
  166. package/scripts/test-merge-harness-package-scenarios.mjs +53 -0
  167. package/scripts/test-npm-package-scenarios.mjs +31 -0
  168. package/scripts/test-sdlc-gh-cli-scenarios.mjs +54 -0
  169. package/scripts/test-setup-github-scenarios.mjs +103 -0
  170. package/scripts/test-setup-wizard-scenarios.mjs +114 -0
  171. package/scripts/test-telemetry-artifact-scenarios.mjs +69 -0
  172. package/scripts/trim-harness-ci.mjs +18 -0
  173. package/scripts/validate-gh-aw-compile.mjs +64 -0
  174. package/scripts/validate-harness.mjs +199 -0
  175. package/scripts/validate-telemetry.mjs +21 -0
  176. package/scripts/verify-bootstrap-stacks.sh +192 -0
@@ -0,0 +1,87 @@
1
+ ---
2
+ description: Nightly harness review — classify failures and propose harness revisions.
3
+ name: Nightly harness review
4
+ on:
5
+ schedule:
6
+ - cron: "0 2 * * *"
7
+ permissions:
8
+ contents: read
9
+ issues: read
10
+ safe-outputs:
11
+ create-pull-request:
12
+ max: 1
13
+ create-issue:
14
+ max: 3
15
+ ---
16
+
17
+ # Nightly harness review (gh-aw source)
18
+
19
+ > **Operational baseline:** [nightly-harness-review.yml](./nightly-harness-review.yml) runs on standard GitHub Actions without gh-aw. Use this Markdown source only when promoting to gh-aw per [docs/gh-aw-dogfood.md](../../docs/gh-aw-dogfood.md).
20
+
21
+ ## Required inputs
22
+
23
+ | Input | Source | Required |
24
+ |-------|--------|----------|
25
+ | Telemetry JSON artifacts | Inner-loop workflows (`harness-ci`, `eval-ci`, retry, PR context) | yes |
26
+ | Aggregation window | Default 24h; match GHA `WINDOW_HOURS` | yes |
27
+ | Failure taxonomy | [docs/failure-taxonomy.md](../../docs/failure-taxonomy.md) | yes |
28
+ | Harness review summary | `harness-review/harness-review-summary.json` from GHA aggregator | yes when chaining |
29
+
30
+ ## Forbidden operations
31
+
32
+ - Do **not** auto-merge pull requests
33
+ - Do **not** modify product application code outside harness paths
34
+ - Do **not** disable CI walls or bypass `safe-output` limits
35
+ - Do **not** replace the GHA nightly job without dogfood criteria green
36
+
37
+ ## Expected outputs
38
+
39
+ | Output | Format | Limit |
40
+ |--------|--------|-------|
41
+ | Harness revision proposal | Pull request (`autonomy:L0`) | `create-pull-request.max: 1` |
42
+ | Routed work items | GitHub issues with dedupe markers | `create-issue.max: 3` |
43
+ | Human summary | Markdown tables in step summary / artifact | reviewable text only |
44
+
45
+ Issue routing rules (GHA implementation): [docs/nightly-harness-review.md](../../docs/nightly-harness-review.md#issue-routing).
46
+
47
+ ## Classification contract
48
+
49
+ Classify each task group into one of:
50
+
51
+ - **FF不足** — repeated convention / lint / issue-spec gaps → harness revision
52
+ - **壁不足** — CI green but review rejects → add walls (tests, lint, contracts)
53
+ - **モデル限界** — retry exhaustion or repeated execution failures → escalate / split task
54
+
55
+ Use `rollup.repeated_failure_signatures` and per-task `classifications[]` from the summary JSON schema (`scripts/lib/harness-review.mjs`).
56
+
57
+ ## Escalation
58
+
59
+ Escalate to humans (issue comment or `create-issue`) when:
60
+
61
+ - `classification` is `モデル限界` with security `wall_failure_type`
62
+ - the same `harness-routing-key` fires three nightly windows in a row without resolution
63
+ - gh-aw compile or safe-output validation fails on this source
64
+
65
+ ## Fallback when gh-aw regresses
66
+
67
+ 1. Keep **GHA** [nightly-harness-review.yml](./nightly-harness-review.yml) as the operational outer loop
68
+ 2. Revert `.md` / `.lock.yml` pair per [docs/revert-playbook.md](../../docs/revert-playbook.md)
69
+ 3. Record incident in dogfood report artifact (`docs/gh-aw-dogfood.md`)
70
+
71
+ ## Promotion criteria (gh-aw vs GHA)
72
+
73
+ Promote gh-aw execution only when **all** hold:
74
+
75
+ - Dogfood CI green for ≥3 consecutive runs on unchanged `.md` sources
76
+ - GHA nightly review and gh-aw classification outputs agree on fixture summaries
77
+ - `create-pull-request.max` remains `1` and no forbidden safe-outputs appear
78
+
79
+ Until then, treat this file as the **specification** and GHA as the **runtime**.
80
+
81
+ ## Agent instructions
82
+
83
+ Analyze failure traces per [docs/failure-taxonomy.md](../../docs/failure-taxonomy.md).
84
+
85
+ When repeated **FF不足** or **壁不足** patterns appear in the summary JSON, ensure routed issues exist (GHA runs `scripts/route-harness-review.mjs`) or propose a harness revision PR with eval / instruction diffs only.
86
+
87
+ Do not auto-merge. Prefer proposal-only PRs at `autonomy:L0`.
@@ -0,0 +1,63 @@
1
+ name: Nightly harness review
2
+
3
+ on:
4
+ schedule:
5
+ - cron: "0 2 * * *"
6
+ workflow_dispatch:
7
+ inputs:
8
+ window_hours:
9
+ description: Hours of telemetry to aggregate
10
+ required: false
11
+ default: "24"
12
+ apply_routing:
13
+ description: Apply issue routing instead of dry-run preview
14
+ required: false
15
+ default: false
16
+ type: boolean
17
+
18
+ permissions:
19
+ actions: read
20
+ contents: read
21
+ issues: write
22
+
23
+ jobs:
24
+ review:
25
+ name: aggregate-and-classify
26
+ runs-on: ubuntu-latest
27
+ steps:
28
+ - uses: actions/checkout@v4
29
+
30
+ - uses: actions/setup-node@v4
31
+ with:
32
+ node-version: "22"
33
+
34
+ - name: Fetch telemetry artifacts
35
+ env:
36
+ GH_TOKEN: ${{ github.token }}
37
+ GITHUB_REPOSITORY: ${{ github.repository }}
38
+ WINDOW_HOURS: ${{ github.event_name == 'workflow_dispatch' && inputs.window_hours || 24 }}
39
+ TELEMETRY_COLLECT_DIR: telemetry-collected
40
+ run: node scripts/fetch-telemetry-artifacts.mjs
41
+
42
+ - name: Aggregate and classify failures
43
+ env:
44
+ GITHUB_REPOSITORY: ${{ github.repository }}
45
+ WINDOW_HOURS: ${{ github.event_name == 'workflow_dispatch' && inputs.window_hours || 24 }}
46
+ TELEMETRY_COLLECT_DIR: telemetry-collected
47
+ HARNESS_REVIEW_OUT_DIR: harness-review
48
+ run: node scripts/aggregate-harness-review.mjs
49
+
50
+ - name: Route repeated failures to issues
51
+ env:
52
+ GH_TOKEN: ${{ github.token }}
53
+ GITHUB_REPOSITORY: ${{ github.repository }}
54
+ HARNESS_REVIEW_OUT_DIR: harness-review
55
+ HARNESS_ROUTING_DRY_RUN: ${{ github.event_name == 'workflow_dispatch' && inputs.apply_routing != true && '1' || '0' }}
56
+ run: node scripts/route-harness-review.mjs
57
+
58
+ - name: Upload harness review summary
59
+ uses: actions/upload-artifact@v4
60
+ with:
61
+ name: nightly-harness-review-${{ github.run_id }}
62
+ path: harness-review/
63
+ if-no-files-found: error
@@ -0,0 +1,49 @@
1
+ name: npm publish
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+ workflow_dispatch:
7
+
8
+ permissions:
9
+ contents: read
10
+ id-token: write
11
+
12
+ jobs:
13
+ publish:
14
+ runs-on: ubuntu-latest
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+
18
+ - uses: actions/setup-node@v4
19
+ with:
20
+ node-version: "22"
21
+ registry-url: https://registry.npmjs.org
22
+
23
+ - name: Verify package version matches release tag
24
+ if: github.event_name == 'release'
25
+ run: |
26
+ TAG="${{ github.event.release.tag_name }}"
27
+ TAG="${TAG#v}"
28
+ PKG="$(node --input-type=module -e "import p from './package.json' with { type: 'json' }; console.log(p.version)")"
29
+ if [ "$TAG" != "$PKG" ]; then
30
+ echo "Release tag ($TAG) must match package.json version ($PKG)" >&2
31
+ exit 1
32
+ fi
33
+
34
+ - name: Validate package contents
35
+ run: |
36
+ npm run validate
37
+ npm run test-sdlc-gh-cli
38
+ npm run test-setup-wizard
39
+ npm pack --dry-run
40
+
41
+ - name: Publish to npm (dry run)
42
+ if: github.event_name == 'workflow_dispatch'
43
+ run: npm publish --dry-run --provenance --access public
44
+
45
+ - name: Publish to npm
46
+ if: github.event_name == 'release'
47
+ run: npm publish --provenance --access public
48
+ env:
49
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
@@ -0,0 +1,138 @@
1
+ name: PR context comment
2
+
3
+ on:
4
+ pull_request:
5
+ types: [opened, synchronize, reopened]
6
+
7
+ permissions:
8
+ pull-requests: write
9
+ checks: read
10
+
11
+ jobs:
12
+ context:
13
+ runs-on: ubuntu-latest
14
+ steps:
15
+ - uses: actions/checkout@v4
16
+ with:
17
+ fetch-depth: 0
18
+
19
+ - name: Build context
20
+ id: ctx
21
+ shell: bash
22
+ env:
23
+ LANGFUSE_HOST: ${{ vars.LANGFUSE_HOST }}
24
+ BASE_REF: ${{ github.base_ref }}
25
+ PR_LABELS: ${{ join(github.event.pull_request.labels.*.name, ', ') }}
26
+ run: |
27
+ BASE="origin/${BASE_REF}"
28
+ LOC=$(git diff --numstat "$BASE"...HEAD | awk '{a+=$1;d+=$2} END {print a+d+0}')
29
+ FILES=$(git diff --name-only "$BASE"...HEAD | wc -l | tr -d ' ')
30
+ LABELS="${PR_LABELS}"
31
+ RETRY=$(echo "$LABELS" | tr ',' '\n' | grep -o 'retry:[0-9]*' | head -1 || true)
32
+ INS_SHA=$(git log -1 --format=%H -- .github/copilot-instructions.md AGENTS.md 2>/dev/null || echo "n/a")
33
+ SKILLS_SHA=$(git log -1 --format=%H -- .github/skills 2>/dev/null || echo "n/a")
34
+ if [[ -f evals/.score-baseline.json ]]; then
35
+ EVAL_SCORE=$(node -e "const b=require('./evals/.score-baseline.json'); console.log(b.eval_pass_rate+'%')")
36
+ else
37
+ EVAL_SCORE="n/a"
38
+ fi
39
+ if [[ -n "$LANGFUSE_HOST" ]]; then
40
+ TRACE="${LANGFUSE_HOST%/} (search: repo=${{ github.repository }}, pr_number=${{ github.event.pull_request.number }})"
41
+ else
42
+ TRACE="_configure LANGFUSE_HOST; then search by repo=${{ github.repository }}, pr_number=${{ github.event.pull_request.number }}_"
43
+ fi
44
+ THREAT_STATUS="n/a"
45
+ {
46
+ echo "loc=$LOC"
47
+ echo "files=$FILES"
48
+ echo "labels=$LABELS"
49
+ echo "retry=$RETRY"
50
+ echo "ins_sha=$INS_SHA"
51
+ echo "skills_sha=$SKILLS_SHA"
52
+ echo "eval_score=$EVAL_SCORE"
53
+ echo "trace=$TRACE"
54
+ echo "threat_status=$THREAT_STATUS"
55
+ } >> "$GITHUB_OUTPUT"
56
+
57
+ - name: Post comment
58
+ uses: actions/github-script@v7
59
+ with:
60
+ script: |
61
+ const { data: checks } = await github.rest.checks.listForRef({
62
+ owner: context.repo.owner,
63
+ repo: context.repo.repo,
64
+ ref: context.payload.pull_request.head.sha,
65
+ });
66
+ const failed = checks.check_runs.filter((c) => c.conclusion === 'failure').map((c) => c.name);
67
+ const ciSummary = failed.length ? `❌ ${failed.join(', ')}` : '✅ no failures (or pending)';
68
+ const body = `## Harness context (auto)
69
+
70
+ | Field | Value |
71
+ |-------|-------|
72
+ | Diff LOC | ${{ steps.ctx.outputs.loc }} |
73
+ | Changed files | ${{ steps.ctx.outputs.files }} |
74
+ | Labels | ${{ steps.ctx.outputs.labels }} |
75
+ | Retry | ${{ steps.ctx.outputs.retry }} |
76
+ | Instructions SHA | \`${{ steps.ctx.outputs.ins_sha }}\` |
77
+ | Skills SHA | \`${{ steps.ctx.outputs.skills_sha }}\` |
78
+ | Eval score (baseline) | ${{ steps.ctx.outputs.eval_score }} |
79
+ | AI credits | _set max-ai-credits in org settings_ |
80
+ | Trace link | ${{ steps.ctx.outputs.trace }} |
81
+ | Threat detection | ${{ steps.ctx.outputs.threat_status }} |
82
+ | CI | ${ciSummary} |
83
+
84
+ <!-- harness-pr-context -->
85
+ `;
86
+ const { data: comments } = await github.rest.issues.listComments({
87
+ owner: context.repo.owner,
88
+ repo: context.repo.repo,
89
+ issue_number: context.issue.number,
90
+ });
91
+ const existing = comments.find((c) => c.body?.includes('harness-pr-context'));
92
+ if (existing) {
93
+ await github.rest.issues.updateComment({
94
+ owner: context.repo.owner,
95
+ repo: context.repo.repo,
96
+ comment_id: existing.id,
97
+ body,
98
+ });
99
+ } else {
100
+ await github.rest.issues.createComment({
101
+ owner: context.repo.owner,
102
+ repo: context.repo.repo,
103
+ issue_number: context.issue.number,
104
+ body,
105
+ });
106
+ }
107
+
108
+ - uses: actions/setup-node@v4
109
+ with:
110
+ node-version: "22"
111
+
112
+ - name: Emit PR context telemetry artifact
113
+ continue-on-error: true
114
+ env:
115
+ TELEMETRY_SOURCE: pr-context
116
+ GITHUB_REPOSITORY: ${{ github.repository }}
117
+ GITHUB_RUN_ID: ${{ github.run_id }}
118
+ GITHUB_RUN_ATTEMPT: ${{ github.run_attempt }}
119
+ GITHUB_WORKFLOW: ${{ github.workflow }}
120
+ GITHUB_EVENT_NAME: ${{ github.event_name }}
121
+ PR_NUMBER: ${{ github.event.pull_request.number }}
122
+ PR_BODY: ${{ github.event.pull_request.body }}
123
+ PR_LABELS: ${{ join(github.event.pull_request.labels.*.name, ',') }}
124
+ BASE_SHA: origin/${{ github.base_ref }}
125
+ CHANGED_FILES: ${{ steps.ctx.outputs.files }}
126
+ DIFF_LOC: ${{ steps.ctx.outputs.loc }}
127
+ AGENT_TYPE: implementer
128
+ EXECUTION_MODE: coding_agent
129
+ FINAL_OUTCOME: in_progress
130
+ run: node scripts/emit-telemetry-artifact.mjs
131
+
132
+ - name: Upload PR context telemetry artifact
133
+ continue-on-error: true
134
+ uses: actions/upload-artifact@v4
135
+ with:
136
+ name: pr-context-telemetry-${{ github.run_id }}
137
+ path: telemetry-artifacts/
138
+ if-no-files-found: ignore
@@ -0,0 +1,33 @@
1
+ name: Product CI (Go)
2
+
3
+ on:
4
+ workflow_call:
5
+
6
+ jobs:
7
+ verify:
8
+ runs-on: ubuntu-latest
9
+ steps:
10
+ - uses: actions/checkout@v4
11
+
12
+ - name: Resolve project directory
13
+ id: root
14
+ shell: bash
15
+ run: |
16
+ if [[ -f sample/go/go.mod ]]; then
17
+ echo "dir=sample/go" >> "$GITHUB_OUTPUT"
18
+ elif [[ -f go.mod ]]; then
19
+ echo "dir=." >> "$GITHUB_OUTPUT"
20
+ else
21
+ echo "No Go project found" >&2
22
+ exit 1
23
+ fi
24
+
25
+ - uses: actions/setup-go@v5
26
+ with:
27
+ go-version: "1.22"
28
+
29
+ - name: Vet and test
30
+ working-directory: ${{ steps.root.outputs.dir }}
31
+ run: |
32
+ go vet ./...
33
+ go test ./...
@@ -0,0 +1,39 @@
1
+ name: Product CI (PHP)
2
+
3
+ on:
4
+ workflow_call:
5
+
6
+ jobs:
7
+ verify:
8
+ runs-on: ubuntu-latest
9
+ steps:
10
+ - uses: actions/checkout@v4
11
+
12
+ - name: Resolve project directory
13
+ id: root
14
+ shell: bash
15
+ run: |
16
+ if [[ -f sample/php/composer.json ]]; then
17
+ echo "dir=sample/php" >> "$GITHUB_OUTPUT"
18
+ elif [[ -f composer.json ]]; then
19
+ echo "dir=." >> "$GITHUB_OUTPUT"
20
+ else
21
+ echo "No PHP project found" >&2
22
+ exit 1
23
+ fi
24
+
25
+ - uses: shivammathur/setup-php@v2
26
+ with:
27
+ php-version: "8.2"
28
+ coverage: none
29
+ tools: composer
30
+
31
+ - name: Install dependencies
32
+ working-directory: ${{ steps.root.outputs.dir }}
33
+ run: composer install --no-interaction --prefer-dist
34
+
35
+ - name: Lint and test
36
+ working-directory: ${{ steps.root.outputs.dir }}
37
+ run: |
38
+ composer lint
39
+ composer test
@@ -0,0 +1,34 @@
1
+ name: Product CI (Python)
2
+
3
+ on:
4
+ workflow_call:
5
+
6
+ jobs:
7
+ verify:
8
+ runs-on: ubuntu-latest
9
+ steps:
10
+ - uses: actions/checkout@v4
11
+
12
+ - name: Resolve project directory
13
+ id: root
14
+ shell: bash
15
+ run: |
16
+ if [[ -f sample/python/requirements-dev.txt ]]; then
17
+ echo "dir=sample/python" >> "$GITHUB_OUTPUT"
18
+ elif [[ -f requirements-dev.txt ]]; then
19
+ echo "dir=." >> "$GITHUB_OUTPUT"
20
+ else
21
+ echo "No Python project found" >&2
22
+ exit 1
23
+ fi
24
+
25
+ - uses: actions/setup-python@v5
26
+ with:
27
+ python-version: "3.12"
28
+
29
+ - name: Lint and test
30
+ working-directory: ${{ steps.root.outputs.dir }}
31
+ run: |
32
+ pip install -r requirements-dev.txt
33
+ ruff check .
34
+ pytest -q
@@ -0,0 +1,35 @@
1
+ name: Product CI (Ruby)
2
+
3
+ on:
4
+ workflow_call:
5
+
6
+ jobs:
7
+ verify:
8
+ runs-on: ubuntu-latest
9
+ steps:
10
+ - uses: actions/checkout@v4
11
+
12
+ - name: Resolve project directory
13
+ id: root
14
+ shell: bash
15
+ run: |
16
+ if [[ -f sample/ruby/Gemfile ]]; then
17
+ echo "dir=sample/ruby" >> "$GITHUB_OUTPUT"
18
+ elif [[ -f Gemfile ]]; then
19
+ echo "dir=." >> "$GITHUB_OUTPUT"
20
+ else
21
+ echo "No Ruby project found" >&2
22
+ exit 1
23
+ fi
24
+
25
+ - uses: ruby/setup-ruby@v1
26
+ with:
27
+ ruby-version: "3.3"
28
+ bundler-cache: true
29
+ working-directory: ${{ steps.root.outputs.dir }}
30
+
31
+ - name: Lint and test
32
+ working-directory: ${{ steps.root.outputs.dir }}
33
+ run: |
34
+ bundle exec rubocop
35
+ bundle exec rspec
@@ -0,0 +1,37 @@
1
+ name: Product CI (TypeScript)
2
+
3
+ on:
4
+ workflow_call:
5
+
6
+ jobs:
7
+ verify:
8
+ runs-on: ubuntu-latest
9
+ steps:
10
+ - uses: actions/checkout@v4
11
+
12
+ - name: Resolve project directory
13
+ id: root
14
+ shell: bash
15
+ run: |
16
+ if [[ -f sample/ts/package.json ]]; then
17
+ echo "dir=sample/ts" >> "$GITHUB_OUTPUT"
18
+ elif [[ -f package.json ]]; then
19
+ echo "dir=." >> "$GITHUB_OUTPUT"
20
+ else
21
+ echo "No TypeScript project found" >&2
22
+ exit 1
23
+ fi
24
+
25
+ - uses: actions/setup-node@v4
26
+ with:
27
+ node-version: "22"
28
+ cache: npm
29
+ cache-dependency-path: ${{ steps.root.outputs.dir }}/package-lock.json
30
+
31
+ - name: Install, lint, typecheck, test
32
+ working-directory: ${{ steps.root.outputs.dir }}
33
+ run: |
34
+ npm ci
35
+ npm run lint
36
+ npm run typecheck
37
+ npm test
@@ -0,0 +1,50 @@
1
+ name: Task issue label sync
2
+
3
+ on:
4
+ issues:
5
+ types: [opened, edited, reopened]
6
+
7
+ permissions:
8
+ issues: write
9
+
10
+ jobs:
11
+ sync-labels:
12
+ runs-on: ubuntu-latest
13
+ steps:
14
+ - uses: actions/checkout@v4
15
+
16
+ - uses: actions/setup-node@v4
17
+ with:
18
+ node-version: "22"
19
+
20
+ - name: Sync labels from Task Issue form
21
+ uses: actions/github-script@v7
22
+ env:
23
+ ISSUE_BODY: ${{ github.event.issue.body }}
24
+ ISSUE_LABELS: ${{ join(github.event.issue.labels.*.name, '||') }}
25
+ with:
26
+ script: |
27
+ const { parseTaskIssueSelections, planIssueLabels } = await import(
28
+ `${process.env.GITHUB_WORKSPACE}/scripts/lib/issue-form-label-sync.mjs`
29
+ );
30
+ const existingLabels = (process.env.ISSUE_LABELS || "")
31
+ .split("||")
32
+ .map((label) => label.trim())
33
+ .filter(Boolean);
34
+ const parsed = parseTaskIssueSelections(process.env.ISSUE_BODY || "");
35
+ if (!parsed.isTaskIssue) {
36
+ core.info("Issue does not match the Task Issue form; skipping.");
37
+ return;
38
+ }
39
+ const plan = planIssueLabels(existingLabels, parsed);
40
+ if (!plan.changed) {
41
+ core.info(plan.reason);
42
+ return;
43
+ }
44
+ await github.rest.issues.setLabels({
45
+ owner: context.repo.owner,
46
+ repo: context.repo.repo,
47
+ issue_number: context.issue.number,
48
+ labels: plan.labels,
49
+ });
50
+ core.notice(`Applied labels: ${plan.labels.join(", ")}`);