@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.
- package/.github/CODEOWNERS +5 -0
- package/.github/ISSUE_TEMPLATE/bug_report.yml +68 -0
- package/.github/ISSUE_TEMPLATE/config.yml +1 -0
- package/.github/ISSUE_TEMPLATE/feature_request.yml +39 -0
- package/.github/ISSUE_TEMPLATE/support.yml +56 -0
- package/.github/ISSUE_TEMPLATE/task.yml +89 -0
- package/.github/agents/implementer.agent.md +17 -0
- package/.github/agents/reviewer.agent.md +18 -0
- package/.github/agents/triager.agent.md +13 -0
- package/.github/aw/actions-lock.json +9 -0
- package/.github/copilot-instructions.md +35 -0
- package/.github/hooks/hooks.json +12 -0
- package/.github/instructions/core.instructions.md +11 -0
- package/.github/instructions/profiles/go.instructions.md +10 -0
- package/.github/instructions/profiles/php.instructions.md +11 -0
- package/.github/instructions/profiles/python.instructions.md +11 -0
- package/.github/instructions/profiles/ruby.instructions.md +11 -0
- package/.github/instructions/profiles/typescript.instructions.md +11 -0
- package/.github/labels.yml +55 -0
- package/.github/pull_request_template.md +33 -0
- package/.github/ruleset.example.json +33 -0
- package/.github/ruleset.harness-eval.example.json +29 -0
- package/.github/skills/quality-loop/SKILL.md +23 -0
- package/.github/workflows/agent-retry-orchestrator.yml +161 -0
- package/.github/workflows/copilot-setup-steps.yml +64 -0
- package/.github/workflows/eval-ci.yml +169 -0
- package/.github/workflows/eval-drift.yml +75 -0
- package/.github/workflows/gh-aw-dogfood-ci.yml +73 -0
- package/.github/workflows/harness-ci.yml +244 -0
- package/.github/workflows/harness-sync.yml +28 -0
- package/.github/workflows/l1-readiness-check.yml +45 -0
- package/.github/workflows/labels-sync.yml +24 -0
- package/.github/workflows/nightly-harness-review.lock.yml +1643 -0
- package/.github/workflows/nightly-harness-review.md +87 -0
- package/.github/workflows/nightly-harness-review.yml +63 -0
- package/.github/workflows/npm-publish.yml +49 -0
- package/.github/workflows/pr-context-comment.yml +138 -0
- package/.github/workflows/product-ci-go.yml +33 -0
- package/.github/workflows/product-ci-php.yml +39 -0
- package/.github/workflows/product-ci-python.yml +34 -0
- package/.github/workflows/product-ci-ruby.yml +35 -0
- package/.github/workflows/product-ci-ts.yml +37 -0
- package/.github/workflows/task-issue-label-sync.yml +50 -0
- package/.github/workflows/weekly-redteam.lock.yml +1571 -0
- package/.github/workflows/weekly-redteam.md +76 -0
- package/.github/zizmor.yml +11 -0
- package/AGENTS.md +54 -0
- package/LICENSE +21 -0
- package/README.md +366 -0
- package/config/stacks.json +55 -0
- package/docs/adoption.md +126 -0
- package/docs/arch.md +535 -0
- package/docs/auth-boundaries.md +16 -0
- package/docs/coding-agent-l1.md +152 -0
- package/docs/exceptions/README.md +25 -0
- package/docs/exceptions/TEMPLATE.md +8 -0
- package/docs/failure-taxonomy.md +23 -0
- package/docs/gh-aw-dogfood.md +109 -0
- package/docs/kpi-baseline.md +9 -0
- package/docs/nightly-harness-review.md +94 -0
- package/docs/operations.md +108 -0
- package/docs/publishing.md +79 -0
- package/docs/revert-playbook.md +44 -0
- package/docs/shared-config.md +30 -0
- package/docs/telemetry-artifacts.md +78 -0
- package/docs/telemetry-schema.md +60 -0
- package/evals/.score-baseline.json +6 -0
- package/evals/e2e-bench/README.md +28 -0
- package/evals/e2e-bench/manifest.json +16 -0
- package/evals/e2e-bench/tasks/e2e-001.yml +10 -0
- package/evals/e2e-bench/tasks/e2e-002.yml +11 -0
- package/evals/e2e-bench/tasks/e2e-003.yml +10 -0
- package/evals/e2e-bench/tasks/e2e-004.yml +14 -0
- package/evals/e2e-bench/tasks/e2e-005.yml +11 -0
- package/evals/e2e-bench/tasks/e2e-006.yml +10 -0
- package/evals/e2e-bench/tasks/e2e-007.yml +10 -0
- package/evals/e2e-bench/tasks/e2e-008.yml +10 -0
- package/evals/e2e-bench/tasks/e2e-009.yml +10 -0
- package/evals/trajectories/rubric.md +12 -0
- package/evals/trajectories/test_harness_conventions.py +271 -0
- package/infra/README.md +49 -0
- package/infra/langfuse/docker-compose.yml +25 -0
- package/infra/otel/collector-config.yml +24 -0
- package/infra/samples/gh-aw-dogfood-report.json +44 -0
- package/infra/samples/harness-review-routing-plan.json +19 -0
- package/infra/samples/harness-review-summary.json +61 -0
- package/infra/samples/telemetry-artifact.json +29 -0
- package/infra/samples/telemetry-payload.json +19 -0
- package/package.json +85 -0
- package/prompts/triager-classify.prompt.yml +10 -0
- package/sample/go/add.go +5 -0
- package/sample/go/add_test.go +9 -0
- package/sample/go/go.mod +3 -0
- package/sample/php/composer.json +26 -0
- package/sample/php/composer.lock +1881 -0
- package/sample/php/phpunit.xml +8 -0
- package/sample/php/src/Add.php +13 -0
- package/sample/php/tests/AddTest.php +16 -0
- package/sample/python/requirements-dev.txt +2 -0
- package/sample/python/src/__init__.py +0 -0
- package/sample/python/src/greet.py +3 -0
- package/sample/python/tests/conftest.py +4 -0
- package/sample/python/tests/test_greet.py +5 -0
- package/sample/ruby/.rubocop.yml +10 -0
- package/sample/ruby/Gemfile +6 -0
- package/sample/ruby/Gemfile.lock +58 -0
- package/sample/ruby/lib/add.rb +9 -0
- package/sample/ruby/spec/add_spec.rb +11 -0
- package/sample/ts/biome.json +6 -0
- package/sample/ts/package-lock.json +1763 -0
- package/sample/ts/package.json +15 -0
- package/sample/ts/src/add.ts +3 -0
- package/sample/ts/tests/add.test.ts +8 -0
- package/sample/ts/tsconfig.json +12 -0
- package/scripts/aggregate-harness-review.mjs +48 -0
- package/scripts/bootstrap-harness.sh +411 -0
- package/scripts/check-diff-size.mjs +46 -0
- package/scripts/check-e2e-manifest.mjs +35 -0
- package/scripts/check-eval-score-drift.mjs +31 -0
- package/scripts/check-gh-aw-dogfood-scope.mjs +51 -0
- package/scripts/check-issue-spec.mjs +215 -0
- package/scripts/check-l1-readiness.mjs +82 -0
- package/scripts/check-open-pr-limit.mjs +34 -0
- package/scripts/doctor.mjs +177 -0
- package/scripts/emit-gh-aw-dogfood-report.mjs +112 -0
- package/scripts/emit-telemetry-artifact.mjs +99 -0
- package/scripts/fetch-telemetry-artifacts.mjs +176 -0
- package/scripts/harness-drift-report.mjs +99 -0
- package/scripts/lib/bootstrap-copy.mjs +123 -0
- package/scripts/lib/ccsd-contract.mjs +212 -0
- package/scripts/lib/diff-size.mjs +103 -0
- package/scripts/lib/doctor-local.mjs +179 -0
- package/scripts/lib/e2e-manifest.mjs +76 -0
- package/scripts/lib/gh-aw-dogfood.mjs +293 -0
- package/scripts/lib/github-config.mjs +94 -0
- package/scripts/lib/harness-ci-fragments.mjs +98 -0
- package/scripts/lib/harness-review-routing.mjs +244 -0
- package/scripts/lib/harness-review.mjs +388 -0
- package/scripts/lib/issue-form-label-sync.mjs +56 -0
- package/scripts/lib/l1-readiness.mjs +258 -0
- package/scripts/lib/merge-harness-package.mjs +36 -0
- package/scripts/lib/npm-package.mjs +129 -0
- package/scripts/lib/setup-wizard.mjs +224 -0
- package/scripts/lib/stacks.mjs +138 -0
- package/scripts/lib/telemetry-artifact.mjs +253 -0
- package/scripts/lib/template-root.mjs +39 -0
- package/scripts/merge-harness-package.mjs +14 -0
- package/scripts/route-harness-review.mjs +168 -0
- package/scripts/run-e2e-bench.mjs +216 -0
- package/scripts/sdlc-gh-cli.mjs +91 -0
- package/scripts/select-eval-jobs.mjs +41 -0
- package/scripts/setup-github.mjs +242 -0
- package/scripts/setup-github.sh +4 -0
- package/scripts/setup-wizard.mjs +426 -0
- package/scripts/test-bootstrap-guidance-scenarios.mjs +94 -0
- package/scripts/test-diff-size-scenarios.mjs +88 -0
- package/scripts/test-doctor-scenarios.mjs +70 -0
- package/scripts/test-e2e-manifest-scenarios.mjs +65 -0
- package/scripts/test-gh-aw-dogfood-scenarios.mjs +74 -0
- package/scripts/test-harness-review-routing-scenarios.mjs +130 -0
- package/scripts/test-harness-review-scenarios.mjs +92 -0
- package/scripts/test-hooks-scenarios.mjs +44 -0
- package/scripts/test-issue-form-label-sync-scenarios.mjs +48 -0
- package/scripts/test-issue-spec-scenarios.mjs +258 -0
- package/scripts/test-l1-readiness-scenarios.mjs +204 -0
- package/scripts/test-merge-harness-package-scenarios.mjs +53 -0
- package/scripts/test-npm-package-scenarios.mjs +31 -0
- package/scripts/test-sdlc-gh-cli-scenarios.mjs +54 -0
- package/scripts/test-setup-github-scenarios.mjs +103 -0
- package/scripts/test-setup-wizard-scenarios.mjs +114 -0
- package/scripts/test-telemetry-artifact-scenarios.mjs +69 -0
- package/scripts/trim-harness-ci.mjs +18 -0
- package/scripts/validate-gh-aw-compile.mjs +64 -0
- package/scripts/validate-harness.mjs +199 -0
- package/scripts/validate-telemetry.mjs +21 -0
- 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(", ")}`);
|