Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- **Review mode no longer fails the run when a document was deliberately deleted** (#210): a source PR that removes a lecture produces a translation PR that removes the corresponding target file — a routine editorial operation that failed its review run in **every** language, reproducibly. The F40 guard (#163) refuses to review when no source content could be fetched, which is right, but it could not tell a failed fetch from a file that is *supposed* to be gone; a deletion has no source content by definition, and `getSourceDiff` skips that fetch deliberately, so the guard was firing on this engine's own intent. A red that is always expected is precisely what trains people to ignore the reds F40 exists to raise. **Now** `getSourceDiff` reports which files the source PR deleted, and those are partitioned out before the content loop: a PR that only deletes is reported as a deletion — no model calls, so it costs nothing — with a comment that states outright that no quality evaluation was performed, and it routes to a human rather than auto-merge, because deleting a translated document is an editorial decision and nothing about the content was verified. A PR that deletes *and* edits now reviews the surviving files instead of aborting on the deleted one. **The guard stays fatal everywhere else, and fails closed**: if the source PR cannot be listed the deletion set comes back empty, so nothing is excused and absent source content is still an abort — absence of evidence is never read as evidence of deletion. A **new** deterministic check falls out of the same information: a target file removed with no matching source deletion — the translation dropping a document the source still has — is now a blocker finding that gates. Also fixed alongside it: the per-file `try` was wide enough that the target-content 404 raised by *any* deletion skipped the rest of the loop body, including the source fetch that would have succeeded, which is how a single deleted file emptied `sourceEnglish` and took the whole run down under a misleading `Error processing …` line. Renames are covered by the same partition, including the delete+add form GitHub reports when heavy edits defeat its rename detection. Resync PRs are unaffected: a commit is a state, not a diff, so there is no deletion to read off it and that path's behaviour is unchanged.
- **The E2E harness tests one version across every workflow, gains Malayalam, and stops destroying the Farsi target's workflows** (#202 and follow-ons): a full run previously pinned **2 of 9 workflows**. The harness rendered only the zh-cn and fa sync templates; the other seven — a hand-made ml sync workflow plus review and rebase in each target repo — floated on `@v0`, so one run tested two versions and reported it as one. Worse, the fa reset ran `rm -rf … .github/` **without re-rendering**, so it silently deleted that target's review and rebase workflows on every run; fa had none at all. And ml, absent from the script entirely but wired up by hand, fired and failed on all 26 PRs of every run with `Unsupported target language` — unreported, because the banner did not know it existed. **Now**: one `LANGUAGES` array drives everything (adding a language is one line plus three fixtures), the harness writes all nine workflows across all four repos from templates carrying a substituted ref, and a per-workflow **census** prints before any PR is created so "this run tested version X" is falsifiable rather than asserted. Target-repo workflows render from `examples/` — the canonical templates users receive — so the harness cannot drift from what it is meant to be testing. The three near-duplicate reset blocks (which had already drifted three separate ways) collapse into subshelled functions with absolute `cd`s, and `git commit || echo` — which made a genuine commit failure indistinguishable from nothing-to-do, then pushed anyway — now fails the run. **`@v0` is preserved, not traded away**: rather than leaving some workflow permanently floating, `--action-ref v0` renders the tag into every workflow as a post-release smoke, so the check moves to *after* the tag move, the only point where its answer means anything (#109). **The default is now `main`, not the package.json version** — the version bump happens in the release commit, so that default tested the *previous* release rather than the code under development, and refused to run at all during a release PR. Release gating is an explicit `--action-ref vX.Y.Z` step. **ml is a first-class third language**, its fixtures seeded with `translate init` so they carry the current `translation:` frontmatter and passed the #159 parity guard on write; the fa and zh-cn fixtures are migrated off the legacy `heading-map:` key with `translate headingmap` (no LLM calls, translations byte-untouched), which matters because the writer *deletes* that key on rewrite — the harness's own baseline used to mutate on run one. Docs corrected: both pages claimed the harness built from `main` and that TEST mode makes "no Claude API calls" — it makes real, billed calls, and this PR roughly doubles them by installing review workflows in every target (~1.4M input tokens measured on two languages pre-dates that, so it is a floor). Guards added in the `workflow-templates.test.ts` mold cover ref substitution, the `main` default, fixture presence and format per language, structural parity against source, and that `.github/` is only deleted where it is also re-rendered.

### Added
- **French: the first native-editor lecture reviews are encoded as engine rules — fr glossary v1.1 (+3 terms) and four register/anti-calque prompt rules**: Emile's hand-review of two machine-seeded lectures (QuantEcon/lecture-python-programming.fr#24 and #25 — ~80 corrections, independently validated at 0 regressions on numpy.md) is the ml-packet pattern (#237) applied to French: every correction he made at least twice becomes a rule, every terminology ruling becomes a glossary pin. Glossary: `Flat array` and `One-dimensional array` → `Tableau unidimensionnel` (the seed's word-for-word "tableau plat" is ruled out explicitly), `Boolean mask` → `Masque booléen` (verified by the editor against French NumPy references). Deliberately **not** pinned, per the #78 bar of real variation or an explicit ruling: terms the seed already rendered consistently (`bloc de code`, `bruit blanc`, `élément par élément`), the context-dependent package-vs-bibliothèque call, and `Lecture → Chapitre` — his edits use both `cours` and `chapitre`, 24 already-seeded lectures say `cours`, so that one goes back to him as a question rather than into the glossary as churn. Prompt rules (fr `additionalRules` 2 → 6): impersonal academic register over calqued direct address ("On pose $T = 200$", not "Posez…"); no word-for-word discourse formulas ("Nous verrons plus loin…", never "Nous pouvons et allons…"); translate descriptive symbols in display math and hints — extending into code comments only where the `code-comments` localization rule is active, so the base keep-code-as-is rule stays authoritative — but never identifiers executable code defines; natural French sentence structure over mirrored English syntax. These rules feed review mode too — harness validation should confirm review does not flag the new register as drift before this reaches a release.


## [0.24.0] - 2026-07-25

Expand Down
10 changes: 9 additions & 1 deletion dist-action/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -26402,9 +26402,17 @@ var LANGUAGE_CONFIGS = {
fr: {
code: "fr",
name: "French",
// Register and anti-calque rules derived from the first native-editor review
// of machine output: Emile (@Honaminto), lecture-python-programming.fr PRs
// #24/#25 (2026-08). Every rule generalises a correction he made at least
// twice across those two lectures.
additionalRules: [
"Use French guillemets \xAB \xBB (with a non-breaking space inside each, e.g. \xAB citation \xBB) for quotations rather than straight or curly double quotes",
'Insert a non-breaking space before the high punctuation marks ; : ! ? as required by French typography (e.g. "Bonjour !" not "Bonjour!")'
'Insert a non-breaking space before the high punctuation marks ; : ! ? as required by French typography (e.g. "Bonjour !" not "Bonjour!")',
`Use the impersonal academic register of French course materials rather than calquing the English direct address: render exercise set-ups as "On pose $T = 200$" (not "Posez..."), task statements as "L'objectif de cet exercice est de..." (not "Votre t\xE2che consiste \xE0..."), and drop chatty asides addressed to the reader (e.g. "prenez votre temps et vous comprendrez")`,
`Do not calque English discourse formulas word-for-word \u2014 render the function, not the words: "We can and will examine..." becomes "Nous verrons plus loin..." (never "Nous pouvons et allons..."), "worth knowing" becomes "utile \xE0 conna\xEEtre" (not "vaut la peine d'\xEAtre connue"), and a heading "The Task: ..." becomes "Objectif : ..." (not "La t\xE2che : ...")`,
'In display math and exercise hints, translate ordinary English words used as descriptive symbols (e.g. $area = \\pi * radius^2$ becomes $aire = \\pi * rayon^2$); never rename identifiers that executable code defines or uses. Where code comments are being localized (the code-comments localization rule), apply the same descriptive-symbol translation there (e.g. "division par radius**2" becomes "division par rayon**2")',
"Prefer natural French sentence structure over mirroring the English: split long English sentences into two French ones and reword constructions that read as translationese \u2014 fidelity is owed to meaning and technical content, not to English syntax"
]
},
ml: {
Expand Down
Loading
Loading