Recently, I have been continuing to push forward my Go Learning & Documentation multilingual project.
As I progress, I have become increasingly aware of one issue:
Infrastructure is meant to serve translation; a translation project should not ultimately turn into an infrastructure project.
Unfortunately, I fell into this trap again this time.
And I fell deeper than before.
v2 was initially estimated at 5 working days; now it has exceeded 30 working days and is still not live
Looking back now, the most unacceptable thing to me is not that v2 itself became more complex.
It is that the gap between it and my initial expectations has grown so large that it is almost incomprehensible.
When I first decided to build Site v2, my thinking was actually very simple.
v1 was already live, and a large number of foundational capabilities already existed, such as the translation process, glossary, Generation, Reviewer, validation, and breakpoint recovery.
So my initial thought was:
v2 would mainly just add translations for some pages on top of the existing foundation.
I even optimistically estimated:
It would take about 5 working days to complete Simplified Chinese v2.
After I actually started working on it, I realized things were not that simple.
v2 was not just about adding a few pages.
The scope gradually expanded to include:
- Learn;
- Docs;
- Site shell;
- Homepage;
- Translation;
- Integrated Surface;
- activation;
- preview;
- Production;
It also involved issues like content packages, representation, and cross-surface consistency.
At this stage, I realized:
5 working days was definitely unrealistic.
So, I constantly adjusted my expectations.
If it ultimately took a dozen or so working days, I could accept that.
Even if it took close to 20 working days, considering this was the first time establishing a complete Site v2 process, I felt I could reluctantly accept it.
Because some of these engineering capabilities could theoretically be reused for other languages later.
But the problem now is:
It has already exceeded 30 working days.
And what’s worse:
Even now, I still cannot determine when Simplified Chinese v2 will actually go live.
This is the most frustrating part.
If I had estimated 20 days and it ended up taking 22 or 25 days, I could at least say it was a project estimation error.
But this is no longer a simple estimation error.
Initially:
Estimated 5 working days.
Later:
20 working days was reluctantly acceptable.
Now:
Over 30 working days, still not live, and the launch date remains uncertain.
This indicates that there is a fundamental problem with the project process itself.
What I find even more unacceptable is:
This is not because I translated dozens of times more content.
I feel that the time actually spent on “translating the content itself” is less than 10% of the entire project duration.
A massive amount of time was consumed on:
- workflow;
- currentness;
- authority;
- recovery;
- representation;
- historical proof;
- successor;
- Surface;
- producer;
- and new mechanisms continually added to fix these mechanisms.
In other words:
A translation project originally estimated to take 5 working days was ultimately dragged out to over 30 working days—not because “translation was too slow,” but because the infrastructure built around the translation became increasingly complex.
This can no longer be simply explained as:
“v2 has a larger scope than v1, so it takes longer.”
If it were just a scope expansion, doubling or tripling the investment might still be understandable.
But when a v2 that already has v1 experience and a large amount of existing infrastructure ultimately takes longer than the initial Simplified Chinese v1 took to go from scratch to live, and after more than 30 working days there is still no clear end in sight,
it shows that:
The infrastructure is no longer helping to accelerate the project; it is slowing down the entire project.
A punctuation issue ultimately turned into several days of infrastructure engineering
What happened over the past few days is particularly typical.
Initially, I was not facing any massive translation errors.
Nor had the entire upstream documentation changed.
A significant portion of the issues were just:
- Chinese and English punctuation;
- representation;
- differences between the historical decoder and the current implementation;
- the current program being unable to re-prove historical installed proof.
In fact, a very important historical breakpoint already existed before this.
The corresponding batch of Learn / Docs translations had already been completed at that time:
32/32 validation PASS
The previously successful TranslationUnit was fully preserved.
The failed Unit had also passed validation after a retry.
In other words:
The translation results themselves had already passed formal validation.
If I had followed the “historical breakpoint recovery” approach I had already established, the first question to consider at this point should actually have been:
Can this legitimate historical PASS be used directly as a recovery breakpoint?
And then further assess:
Is there any evidence proving that these translation contents themselves have become invalid?
If not, the original results should be preserved as much as possible, and only the truly affected parts should be processed.
But that is not how things went this time.
The problem gradually evolved into:
historical construction bytes
→ installed-derived transport recovery
→ mixed-role attribution
→ role-separated producer
→ semantic IR
→ source-to-role closure
→ per-Unit dependency proof
→ producer3
→ currentness integration
At this point, I suddenly realized:
I was no longer recovering a translation task.
I was building an entire system to re-prove how past programs generated historical results using the current code.
The engineering complexity of these two things is not on the same order of magnitude at all.
A problem that could have been solved in about a day ultimately took around four days
This is one of the things I regret most this time.
Looking back at it now, I believe:
If I had directly adopted the existing historical breakpoint, first accepted the legitimate 32/32 validation PASS at that time, then determined whether there was any actual content semantic invalidation, and finally only reopened the truly affected TranslationUnit,
this issue could likely have been resolved in about a day.
At the very least, it would not have devolved into spending several consecutive days building recovery infrastructure.
But the reality was:
To prove why a historically PASSed result could continue to be used, I spent another four days or so continuing to perfect the infrastructure.
And even now, the related implementation is not completely finished.
This is absurd.
The purpose of a historical breakpoint existing in the first place is:
Not to redo things that have already been proven.
Yet this time, to re-prove “why this historical breakpoint can still be used,” another mechanism was created that is far more complex than the original recovery process.
Fail-closed was taken too far
My multilingual project has always emphasized one principle:
fail closed.
If you cannot confirm that a mutation is safe, do not execute it blindly.
There is no problem with this principle itself.
I even think it is an important foundation for the long-term maintenance of this project.
The real problem is:
This time, fail-closed was taken too far.
It gradually became:
If the current implementation cannot re-prove historical results, the infrastructure must continue to be perfected until it can be re-proven.
Looking back now, these two things are actually not the same at all.
Fail-closed should mean:
If you cannot prove a new operation is safe, do not execute the new operation.
But it does not mean:
Every past legitimately PASSed result must be able to be formally re-proven by future versions of the program.
If a historical result already had:
- formal Generation;
- validation PASS;
- identity;
- SHA;
- provenance;
- no subsequent conflicting mutations;
- no evidence proving content semantic invalidation;
then this historical PASS itself should be a trusted recovery breakpoint.
implementation changed
It should not automatically be equivalent to:
historical content invalid
These are two completely different concepts.
Every blocker can lead to building another layer; this is the most dangerous part
What really put me on alert this time was not that any specific design was particularly bad.
On the contrary, many of the designs actually look quite reasonable when taken individually.
For example:
Historical construction bytes are insufficient?
Then supplement the historical construction authority.
Found that declaration simultaneously bears multiple responsibilities?
Then design mixed-role attribution.
Found that approvedResponseInputs cannot be safely categorized?
Then design a role-separated producer.
Found that role equality is not strict enough?
Then design a semantic IR.
Found that batch-level delta cannot accurately determine the affected Unit?
Then continue designing per-Unit dependency proof.
Every step can be justified with sufficient technical reasons.
Every step can explain:
“Why doing this is reasonable.”
But the real missing question is:
Why are we still doing this?
This question, however, was not continually re-examined.
Thus, a very dangerous path was formed:
Fix a blocker.
Discover another blocker.
To make the upper-level design hold, build the next level.
The next level reveals a new formal gap.
Continue patching it.
Technically, every step is self-consistent.
Overall, it has completely deviated from the project’s true goal.
A danger of reinventing the wheel: everything can always be improved
Developing your own infrastructure has a very obvious advantage:
Control.
I can control:
- schema;
- identity;
- retry;
- QC;
- recovery;
- currentness;
- provenance;
- CAS;
- activation;
- historical evidence.
When the project encounters special situations, I can also continue to modify the system to cover new scenarios.
This is certainly very appealing.
But this time it made me even more aware:
The biggest problem with reinventing the wheel is precisely that:
Everything can always be improved.
There is no natural boundary telling you:
“Enough.”
Mature frameworks often force developers to accept some existing designs.
When writing your own, it is easy to develop another mindset:
Since this problem can theoretically be solved, let’s solve it.
The problem is:
Just because it can be solved theoretically does not mean it is worth solving in the current project.
If engineering design has no stop line, it can easily expand infinitely downward.
This is not the first time this has happened
What makes me feel even worse is:
This is not the first time I have encountered the problem of infrastructure over-engineering.
Previously, during the translation of historical blog posts, I went through a similar situation.
At that time, it was likewise for:
- translation consistency;
- automation;
- recovery capability;
- state management;
continually improving the translation infrastructure.
Only later did I realize:
A massive amount of time was eaten up by the infrastructure itself.
Because of that experience, when working on this multilingual project, I was actually subconsciously trying to avoid it happening again.
Many principles had even been formed within the project:
- do not redo trusted outputs;
- recover first on failure;
- if there is a historical breakpoint, continue from it;
- strictly isolate Generation and Reviewer;
- do not infinitely optimize for extreme performance;
- prioritize Codex quota for correctness blockers;
- do not re-verify legitimate PASSes.
Theoretically, these principles should have been able to prevent the same problem from appearing again.
Yet it still happened.
And I feel:
This time it is even more severe than during the historical blog post translation.
Because this time the infrastructure not only consumed development time.
It also directly blocked the v2 launch.
Codex’s weekly quota made this problem even worse
If it were just an increase in local development time, the problem might not have been so obvious.
But now there is also a very real constraint:
Codex has quotas.
I am using ChatGPT Plus.
Not only is there a 5-hour window quota, but more importantly, there is a weekly quota.
When the 5-hour quota is used up, it can recover after a few hours.
But if the weekly quota is consumed by a large amount of infrastructure work, the entire project will come to a direct halt when it actually needs Codex.
And recently, a large amount of quota has been consumed on:
- understanding complex workflows;
- formal contract;
- historical reconstruction;
- static analysis;
- semantic IR;
- projection;
- dependency proof;
- design review;
- successor review;
- recovery infrastructure implementation.
This work is certainly not without value.
But the problem is:
Actual translation, revision, review, and launch also need these quotas.
Thus, an absurd result occurred:
To make the translation process more reliable, the model quota that could have been used to continue advancing the translation project was consumed.
Infrastructure is supposed to increase throughput.
If an infrastructure continually decreases the throughput of the entire project, then it should be re-examined.
The 5-hour quota is not the only problem; the weekly quota is the real bottleneck
Earlier on, I focused more on Codex’s 5-hour quota.
Later, it became increasingly obvious that:
What really matters is actually the weekly quota.
If it is just a 5-hour window being used up, you can continue after the next recovery cycle.
But if a complex infrastructure task continuously consumes several windows, then what is truly affected is the development capacity for the entire week.
And I still have:
- zh-CN Site v2;
- subsequent other locales;
- Generation;
- Reviewer;
- activation;
- Production;
- other multilingual project research;
All of these require Codex.
If a large amount of weekly quota is spent on a problem that could have been recovered from a historical breakpoint, then from the perspective of the entire project portfolio, the return on investment is very poor.
So from now on, Codex quota can no longer be treated as an “internal tool limit.”
It should be treated as:
A formal project resource.
Just like development time, it needs to be budgeted.
Why Co-op Translator is starting to look increasingly valuable
This is also why I have increasingly felt lately that Microsoft’s Co-op Translator might be very valuable.
Not because it will necessarily meet all my needs.
Nor because it will definitely be stricter than the solution I designed myself.
But because mature frameworks have an often-overlooked advantage:
They set an external upper limit on infrastructure complexity.
If using an off-the-shelf framework, when encountering a problem, it is easier to consider:
How can this be solved within the framework’s existing capabilities?
Whereas when reinventing the wheel, it is easier to consider:
Should I add another new schema?
Should I add another authority?
Should I add another type of currentness proof?
Should I design another set of projections?
Should I build another IR?
The answer to each of these could be “yes.”
And then the project becomes increasingly heavy.
This time it made me realize more clearly:
Control is not free.
Excessively pursuing control can itself become the project’s biggest uncontrollable factor.
This does not mean immediately migrating to Co-op Translator now
Of course, this lesson should not swing to the other extreme either.
If I immediately initiate:
“Migrate the entire go-tour-i18n to Co-op Translator”
just because I feel the infrastructure is too heavy now, it would likely turn into another large-scale infrastructure engineering project lasting several weeks.
This would just be repeating the same problem in a different way.
So I am now more inclined to:
Not immediately migrate the existing go-tour-i18n.
Continue to use the mature capabilities that already exist.
But for future new multilingual projects, before designing infrastructure from scratch, prioritize asking:
Can Co-op Translator or other mature solutions directly handle 70% to 80% of the foundational capabilities?
If so:
reuse them as much as possible.
The project itself only maintains a thin layer of special logic.
Rather than defaulting to reinventing an entire translation infrastructure.
A historical PASS should truly become a breakpoint
After this incident, I believe a rule needs to be formally strengthened in the repository:
Historical PASS First
A legitimate, complete historical PASS with no subsequent conflicting mutations should by default be treated as a trusted recovery breakpoint.
Unless there is clear evidence proving that:
- the canonical source has undergone semantic changes;
- the membership has undergone relevant changes;
- the protected representation has become invalid;
- the dependency has actually changed;
- validation has explicitly determined the historical output to be invalid;
Otherwise:
Do not require the current implementation to re-prove historical implementation semantics.
Especially not just because:
- the implementation SHA changed;
- the decoder implementation changed;
- the producer implementation changed;
- the workflow code changed;
you automatically assume that the historical translation results need to be re-proven.
This should become the true default recovery strategy.
Building new infrastructure must become the last option
When encountering a recovery blocker in the future, the decision sequence should become:
Step 1:
Is there a legitimate historical PASS that can serve as a breakpoint?
Step 2:
Is there clear evidence proving that the historical content has become semantically invalid?
Step 3:
If it is indeed invalid, can only the exact affected scope be reopened?
Step 4:
Can existing recovery / retry / successor mechanisms solve it?
Only when none of these can safely continue,
is it permissible to consider:
adding new infrastructure.
In other words:
Adding new infrastructure should become the last option.
Rather than, upon seeing a current proof construction failure, immediately reacting by continuing to perfect the proof system.
An “infrastructure complexity stop line” must be added
After this incident, I plan to formally add relevant rules to the repository documentation and project instructions.
In particular, one needs to be added:
Mandatory Complexity Reassessment
If a localized translation or recovery problem exhibits any of the following:
- estimated engineering time exceeds 1 working day;
- requires adding a new formal schema;
- requires adding a new authority;
- requires modifying currentness;
- requires modifying mutation / CAS semantics;
- requires building AST / IR / static analysis;
- requires adding a new historical reconstruction mechanism;
- a blocker consecutively spawns a second layer of new infrastructure blockers;
a mandatory stop must occur.
Then re-examine:
Is there a historical breakpoint that can be recovered?
You cannot continue patching all the way down along the current infrastructure route.
This step previously lacked a true hard stop line.
This time it must be added.
Having already spent a lot of time is not a reason to continue
Additionally, a principle needs to be clarified:
Sunk costs cannot become a reason to continue developing a subsystem.
For example:
“I’ve already spent three days on it; let’s spend two more days to finish it completely.”
This kind of thinking is very dangerous.
Because it can easily drag a technical route that has already suffered cost overruns into even greater losses.
If a new assessment finds that:
- the historical PASS can be safely recovered;
- the unfinished infrastructure has no obvious benefit for multiple future locales;
then it should be permissible to:
freeze the unfinished infrastructure.
Rather than feeling compelled to finish it just because a lot has already been invested.
Codex must also redivide its responsibilities
There was also another obvious problem this time:
Some deterministic work that could have been done by the Local terminal also consumed Codex quota.
Going forward, the division of labor must be stricter.
Codex is primarily used for:
- engineering that requires modifying repo code/docs;
- correctness blocker;
- real defects that can be reused across locales;
- activation / Production blocker.
The Maintainer Local terminal is responsible for:
- read-only inspection;
- inventory;
- currentness reassessment;
- proof;
- contract verification;
- first-real-use gate;
- deterministic workflow;
- formal command execution;
- Git checkpoint;
- push.
In particular:
Codex can no longer be allowed to heavily consume quota doing read-only reviews that can be performed by the Local terminal.
The Codex weekly quota itself is a project resource.
It must be reserved for work that truly requires code reasoning and code modifications.
Reviews must also have a cost ceiling
This time, even the design review became too heavy.
Doing a complete, independent review for the first high-risk formal design is reasonable, I think.
Because the first review did find real problems.
However, a successor review should not re-review the entire system from scratch every time.
By default, future reviews should only check:
- the previous round’s findings;
- the modified areas this time;
- bounded regression surface.
Parts that have legitimately PASSed and were not touched by this revision should not undergo a full review again.
Otherwise, the review process itself, “intended to ensure quality,” will also become a new resource black hole.
A translation project should ultimately be measured by content throughput
This time made me rethink a most basic question:
How exactly should a translation project measure progress?
Previously, I tended to focus on:
- whether the workflow is complete;
- whether the authority is strict;
- whether currentness is provable;
- whether recovery is reliable enough;
- whether provenance is complete.
These are all important.
But now I feel an even simpler, more direct metric must be added:
How much content has actually been translated, reviewed, and gone live?
If a translation project spends several consecutive weeks perfecting infrastructure,
while the translated content that actually goes live shows no significant growth,
this in itself should be viewed as an architecture warning.
It is not “the project is diligently laying the groundwork.”
Rather:
The project may have deviated from its main goal.
A translation project should first and foremost be a translation project
The core main process of a translation project should ultimately be very simple:
Translate → Validate → Review → Launch
The reason infrastructure exists is to make these four steps:
- more reliable;
- faster;
- easier to recover;
- easier to reuse across locales.
Not to make these four steps increasingly difficult to happen.
If an infrastructure system ultimately needs to spend days proving:
“Why a translation result that has already validation PASSed can still be used,”
then you should stop and rethink:
What problem are we actually solving?
This Site v2:
Initially I estimated:
5 working days.
Later, after discovering the scope expansion:
20 working days, which I could also reluctantly accept.
Now:
It has already exceeded 30 working days.
And Simplified Chinese v2 is still not live.
Even when it can go live is still uncertain.
This result is enough to show me:
Infrastructure design has gone out of control.
The cost of this lesson is very high.
Not just in time.
Also in Codex’s 5-hour quota.
And the even more precious weekly quota.
And the other languages and projects that have been delayed.
So this time, I cannot just write a blog post to summarize it and then continue as before.
I plan to truly write this lesson into:
- repository documentation;
- workflow;
- project instructions;
- recovery decision principles;
- Codex usage rules.
Because I have already encountered a similar problem once during the historical blog post translation.
If a true stop line is not formed this time,
it could still happen a third time in the future.
And for the third time, I do not want to pay the same price again.
