During the development of Go Learning & Documentation v2, “history” later became a very important topic.
But going back to the very beginning, my purpose for keeping history was actually quite simple.
It was not to build an increasingly complex audit system.
Nor was it to enable infinite forward tracing of every state.
There was only one problem I originally wanted to solve:
Why redo content that has already been translated and reviewed?
A Tour of Go has already accumulated a large amount of official translation work.
Much of this content has already gone through:
Generation
↓
Machine validation
↓
Independent QC
↓
revision if necessary
↓
re-QC
↓
final passIf, upon entering v2, we invalidate all these results simply because the project version changed or the workflow gained new capabilities, and then re-translate and re-review everything, I think this not only wastes time but may even reduce the stability of the final results.
So the original true value of history is actually:
Letting already high-quality completed work continue to function.
v2 should not mean “starting from scratch”
In software development, a major version upgrade often gives people an intuitive feeling:
v1 is over, now starting v2.
If this versioning concept is brought directly into a translation system, it easily leads to the following approach:
v1 Translation
↓
Archive
v2 Translation
↓
regenerate all contentFrom an engineering implementation perspective, this is very clean.
The new version only handles its own data.
The old version is all left in a history directory.
There are no complex relationships between old and new.
But for translation, this kind of “cleanliness” is not necessarily reasonable.
Assume a certain English Page:
- source has not changed;
- official terminology rules have not affected it;
- candidate has no issues;
- has passed Independent QC;
- the new parser can still validate it;
- neither the current content nor the content the user ultimately sees has undergone any semantic changes.
Then merely because:
we are now entering v2
requiring a re-translation has no practical value.
A version number is an engineering milestone.
It should not automatically become a reason for invalidating language work.
Translation work and ordinary cache are not exactly the same
On the surface, this matter is very much like cache reuse.
If the old result is still valid, just continue using it.
But I feel that official translation work actually deserves more careful protection than an ordinary cache.
Ordinary caches can usually be deleted and recalculated.
For example:
source
↓
deterministic function
↓
cacheIf the cache is lost, running it again should theoretically yield the exact same result.
AI translation is not like this.
Given the same English source, handing it to the model for generation again may result in:
- different sentence structures;
- different vocabulary choices;
- different paragraph transitions;
- different word orders;
- some new subtle language variations.
Many of these changes do not represent quality improvements.
They are merely:
another equally valid expression.
Therefore, a TranslationUnit that has already undergone independent review cannot be simply understood as:
“Just regenerate it anyway.”
It is already a verified language work.
Without a real reason, regenerating it would instead introduce new variables.
Repeated translation also brings repeated review
The cost of a new Generation is also not just the model invocation itself.
Whenever a candidate changes, it means the subsequent trusted chain also needs to be rebuilt.
For example:
new Generation
↓
Machine validation
↓
Candidate Snapshot
↓
Independent QCIf the Reviewer finds new issues:
B / C / D
↓
exact revision
↓
re-QCThus, a Page that was originally completed consumes again, due to an unnecessary regeneration:
- Generation time;
- Reviewer time;
- validation;
- revision;
- evidence;
- workflow coordination.
More importantly, these costs do not bring new user value.
Because that Page might have been correct from the start.
So avoiding repeated translation is essentially also avoiding:
running an entire round of the quality process just to validate changes that never needed to happen.
History should first answer: “Can this work still be used?”
Therefore, I later became increasingly inclined to define the first responsibility of history very simply:
Helping the system determine whether existing work can continue to be reused.
What really needs to be focused on here is the current reality.
For example:
Source changed?
Glossary affected?
Representation still valid?
Candidate still current?
Previous QC still trustworthy?If these conditions still hold, then the best answer history can give should be:
Continue using it.
Rather than:
“Because the workflow was upgraded, running it again feels safer.”
This is also a core direction that gradually formed throughout v2:
Only process the parts that have actually changed.
Source unchanged is the most basic layer
The most direct basis for history reuse is of course the source.
If the English source has changed, then whether the old translation is still valid must be re-evaluated.
But if the source has not changed at all, it at least indicates:
The translation object itself has not changed.
Of course, this alone cannot directly prove that the old candidate can definitely continue to be used.
Because other dependencies may also change.
For example, the glossary.
Previous articles have already stated:
A change in the glossary file does not mean all TranslationUnits are automatically invalidated.
It requires further determining whether the semantic delta actually affects this Page.
Therefore, source identity and glossary compatibility can be combined:
Source unchanged
+
Glossary compatible
↓
Old translation may still be validThe “may” here is important.
Because the parser, representation, or other related rules still need to be considered.
But at least there is no reason to start over directly from Generation.
A parser upgrade should also not automatically reset language work to zero
The previous article just covered the Learn / Docs parser.
The parser will continue to evolve.
Today it might add recognition for a certain teaching comment.
Tomorrow it might fix a certain link binding.
In the future, it might further refine a new Markdown representation.
If every change in parser implementation meant regenerating all historical TranslationUnits, then every engineering improvement to the parser would generate a massive amount of language work.
But what should really be asked is:
Can the old candidate still hold up under the new parser and validator?
If the answer is:
Parse = PASS
Reconstruction = PASS
Validation = PASSAnd no actual impact on this Page from the parser change is found, then there is no reason for the old translation itself to be invalidated.
This is also a very important meaning of “reusing historical work”:
Infrastructure upgrades should not automatically overturn language work.
Results that have passed QC are especially worth protecting
There is another particularly valuable type of information in history:
Independent QC.
Generation producing a candidate itself only proves:
There is a candidate translation.
Machine validation PASS only proves:
The machine found no structural issues.
Only after truly completing Independent QC is an additional layer added:
An independent Reviewer has made a language and technical quality judgment on this TranslationUnit.
If it ultimately receives an A, then this result has accumulated quite valuable quality evidence.
So when future workflows change, such work should be protected as much as possible.
Of course, this does not mean:
“It was an A before, so it will always be an A.”
If the source changed.
The Glossary actually affected it.
The Parser found a structural issue missed in the past.
Or other authority changes make the old conclusion no longer valid.
Then it should of course re-enter the process.
But if none of these things happened, merely because:
milestone changed
workflow gained new featuresresetting all A’s is, I feel, very wasteful.
History reuse has another easily overlooked value: reducing language drift
Beyond costs, there is another issue I have increasingly valued later on:
Language stability.
For a long-running documentation site, constantly regenerating translations without necessity creates a very strange phenomenon.
The Source clearly has not changed.
The user reads today:
“You can run this command…”
After a while, upon regeneration, it might become:
“You can execute this command…”
And the next time it becomes:
“After executing this command…”
None of the three sentences may be wrong.
But for a technical documentation site, this kind of change is actually meaningless.
It is just creating:
translation churn.
Worse still, every such language change might trigger:
- diff;
- QC;
- revision;
- Surface change;
- other downstream judgments.
So reusing trusted history can also help maintain:
Keeping language that has already stabilized as stable as possible.
This is very valuable for terminology consistency, stylistic consistency, and long-term maintenance.
New content should be added, not rolling old content back in
A significant change in v2 is that the project expanded from Tour to:
- Site shell;
- Learn;
- Docs;
- future content packages.
If a “full redo on new milestone” approach is adopted, then every time content is added, it is very likely to pull previous work back in.
For example:
Add Learn
↓
Reprocess Tour + Learn
Add Docs
↓
Reprocess Tour + Learn + Docs
Add package X in the future
↓
Reprocess everythingThis expansion method will quickly get out of control.
A more reasonable pattern should be:
Existing stable content
→ carry
New content
→ Generation / QC
Actually affected old content
→ exact revision / re-QCThat is to say:
New workloads should be as close to “additions and actual changes” as possible, rather than close to “the entire historical corpus”.
This is very important for long-term expansion.
A Milestone should not become a new governance namespace
Therefore, after v2, I also became increasingly clear on another design principle:
v1, v2, v3 are milestones, and should not automatically become new language governance namespaces.
If every milestone establishes:
v1 glossary
v1 translation history
v1 QC
v2 glossary
v2 translation history
v2 QC
v3 ...Then the language history of the same locale will be artificially cut into many segments.
When wanting to reuse it later, one would constantly need to resolve:
Can v1’s A be migrated to v2?
How do the v2 glossary and v3 glossary correspond?
Which generation does this candidate actually belong to?
But from the language itself:
Simplified Chinese is still the same Simplified Chinese locale.
The project upgraded.
The Parser evolved.
Content packages increased.
But verified language work does not naturally expire just because an engineering milestone changed its name.
So a more reasonable direction is:
The same locale continues its own glossary, Generation / Reviewer provenance, and trusted language history.
Handle changes only when they actually occur.
Carry-forward is not “copying old files”
However, “reusing history” is also easily misunderstood as another dangerous practice:
The old file exists, so just copy it over.
This is not the trusted reuse I am talking about.
The file existing only proves:
There is something on the disk.
It cannot prove:
That this thing still conforms to the current authority.
A real carry should at least be built on explicit conditions.
For example:
source unchanged
glossary compatible
representation valid
candidate unchanged
previous QC trustworthyThen the system can conclude:
trusted unchanged carryThat is to say:
Reuse is not bypassing validation, but proving that “there is no need to redo the language work”.
The difference between the two is massive.
Reuse and Revalidate are also not the same concept
There is another very useful distinction here.
A historical candidate can:
Not undergo a new Generation
But still:
Go through a new deterministic machine validation.
For example, after a parser upgrade, the old candidate can be put into the new validator for re-checking.
If it still PASSes, then we have obtained a new machine fact.
But no new language text was generated.
This is often much more reasonable than:
parser changed
↓
regenerate translationTherefore, history reuse does not mean:
“It passed before, so we won’t check anything going forward.”
It is closer to:
Re-validate what can be deterministically re-validated; do not regenerate language that does not need to be regenerated.
This is also an important boundary I see between machine work and language work.
What truly needs reprocessing should be the exception set
After running for a long time, a relatively healthy system should not face the following every time:
all unitsBut should increasingly approach:
missing
restore_failed
validation_failed
stale
affectedThat is to say, the normal situation is:
Content that has already stabilized continues to remain stable.
The system mainly handles exceptions and changes.
This is very similar to many long-running software systems.
If every deployment requires rebuilding the entire historical state, it becomes increasingly difficult to maintain as the scale grows.
The translation system is the same.
As locales increase, Pages increase, and content packages increase:
Full reprocessing should become less frequent, not more frequent.
The value of history is essentially about reducing redundant labor
Reaching this point, I think the core of this article can be condensed into one very simple sentence:
The value of history is not proving how many things happened in the past, but avoiding redoing things that were already done right.
It should help the system reuse:
- already translated candidates;
- already passed QC;
- already determined glossary decisions;
- already verified stable content.
And then spend limited time and model resources on:
Where things are truly added, truly changed, and where problems truly occur.
This is the real problem that history was meant to solve when it was first added to this project.
But later, history started becoming increasingly heavy
However, this v2 also made me realize another side.
When a system increasingly values history, identity, predecessor, Snapshot, promotion, and various evidence, a change can easily happen gradually:
At first:
Saving history was to move forward faster.
Later, it might become:
To move forward, more and more history must first be restored.
To restore a current state, one needs to find the predecessor.
After finding the predecessor, one then needs to restore an earlier Snapshot.
To prove that Snapshot, one needs to continue tracing back even earlier evidence.
Finally, the engineering team starts spending a lot of time:
Not translating new content, but doing archaeology.
This shows that the role of history has started to deviate from the original goal.
And a very important architectural adjustment in the later stages of this v2 is:
History will continue to be retained, but future work will no longer require infinite forward tracing and reconstruction of all past states.
This is also the topic the next article will organize.
Because if this article is answering:
Why is history worth keeping?
Then the next article will answer another equally important question:
When should restoring history stop?
And this question is precisely one of the important reasons why the actual development time for this v2 far exceeded initial expectations.
