Add zh-cn translation sync workflow (Phase 0 Track B)#979
Conversation
Wires this repo as the source for QuantEcon/lecture-python.zh-cn: on each merged lecture PR (or a \translate-resync comment), the action translates the changed lectures and opens a PR in the target repo. Copied from lecture-python-intro's proven workflow with only the target-repo changed. Part of Phase 0 Track B (#947). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR adds a GitHub Actions workflow to automatically sync (translate) changed lecture content from this English source repository into the QuantEcon/lecture-python.zh-cn target repository when PRs merge (or when manually re-triggered via a \translate-resync comment).
Changes:
- Introduces a new workflow triggered on merged PRs affecting lecture Markdown /
_toc.yml. - Adds an
issue_commenttrigger intended to allow manual resync via\translate-resync. - Runs
QuantEcon/action-translationinsyncmode targetingQuantEcon/lecture-python.zh-cn.
📖 Netlify Preview Ready!Preview URL: https://pr-979--sunny-cactus-210e3e.netlify.app Commit: Build Info
|
|
Pre-merge verification per QuantEcon/project-translation#14 step 3 (2026-07-22): Pin — Shape — byte-identical to the proven source-sync template in Secrets — both org secrets are visible to this repo (verified via the repo's organization-secrets API): Target readiness — lecture-python.zh-cn is fully prepared: drift reconciled and merged (#188–#193), metadata bootstrap merged (#195), corpus verified at 84 aligned + 37 source-only with zero outdated and zero missing heading-maps, review/rebase workflows live on Ready to merge. Once in, the first organic lecture merge (or a |
…issions Copilot review: the issue_comment trigger ran a secrets-bearing job for any comment containing the command, from any user, on any issue. Now requires a PR comment from OWNER/MEMBER/COLLABORATOR. Adds permissions: contents: read since the action authenticates via QUANTECON_SERVICES_PAT, not GITHUB_TOKEN. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…192) (#219) * fix(security): gate the \translate-resync trigger on commenter trust (#192) The `issue_comment` branch of the source-sync workflow's `if:` checked only that the comment body contained the magic string. `issue_comment` workflows run in default-branch context with full access to secrets, and GitHub cannot filter the event by body at the trigger level — so that `if:` is the only gate. Any GitHub account could comment `\translate-resync` on a merged PR and spend Anthropic credits and runner minutes, repeatedly. The commenter controls nothing but the trigger, so this is cost abuse rather than code execution, but it was live in the canonical template and therefore on every deployed instance. Two smaller holes came with it, absorbed from #138: the condition never required `github.event.issue.pull_request`, so a comment on a plain issue fired a run too; and the generated workflow carried no `permissions:` block at all, leaving the ambient GITHUB_TOKEN at the repo default. The `issue_comment` clause now requires all four conditions — a comment on a PR, the command, and an author in ["OWNER", "MEMBER", "COLLABORATOR"] — and the job declares `permissions: contents: read`, since the action authenticates to the target repo with the PAT input and checkout is the ambient token's only consumer. CONTRIBUTOR is deliberately excluded. `src/inputs.ts` has always enforced exactly this three-way set inside the action, so admitting it at the workflow level would only buy a billed run that then no-ops; the outer gate has to be at least as tight as the inner one. Recorded in .dev/decisions/D-2026-07-26-resync-trust-gate-association-set.md. The fix lands in all fourteen in-repo copies — the scaffolder, twelve documented copies across README, examples/, quickstart, action-reference and the three tutorials, and the E2E harness template — plus the FAQ's stated requirements. The exposure was never one file: each new doc page had copied the shape from an older one, and the docs are how the estate gets configured. A new guard in workflow-templates.test.ts sweeps rather than enumerates. It parses every workflow under README.md, examples/, docs/, tool-test-action-on-github/ and .github/, plus the scaffolder's output, and fails per job on a missing condition, a missing `contents: read`, or any surviving copy of the pre-fix one-line form — so a doc page added tomorrow is covered the day it lands. It also asserts the workflow's association set still matches TRUSTED_ASSOCIATIONS in inputs.ts, which keeps the two gates from drifting apart. Verified it fails before trusting it: regressing one doc page turns 5 assertions red. It parses rather than greps because a substring check passes on a copy whose YAML fold silently swallowed a clause. The folded `if:` shape is the one deployed in QuantEcon/lecture-python.myst since 2026-07-22, where both trigger branches have fired since — checked before copying it, because a mis-folded `if:` would stop the sync firing on merges entirely and would look exactly like "nothing happened". dist-action/ is byte-identical: this is CLI, docs and tests only. Rollout steps 2 and 3 remain, in other repos: test-translation-sync's three sync workflows pick the gate up on the next harness run (the template is fixed here), and the production source repos still need the same edit by hand. Refs #192, #138. Surfaced by Copilot on QuantEcon/test-translation-sync#671 and QuantEcon/lecture-python.myst#979. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * dev: file #220 for the estate rollout and record the audit behind it Audited all eight deployed sync workflows rather than trusting #192's list — an org-wide search for `translate-resync` returns exactly those eight outside this repo, and each was fetched and checked. #192's list was accurate: four production workflows ungated, myst already fixed, the three harness ones carrying `issue.pull_request` but neither the trust gate nor permissions. Refs #220, #192. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Part of #947. Wires this repo as the English source for QuantEcon/lecture-python.zh-cn: on each merged lecture PR (or a
\translate-resynccomment) the action translates the changed lectures and opens a PR in the target repo. Copied from lecture-python-intro's proven workflow with only the target-repo changed; pinsQuantEcon/action-translation@v0.Secrets: ANTHROPIC_API_KEY and QUANTECON_SERVICES_PAT are already org-visible to this repo (verified 2026-07-18).
Decision note for merge time: 42 of 121 lectures have no translation yet. Once this workflow is live, a merged source PR touching an untranslated lecture will open a new-translation PR in the target — effectively incremental Phase 2 without a restarted review campaign. If that is not wanted yet, hold this PR until the campaign scoping (see the Track B editor report in project-translation) is settled, or merge and triage new-file PRs as they appear; each arrives as a reviewable PR either way.
🤖 Generated with Claude Code