This is an automated email from the ASF dual-hosted git repository.

morningman pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris-website.git


The following commit(s) were added to refs/heads/master by this push:
     new b2216b0b48a [ci](i18n) Schedule Korean translation runs twice daily 
(#4409)
b2216b0b48a is described below

commit b2216b0b48add56314a2d6d2880efdc7b2b9e65d
Author: Mingyu Chen (Rayner) <[email protected]>
AuthorDate: Tue Oct 20 07:13:32 2026 +0100

    [ci](i18n) Schedule Korean translation runs twice daily (#4409)
    
    ## Why
    
    Korean generation has been manual-only (`workflow_dispatch`) since the
    workflow was added in #4358. All 3336 Korean target documents (Dev 1670,
    4.x 1615, community 51) are now translated, merged and served in
    production. From here the workflow needs to keep them current as the
    English sources change, the same way the Japanese workflow does.
    
    ## What changed
    
    ### 1. Schedule
    
    `korean-translation.yml` now also runs at 04:43 and 16:43 UTC, twenty
    minutes after the Japanese schedule (04:23 and 16:23). Both workflows
    already share the `japanese-translation-ja` concurrency group with
    `cancel-in-progress: false` and `queue: max`, so a Korean run waits
    while a Japanese run is still working and never uses the Codex auth pool
    at the same time.
    
    ### 2. Scheduled runs generate
    
    Scheduled runs have no inputs, so the mode fell back to `dry-run`. But
    `workflow-scan.cjs` treats every scheduled run as eligible, while
    `workflow-generate.cjs` only runs in `generate` mode. With the old
    fallback, a scheduled run with a pending document would have reached the
    generation step and failed after loading Codex auth. The fallback is now
    `generate`, matching the Japanese workflow. Manual dispatch still
    defaults to `dry-run`.
    
    ### 3. Tests
    
    `korean-workflow.test.cjs` now asserts the schedule (and that it stays
    offset from the Japanese one) and the new fallback. A new test passes
    the mode a scheduled run resolves to into `allowGeneration`. With the
    old `dry-run` fallback, both tests fail.
    
    ### 4. Docs
    
    `translations/README.md` still described the workflow as manual-only and
    production as Japanese-only. Both statements are updated.
    
    Unchanged: the planner limit (20) and batch size (10), open-PR
    reconciliation and deduplication, protection of human-owned targets, the
    `translate-ko` label check before auth loading, and the PR admission
    checks. Maintainers review and merge generated PRs as before; nothing is
    merged automatically.
    
    ## Verification
    
    - `node --test` on Node 20.20.2: `korean-workflow` 5/5, `workflow`
    29/29, `multi-locale` 6/6.
    - Mutation check: restoring the `dry-run` fallback fails the two updated
    assertions.
    - Scheduled discovery replayed locally on this branch
    (`GITHUB_EVENT_NAME=schedule`, `I18N_MODE=generate`, `I18N_LOCALE=ko`):
    38 open PRs, 0 relevant; required 3336, merged current 3336, pending 0;
    selected 0, `can_generate=false`. On today's state, a scheduled run
    scans and skips generation without calling the model.
    
    ## After merge
    
    The first scheduled run will be checked for its trigger time, lock and
    queue behaviour, discovery summary, and that generation is skipped while
    nothing is pending.
    
    Rollback: remove the `schedule` block. Manual dispatch keeps working
    either way.
    
    🤖 Generated with [Claude Code](https://claude.com/claude-code)
    
    Co-authored-by: morningman <[email protected]>
    Co-authored-by: Claude Opus 5.5 (1M context) <[email protected]>
---
 .github/workflows/korean-translation.yml        | 14 +++++++++----
 scripts/i18n/__tests__/korean-workflow.test.cjs | 20 ++++++++++++++++---
 translations/README.md                          | 26 +++++++++++++++----------
 3 files changed, 43 insertions(+), 17 deletions(-)

diff --git a/.github/workflows/korean-translation.yml 
b/.github/workflows/korean-translation.yml
index 133a4ea2fcb..11487252b54 100644
--- a/.github/workflows/korean-translation.yml
+++ b/.github/workflows/korean-translation.yml
@@ -21,6 +21,12 @@ on:
       paths:
         description: Optional JSON array of exact English .md/.mdx files 
(exclusive with path)
         type: string
+  # Twenty minutes after the Japanese schedule; the shared lock below holds
+  # this run while a Japanese run is still in progress. Scheduled runs have no
+  # inputs, so the mode falls back to generate; manual runs keep the dry-run
+  # default.
+  schedule:
+    - cron: '43 4,16 * * *'
 
 permissions:
   contents: read
@@ -62,7 +68,7 @@ jobs:
       - name: Plan all current and historical pending documents
         id: scan
         env:
-          I18N_MODE: ${{ inputs.mode || 'dry-run' }}
+          I18N_MODE: ${{ inputs.mode || 'generate' }}
           I18N_PLUGIN: ${{ inputs.plugin }}
           I18N_VERSION: ${{ inputs.version }}
           I18N_PATH: ${{ inputs.path }}
@@ -110,7 +116,7 @@ jobs:
           APP_ID: ${{ secrets.I18N_GITHUB_APP_ID }}
           APP_PRIVATE_KEY: ${{ secrets.I18N_GITHUB_APP_PRIVATE_KEY }}
           I18N_GITHUB_PAT: ${{ secrets.I18N_GITHUB_PAT }}
-          I18N_MODE: ${{ inputs.mode || 'dry-run' }}
+          I18N_MODE: ${{ inputs.mode || 'generate' }}
         run: |
           if [[ -n "$APP_ID" && -n "$APP_PRIVATE_KEY" ]]; then
             echo 'auth_kind=app' >> "$GITHUB_OUTPUT"
@@ -140,7 +146,7 @@ jobs:
         if: steps.config.outputs.ready == 'true'
         id: fresh
         env:
-          I18N_MODE: ${{ inputs.mode || 'dry-run' }}
+          I18N_MODE: ${{ inputs.mode || 'generate' }}
           I18N_PLUGIN: ${{ inputs.plugin }}
           I18N_VERSION: ${{ inputs.version }}
           I18N_PATH: ${{ inputs.path }}
@@ -192,7 +198,7 @@ jobs:
         id: translation
         env:
           I18N_CODEX_MODEL: ${{ vars.I18N_CODEX_MODEL || 'gpt-6-sol' }}
-          I18N_MODE: ${{ inputs.mode || 'dry-run' }}
+          I18N_MODE: ${{ inputs.mode || 'generate' }}
           I18N_PATH: ${{ inputs.path }}
           I18N_MAX_PAGES: ${{ inputs.mode == 'validate' && '1' || '10' }}
           GITHUB_REPOSITORY: ${{ github.repository }}
diff --git a/scripts/i18n/__tests__/korean-workflow.test.cjs 
b/scripts/i18n/__tests__/korean-workflow.test.cjs
index b193deb02e9..6b83352a05e 100644
--- a/scripts/i18n/__tests__/korean-workflow.test.cjs
+++ b/scripts/i18n/__tests__/korean-workflow.test.cjs
@@ -5,6 +5,7 @@ const path = require('node:path');
 const yaml = require('js-yaml');
 const os = require('node:os');
 const {spawnSync} = require('node:child_process');
+const {allowGeneration} = require('../workflow-generate.cjs');
 const workflows = path.resolve(__dirname, '../../../.github/workflows');
 const load = name => yaml.load(fs.readFileSync(path.join(workflows, name), 
'utf8'));
 const korean = load('korean-translation.yml');
@@ -22,8 +23,11 @@ test('one-page validation rejects an exact batch list before 
creating scan artif
     assert(!fs.existsSync(output));
 });
 
-test('Korean generation requires a manual choice and shares the existing 
whole-run lock', () => {
-    assert.deepEqual(Object.keys(korean.on), ['workflow_dispatch']);
+test('Korean generation runs on its schedule or a manual choice and shares the 
existing whole-run lock', () => {
+    assert.deepEqual(Object.keys(korean.on), ['workflow_dispatch', 
'schedule']);
+    // Twice daily, offset from the Japanese runs that hold the same lock.
+    assert.deepEqual(korean.on.schedule, [{cron: '43 4,16 * * *'}]);
+    assert.deepEqual(japanese.on.schedule, [{cron: '23 4,16 * * *'}]);
     assert.equal(korean.on.workflow_dispatch.inputs.mode.default, 'dry-run');
     assert.deepEqual(korean.on.workflow_dispatch.inputs.mode.options, 
['dry-run', 'validate', 'generate']);
     assert.equal(korean.on.workflow_dispatch.inputs.locale, undefined);
@@ -37,7 +41,7 @@ test('Korean generation requires a manual choice and shares 
the existing whole-r
     for (const job of Object.values(korean.jobs)) {
         assert.equal(job.env.I18N_LOCALE, 'ko');
         for (const step of job.steps) {
-            if (step.env?.I18N_MODE) assert.equal(step.env.I18N_MODE, "${{ 
inputs.mode || 'dry-run' }}");
+            if (step.env?.I18N_MODE) assert.equal(step.env.I18N_MODE, "${{ 
inputs.mode || 'generate' }}");
             if (step.uses?.startsWith('actions/checkout@')) {
                 assert.equal(step.with['fetch-depth'], 0);
                 assert.equal(step.with['persist-credentials'], false);
@@ -46,6 +50,16 @@ test('Korean generation requires a manual choice and shares 
the existing whole-r
     }
 });
 
+test('a scheduled run resolves to a mode that the generation gate accepts', () 
=> {
+    // Discovery marks every scheduled run eligible, so the input-less fallback
+    // must be a mode that workflow-generate.cjs will run, not a dry run.
+    const step = korean.jobs.generate.steps.find(item => item.id === 
'translation');
+    const fallback = /\|\| '([a-z-]+)' \}\}$/.exec(step.env.I18N_MODE)[1];
+    assert.equal(allowGeneration({I18N_MODE: fallback, GITHUB_EVENT_NAME: 
'schedule', I18N_MAX_PAGES: '10'}), true);
+    assert.equal(allowGeneration({I18N_MODE: 
korean.on.workflow_dispatch.inputs.mode.default,
+        GITHUB_EVENT_NAME: 'workflow_dispatch', I18N_MAX_PAGES: '10'}), false);
+});
+
 test('Korean discovery and generation exchange Korean artifacts at the exact 
scanned commit', () => {
     const discover = korean.jobs.discover.steps;
     const generate = korean.jobs.generate.steps;
diff --git a/translations/README.md b/translations/README.md
index d940cc7cb31..75806b97e50 100644
--- a/translations/README.md
+++ b/translations/README.md
@@ -32,7 +32,7 @@ build; the scoped website build and static-page verification 
run afterward.
 
 Korean is registered as an optional documentation locale. Enable it locally 
with
 `DORIS_ENABLE_KO=true`, or enable both managed languages with
-`DORIS_ENABLE_LOCALES=ja,ko`. Production deployment still enables Japanese 
only.
+`DORIS_ENABLE_LOCALES=ja,ko`. Production deployment enables both Japanese and 
Korean.
 Korean ordinary pages use the existing English fallback.
 
 The initial Korean native inventory is pinned to the merged source commit in
@@ -103,10 +103,17 @@ existing source/technical hash algorithms unchanged. 
Offline Korean fixtures
 exercise these boundaries without real credentials or model calls; actual
 single-page generation is a separate validation step.
 
-The `Korean translation discovery` workflow is manual-only and defaults to a
-read-only dry run. It fixes the locale to `ko`, uses separate Korean artifacts,
-and shares the existing `japanese-translation-ja` lock with Japanese runs.
-After the workflow is merged, run discovery on master:
+The `Korean translation discovery` workflow runs at 04:43 and 16:43 UTC daily
+and on manual dispatch. It fixes the locale to `ko`, uses separate Korean
+artifacts, and shares the existing `japanese-translation-ja` lock with Japanese
+runs. The schedule starts twenty minutes after the Japanese one, so a Korean 
run
+waits while a Japanese run is still in progress. A scheduled run generates a
+batch when eligible Korean documents are pending, with the same limits as a
+manual `generate` run: the planner considers at most 20 targets and a batch has
+at most 10 pages. It opens a normal labeled PR that maintainers review and 
merge
+like any other; nothing is merged automatically. With nothing pending, a
+scheduled run only scans and makes no model call. Manual dispatch defaults to a
+read-only dry run. To run discovery on master:
 
 ```bash
 gh workflow run korean-translation.yml --repo apache/doris-website --ref 
master -f mode=dry-run
@@ -120,8 +127,7 @@ to one and rechecks active PRs before calling Codex. 
Generation checks the
 runtime and auth pool. A write credential enables a normal labeled PR after
 shared admission checks; otherwise a successful one-page validation remains
 an artifact and does not establish the PR publication path. Inspect generation
-warnings and normal PR checks before merging. There is no Korean generation
-schedule in this workflow.
+warnings and normal PR checks before merging.
 
 ## Search, navigation and four-language validation
 
@@ -605,7 +611,7 @@ No real model call or GitHub write occurs.
 
 ### Selecting an exact Korean manual batch
 
-The Korean workflow remains manual-only and defaults to `dry-run`. Its optional
+Manual Korean dispatch defaults to `dry-run`. Its optional
 `paths` input accepts a JSON array of 1–20 exact English source files, so a 
bounded
 batch can select documents from different folders without including every page
 under a shared prefix:
@@ -622,8 +628,8 @@ fresh scan immediately before generation. `validate` still 
requires one exact
 targets and generation still produces at most 10. Exact selection preserves
 full coverage counts, current-page and active-PR exclusion, human ownership,
 scope/version checks, and exact-master protection. Unknown, duplicate,
-malformed or out-of-scope source paths fail before model calls. This input does
-not enable scheduled generation.
+malformed or out-of-scope source paths fail before model calls. Scheduled runs
+do not use this input; they plan from the full scope.
 
 The planner CLI exposes the same filter as `--paths '<JSON array>'`.
 


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to