diff --git a/.github/workflows/techapi-verify-comment.yml b/.github/workflows/techapi-verify-comment.yml index d96fd8a..feb0e69 100644 --- a/.github/workflows/techapi-verify-comment.yml +++ b/.github/workflows/techapi-verify-comment.yml @@ -56,6 +56,9 @@ jobs: env: TECHAPI_COMMENT_ID: ${{ github.event.client_payload.comment_id }} + - name: Checkout TechEngine + uses: actions/checkout@v4 + - name: Checkout TechAPI PR head uses: actions/checkout@v4 with: @@ -67,15 +70,21 @@ jobs: - uses: actions/setup-python@v5 with: python-version: "3.12" + cache: pip - # app.verify is a stdlib-only TechAPI module; run it from the checkout. - # mode=tier0 (auto PR report): fast offline Tier 0 only (changed + baseline). - # mode=all (/verify on demand): `pr` runs Tiers 0-3 (3 = promotion DRY-RUN). + - name: Install TechEngine + run: pip install -e . + + # app.verify now lives in TechEngine; run it from the engine root with + # TECHAPI_DATA_DIR pointing at the TechAPI checkout (its `_changed_data_slugs` + # runs git inside that data repo). mode=tier0 = fast offline Tier 0 (auto PR + # report); mode=all = `pr` Tiers 0-3 (3 = promotion DRY-RUN). - name: Run verification id: verify + env: + TECHAPI_DATA_DIR: ${{ github.workspace }}/TechAPI/data run: | - cd TechAPI - git fetch origin main --depth=1 || true + git -C TechAPI fetch origin main --depth=1 || true { echo 'report<true and open a PR on TechAPI (else dry-run)" + type: boolean + default: false + max_urls: + description: "Frontier records to URL-check" + default: "2000" + max_crossref: + description: "Records to cross-reference" + default: "500" + schedule: + - cron: "0 4 * * 1" # Mondays 04:00 UTC + +permissions: + contents: read + +concurrency: + group: verify-network + cancel-in-progress: false + +jobs: + verify-network: + runs-on: ubuntu-latest + env: + PYTHONIOENCODING: utf-8 + APPLY: ${{ github.event_name == 'schedule' || github.event.inputs.apply == 'true' }} + TECHAPI_DATA_DIR: ${{ github.workspace }}/TechAPI/data + WRITE_TOKEN: ${{ secrets.TECHENGINEBOT_TOKEN || secrets.TECHAPI_TOKEN }} + steps: + - name: Checkout TechEngine + uses: actions/checkout@v4 + + - name: Checkout TechAPI + uses: actions/checkout@v4 + with: + repository: GetTechAPI/TechAPI + path: TechAPI + fetch-depth: 0 + token: ${{ secrets.TECHENGINEBOT_TOKEN || secrets.TECHAPI_TOKEN || secrets.GITHUB_TOKEN }} + + - uses: actions/setup-python@v5 + with: + python-version: "3.12" + cache: pip + + - name: Install TechEngine + run: pip install -e . + + - name: Tier 0 score (writes scores cache) + run: python -m app.verify score + + - name: Tier 1 source-URL liveness + run: python -m app.verify check-urls --max ${{ github.event.inputs.max_urls || '2000' }} + + - name: Tier 2 external cross-reference + run: python -m app.verify crossref --max ${{ github.event.inputs.max_crossref || '500' }} + + - name: Tier 3 promote (dry-run) + run: python -m app.verify promote + + - name: Tier 3 promote (apply) + if: ${{ env.APPLY == 'true' }} + run: python -m app.verify promote --apply + + - name: Structural validator self-check + if: ${{ env.APPLY == 'true' }} + run: python -m app.validate + + # Guard: the only tracked changes in TechAPI may be `verified` toggles in + # data/**.json (the ledger under data/_verify/ is expected to change too). + - name: Guard diff scope + if: ${{ env.APPLY == 'true' }} + run: | + python - <<'PY' + import subprocess, sys + out = subprocess.run( + ["git", "-C", "TechAPI", "diff", "--unified=0", "--", + "data/", ":(exclude)data/_verify/**"], + capture_output=True, text=True).stdout + bad = [] + for line in out.splitlines(): + if line.startswith(("+++", "---", "@@", "diff ", "index ")): + continue + if line.startswith(("+", "-")) and line[1:].strip(): + body = line[1:].strip().rstrip(",") + if body not in ('"verified": true', '"verified": false'): + bad.append(line) + if bad: + print("Unexpected non-verified changes:") + print("\n".join(bad[:50])) + sys.exit(1) + print("diff scope OK: only verified toggles") + PY + + - name: Open promotion PR on TechAPI (TechEngineBot) + if: ${{ env.APPLY == 'true' }} + env: + GH_TOKEN: ${{ env.WRITE_TOKEN }} + run: | + set -e + cd TechAPI + if git diff --quiet -- data/; then + echo "no promotions to commit"; exit 0 + fi + branch="verify/promote-${{ github.run_id }}" + git config user.name "TechEngineBot" + git config user.email "289859915+TechEngineBot@users.noreply.github.com" + git checkout -b "$branch" + git add data/ + git commit -m "data(verify): promote records to verified (reality cross-reference) + + Auto-promotions from the verification layer (green+live-source or crossref-confirm). + Each flip is verified:false->true only; see data/_verify/ledger.jsonl. Refs #1" + git push origin "$branch" + gh pr create --repo GetTechAPI/TechAPI --base main --head "$branch" \ + --title "data(verify): verified promotions ($(date -u +%Y-%m-%d))" \ + --body "Automated verified promotions from \`app.verify promote\` (run in TechEngine). Each change flips only the \`verified\` flag; structural validator passed and diff scope guarded. Review before merge. Refs #1" diff --git a/.github/workflows/verify-status.yml b/.github/workflows/verify-status.yml new file mode 100644 index 0000000..472ed2a --- /dev/null +++ b/.github/workflows/verify-status.yml @@ -0,0 +1,61 @@ +name: verify-status + +# Keep TechAPI's data/_verify/status.json (the verification-state aggregate: how +# many records are verified + Tier 0 bands per category) current. Runs in +# TechEngine against a TechAPI checkout and commits the refreshed file back to +# TechAPI main as TechEngineBot. Fires when TechAPI main changes (relayed by +# TechAPI's notify-engine -> techapi-updated) and daily as a backstop. The +# "commit only if changed" guard means the status commit can't loop. +on: + repository_dispatch: + types: [techapi-updated] + schedule: + - cron: "30 5 * * *" # daily 05:30 UTC backstop + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: verify-status + cancel-in-progress: false + +jobs: + status: + runs-on: ubuntu-latest + env: + PYTHONIOENCODING: utf-8 + TECHAPI_DATA_DIR: ${{ github.workspace }}/TechAPI/data + steps: + - name: Checkout TechEngine + uses: actions/checkout@v4 + + - name: Checkout TechAPI + uses: actions/checkout@v4 + with: + repository: GetTechAPI/TechAPI + path: TechAPI + token: ${{ secrets.TECHENGINEBOT_TOKEN || secrets.TECHAPI_TOKEN || secrets.GITHUB_TOKEN }} + + - uses: actions/setup-python@v5 + with: + python-version: "3.12" + cache: pip + + - name: Install TechEngine + run: pip install -e . + + - name: Regenerate verification status aggregate + run: python -m app.verify status --output TechAPI/data/_verify/status.json + + - name: Commit to TechAPI if changed (TechEngineBot) + run: | + cd TechAPI + git add data/_verify/status.json + if git diff --cached --quiet; then + echo "verification status unchanged"; exit 0 + fi + git config user.name "TechEngineBot" + git config user.email "289859915+TechEngineBot@users.noreply.github.com" + git commit -m "chore(verify): refresh verification status aggregate" + git push origin HEAD:main