From bf74b0b057106c1cc9894b30d4aa32f773137215 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 18 May 2026 03:47:31 +0000 Subject: [PATCH] fix(ci): repair notebook-sync workflow syntax causing instant failures MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three defects in .github/workflows/notebook-sync.yml combined to make GitHub Actions reject the file at parse time, so every run failed instantly with conclusion=failure, zero jobs dispatched, and `gh run view --log-failed` returned "log not found": 1. workflow_dispatch: was declared at the top level instead of nested under on:. The bare key `on` is parsed as YAML True, and a sibling top-level workflow_dispatch: is rejected by Actions as an unexpected workflow section. All ${{ inputs.* }} references downstream were thus undefined. 2. extract-issue.outputs.event_type referenced steps.event.outputs.type but the actual step id is event_type. 3. Duplicate pull_request_review) case in the bash case block. In addition, once the workflow parses and dispatches jobs, the sync-notebook job failed at action-resolution time: 4. peter-evans/create-or-update-file@v3 does not exist on github.com (404 — the canonical peter-evans actions are create-pull-request, create-or-update-comment, create-issue-from-file, etc.). Replaced with actions/github-script@v7 using github.rest.repos.createOrUpdateFileContents via the REST API. Added permissions.contents: write on the sync-notebook job (default GITHUB_TOKEN scope was Contents: read). Validation: - actionlint 1.7.12: all syntax-check and expression errors clear. Only a pre-existing low-severity advisory about github.event.issue.title being potentially untrusted in an inline script remains, unrelated to the instant-failure issue. - python yaml.safe_load: on: now contains all six triggers including workflow_dispatch with inputs [issue_number, sync_type]; four jobs defined; extract-issue.outputs.event_type resolves to the correct step id. L7 UNITY held: YAML/actions-side repair only — no *.sh added, no gen/ edits, no spec changes. RTL/GDS/verdict.json gates untouched. docs/NOW.md updated per NOW Sync Gate. Closes #695 Co-Authored-By: Claude Opus 4.7 --- .github/workflows/notebook-sync.yml | 109 +++++++++++++++++++--------- docs/NOW.md | 16 +++- 2 files changed, 89 insertions(+), 36 deletions(-) diff --git a/.github/workflows/notebook-sync.yml b/.github/workflows/notebook-sync.yml index f63066f1..1124f3a0 100644 --- a/.github/workflows/notebook-sync.yml +++ b/.github/workflows/notebook-sync.yml @@ -18,23 +18,22 @@ on: types: [submitted, edited] push: branches: ['feature/**', 'fix/**', 'ring-*/**', 'issue-*/**'] - -# Allow manual trigger -workflow_dispatch: - inputs: - issue_number: - description: 'Issue number to sync' - required: true - type: number - sync_type: - description: 'Type of sync' - required: false - type: choice - default: 'push' - options: - - push - - comment - - activity + # Allow manual trigger + workflow_dispatch: + inputs: + issue_number: + description: 'Issue number to sync' + required: true + type: number + sync_type: + description: 'Type of sync' + required: false + type: choice + default: 'push' + options: + - push + - comment + - activity jobs: # Extract issue number from event @@ -44,7 +43,7 @@ jobs: outputs: issue_number: ${{ steps.issue.outputs.number }} issue_title: ${{ steps.issue.outputs.title }} - event_type: ${{ steps.event.outputs.type }} + event_type: ${{ steps.event_type.outputs.type }} steps: - name: Checkout repo uses: actions/checkout@v4 @@ -76,12 +75,6 @@ jobs: ISSUE_TITLE="${{ github.event.pull_request.title }}" echo "type=pr" >> $GITHUB_OUTPUT ;; - pull_request_review) - # Extract issue number from PR body or branch - ISSUE_NUM="${{ github.event.pull_request.number }}" - ISSUE_TITLE="${{ github.event.pull_request.title }}" - echo "type=pr" >> $GITHUB_OUTPUT - ;; push) # Extract from branch name: feature/issue-357 -> 357 BRANCH="${{ github.ref_name }}" @@ -123,6 +116,8 @@ jobs: needs: extract-issue if: needs.extract-issue.outputs.issue_number != '' runs-on: ubuntu-latest + permissions: + contents: write steps: - name: Checkout repo uses: actions/checkout@v4 @@ -177,19 +172,65 @@ jobs: exit 0 } - - name: Update sync status as commit + - name: Update sync status as commit (best-effort) if: github.event_name == 'issues' || github.event_name == 'pull_request' - uses: peter-evans/create-or-update-file@v3 + continue-on-error: true + uses: actions/github-script@v7 + env: + SYNC_TIME: ${{ github.event.repository.updated_at }} + EVENT_NAME: ${{ github.event_name }} + ISSUE_NUM: ${{ needs.extract-issue.outputs.issue_number }} with: - path: .trinity/notebook_sync_status.json - content: | - { - "last_sync": "${{ github.event.repository.updated_at }}", - "last_event": "${{ github.event_name }}", - "last_issue": ${{ needs.extract-issue.outputs.issue_number }}, - "synced_at": "${{ github.event.repository.updated_at }}" + script: | + const path = '.trinity/notebook_sync_status.json'; + const content = JSON.stringify({ + last_sync: process.env.SYNC_TIME, + last_event: process.env.EVENT_NAME, + last_issue: Number(process.env.ISSUE_NUM), + synced_at: process.env.SYNC_TIME, + }, null, 2) + '\n'; + const contentB64 = Buffer.from(content).toString('base64'); + + // On 'issues' and 'pull_request' events the workflow has no + // single canonical branch to commit to (PRs from forks have a + // read-only token; 'issues' has no ref at all). Resolve the + // repository's default branch and commit there as best-effort. + const repoInfo = await github.rest.repos.get({ + owner: context.repo.owner, + repo: context.repo.repo, + }); + const branch = repoInfo.data.default_branch; + + let sha; + try { + const { data } = await github.rest.repos.getContent({ + owner: context.repo.owner, + repo: context.repo.repo, + path, + ref: branch, + }); + sha = data.sha; + } catch (e) { + if (e.status !== 404) throw e; + } + + try { + await github.rest.repos.createOrUpdateFileContents({ + owner: context.repo.owner, + repo: context.repo.repo, + path, + message: 'Update NotebookLM sync status [skip ci]', + content: contentB64, + branch, + ...(sha ? { sha } : {}), + }); + core.info(`Wrote ${path} on ${branch}`); + } catch (e) { + // 403/422 are expected when the workflow runs from a fork or + // when branch protection blocks the write. This step is a + // book-keeping nicety, not a correctness gate — log and pass. + core.warning(`Status commit skipped (${e.status} ${e.message})`); } - message: "Update NotebookLM sync status [skip ci]" # Sync activity.md periodically sync-activity: diff --git a/docs/NOW.md b/docs/NOW.md index e322f345..16f1064d 100644 --- a/docs/NOW.md +++ b/docs/NOW.md @@ -1,8 +1,20 @@ # NOW — Trinity t27 sync -Last updated: 2026-05-17 +Last updated: 2026-05-18 -## docs(TRI-NET) — positioning package (this PR, #693, Closes #627) +## ci(notebook-sync) — repair workflow syntax causing instant failures (this PR, #694, Closes #695) + +- **Fixed**: `.github/workflows/notebook-sync.yml` was failing instantly on every push since #693 merged — runs completed in seconds with `conclusion=failure`, zero jobs dispatched, `gh run view --log-failed` reported *log not found*. +- **Root cause (three combined defects)**: + 1. `workflow_dispatch:` was declared at the top level instead of nested under `on:` — Actions rejected the file at parse time (bare `on` is interpreted as YAML `True`). + 2. `extract-issue.outputs.event_type` referenced `steps.event.outputs.type` while the step id is `event_type`. + 3. Duplicate `pull_request_review)` case in the bash event dispatch. +- **Latent runtime defect surfaced once jobs began dispatching**: `sync-notebook` referenced `peter-evans/create-or-update-file@v3`, which does not exist on github.com (404). Replaced with `actions/github-script@v7` using `github.rest.repos.createOrUpdateFileContents`; added `permissions.contents: write` on the `sync-notebook` job. Step targets the repo's default branch (resolved via `repos.get`) because on `issues` / `pull_request` events there is no canonical branch to commit to, and is wrapped in `continue-on-error` + internal `try/catch` so a 403/422 from fork PRs or branch protection logs a warning instead of failing the sync job — matches the existing best-effort pattern around the `python sync.py || warnings; exit 0` block immediately above. +- **Validation**: `actionlint 1.7.12` — all syntax-check and expression errors cleared. `yaml.safe_load` confirms `on:` contains all 6 triggers including `workflow_dispatch` with `inputs: [issue_number, sync_type]`. +- **L7 UNITY held**: YAML/actions-side repair only — no `*.sh` added, no `gen/` edits, no spec changes. RTL/GDS/`verdict.json` gates untouched. TRI-NET docs package from #693 untouched. +- Closes #695 + +## docs(TRI-NET) — positioning package (#693, Closes #627) - **NEW** (root-level, docs-only): `STATUS.md`, `LINEUP.md`, `FORMAT_REGISTRY.md`, `COMPETITORS.md`, `BENCHMARKS.md`, `CLARA_TRACEABILITY.md` - **README.md first screen**: additive "What this repo is" block linking to the six new docs; rest of README unchanged