没有不值得去解决的问题,也没有不值得去学习的技术!

Why Do Two Extra Pages Trigger a 49→51 Migration?

Why Do Two Extra Pages Trigger a 49→51 Migration?

作者:

在

While maintaining a Go multilingual translation project recently, I encountered a change that looked trivial but turned out to be far more complex than expected.

The original learn-docs-v1 content package already contained 49 pages, and these 49 pages had not just been translated. They had already gone through translation generation, machine verification, candidate snapshots, independent quality reviews, precise revisions, independent re-reviews, and A-only finalization.

Based on its state at the time, this content package was very close to completion.

Later, I realized that two more pages should have belonged to this set of Learn / Docs content from the start: /doc/ and /doc/install.

As a result, the current full membership went from 49 Pages to 51 Pages.

On the surface, this seemed like just adding two more pages. But once I actually started handling it, I quickly realized that 49 → 51 was not simply adding two translation tasks; it was a formal content package membership migration.

The cost of these two scenarios is not even in the same order of magnitude.

If it had been 51 pages from the start, things would have been much simpler

Suppose the project had confirmed from the very beginning that learn-docs-v1 contained 51 Pages. The entire process would have been very straightforward.

For subsequent new languages, translation generation could have been split into two batches right from the start based on the full membership: the first batch processing pages 1–30, and the second batch processing pages 31–51.

The independent quality reviews could likewise have been conducted in two groups: 1–30 and 31–51.

After the two batches of translation generation and machine verification were completed, a complete candidate snapshot would be created. Once the initial independent reviews for both groups were fully recorded, the issues requiring revision would be consolidated, followed by centralized revisions, independent re-reviews, and A-only finalization.

Throughout the entire lifecycle, it would have been known from the beginning that the final deliverable was 51 pages.

All formal identities, candidate snapshots, review scopes, and final confirmations would have been built around these 51 pages.

In this scenario, there would be no membership migration, nor any issue of adding pages 50 and 51 into the formal lifecycle after the original 49 pages were already completed.

What is truly expensive is that the first 49 pages already have a formal history

This is exactly where the problem lies.

By the time I discovered the two missing pages, the original 49 pages were no longer just ordinary files. They already possessed translation generation results, machine verification results, candidate snapshots, independent review results, precise revision records, independent re-reviews, final confirmations, current authorization relationships, and their corresponding SHAs and identity identifiers.

Therefore, it cannot simply be assumed that 49 plus 2 naturally equals a new, complete 51-page state.

Many of the formal artifacts express not just “these 49 pages are well translated,” but rather “for the formal content package membership set at that time, these 49 pages have completed the corresponding stages.”

Once the content package membership changes, the questions become: which old conclusions can still be inherited, which states must be rebuilt, what the new complete content package identity is, whether the old candidate snapshot can still serve as the current snapshot, and how the newly added pages should enter the formal review scope.

This is where the membership migration starts to get complicated.

Adding two pages does not mean the old lifecycle can be automatically inherited

The most intuitive thought is: the old 49 pages have all been reviewed as A, so just translate and review the two new pages separately, and we are done, right?

From a purely linguistic quality perspective, this idea seems fine.

However, the formal workflow also has to deal with another layer of reality: the current complete content package has changed.

It was originally learn-docs-v1 = 49 Page, and now it has become learn-docs-v1 = 51 Page.

This means the complete membership relationship requires a new formal authoritative state, and the candidate snapshot must also be able to represent the current complete 51 pages.

The portions of the historical 49 pages that can continue to be inherited need explicit justification for why they are still valid; the two newly added pages must enter the current lifecycle, and they cannot skip their own translation generation, quality review, and final confirmation just because the adjacent 49 pages are already done.

What truly needs to be established is a chain that can explain the complete history: why the old 49 pages remain valid, why the 2 newly added pages have completed their own formal processes, and why these 51 pages can now jointly form the new complete content package.

Migration costs are often far greater than the new content itself

This is also the most noteworthy part of this experience.

If you only count the translation workload, the newly added content is just two pages, which makes the cost seem very low.

But once the content package has entered the formal lifecycle, the actual work brought about by adding new members may include updating the formal membership authority, creating a new complete candidate snapshot, determining which historical pages can be inherited, identifying which pages need re-reviewing, updating current authorizations, re-establishing the complete package identity, and continuing to handle subsequent reviews and the archiving’s dependency on membership changes.

At the same time, you must also ensure that the old formal history is not overwritten.

Therefore, adding 2 pages does not mean adding only the workload of 2 pages.

The true cost also includes membership migration, historical inheritance justification, and the re-linking of the subsequent lifecycle.

This is why “adding a few pages later” can sometimes be much more expensive than organizing the membership completely from the start.

The later the omission is discovered, the higher the cost

If the membership omission happens at the very beginning, the handling cost is actually very low.

For example, if it is discovered before formal Generation has even started that the originally prepared 49 pages should actually be 51 pages, you only need to fix the membership list. The system has no candidate snapshots, no review results, no final confirmations, and certainly no historical inheritance relationships that need explaining.

If the omission is discovered after translation generation is finished, the migration cost already begins to appear.

If it is discovered after the independent reviews, the cost continues to increase.

If A-only finalization has already been completed and an omission is then found, the difficulty of handling it becomes significantly higher.

If the omission is only discovered after the content package has entered archiving, integrated site review, activation, or even the production environment, the scope of impact will expand even further.

Therefore, the cost of a membership omission does not increase linearly. The closer it is to the backend of the lifecycle, the higher the repair cost typically is.

When adding a batch of pages in the future, I prefer to do a complete membership audit first

After this experience, I started rethinking the idea of “adding a batch of brand-new pages.”

Previously, I might have first asked how to translate these pages. Now, I feel the first question should be: which pages does this batch actually include in full?

Before formal Generation begins, you should try to organize the current membership list as completely as possible.

In particular, you need to check for content that is easily overlooked, such as section entry pages, index pages, installation pages, overview pages, top-level entries like /doc/, pages accessible via navigation but easily mistaken as non-main text, and pages located at different paths from the main content but actually belonging to the same product surface.

Doing this is not about pursuing formal perfection.

The real reason is that once the lifecycle begins, the membership list is no longer just an ordinary to-do list.

Translation generation, candidate snapshots, independent reviews, final confirmations, and content package archiving will all progressively consume this membership definition.

The later you modify it, the more it resembles a formal migration rather than a normal edit.

“Do part first, add the rest later” is not always more agile

In ordinary content projects, completing a portion first and continuing to add content later is usually a very reasonable approach.

But a formal translation workflow has an obvious difference: for every stage completed, the system accumulates new historical states.

If you can already reasonably determine that this batch of pages ultimately belongs to the same complete content package, then doing 49 pages first and adding 2 more after everything is finished may not necessarily save more time than confirming 51 pages from the start and entering the lifecycle together.

The former approach seems to start faster, but you have to pay a membership migration cost later.

The latter approach requires a little more time upfront to verify the scope, but it allows the entire subsequent lifecycle to remain stable.

This is also why I now place increasing importance on upfront completeness.

Of course, it is impossible to predict all future content at once

A boundary needs to be drawn here.

I am not saying that a content package can never have new pages added after it is established.

Real projects will definitely continue to evolve, and Go’s official documentation may also add genuinely new pages in the future. It is impossible to predict all of this future content today.

This kind of future addition is not exactly the same as this 49 → 51 situation.

What I truly want to avoid is: pages that currently exist and logically clearly belong to the same batch of formal content being omitted due to an incomplete upfront inventory.

This type of omission can usually be minimized through a membership audit before the formal lifecycle begins.

So the goal is not to predict all pages for the next few years at once, but rather to organize the formal membership as completely as possible before the current lifecycle begins, based on the canonical source that already exists.

Genuinely new future content can still enter through the formal successor process.

These two things do not conflict.

The membership list itself is part of the architecture

This migration also made me rethink the content membership list.

It used to be easy to view it as just a file list, but as the entire multilingual workflow becomes more formal, I increasingly feel that the membership list itself is part of the architecture.

It determines what belongs to the current content package and what does not; what translation generation should cover; what reviews should evaluate; what final confirmations actually confirm; when a content package can be considered complete; and which formal content the subsequent integrated site review is built upon.

Therefore, membership is not auxiliary data that can be casually modified after the lifecycle begins.

It is closer to a machine definition of what the current product surface officially contains.

Once it has been consumed by multiple subsequent stages, it should be subject to constraints similar to other formal authoritative states.

Subsequent languages should not repeat the history of 49 → 51

This migration has at least one benefit: it happened in Simplified Chinese, the language used to establish the complete process.

The engineering cost paid here can be transformed into a stable process that subsequent languages can directly reuse.

Therefore, new locales in the future should not repeat the history of “doing 49 pages first, discovering 2 more pages after completion, and then redoing a 49 → 51 migration.”

Subsequent languages should start directly from the current complete authority, that is, from learn-docs-v1 = 51 Page.

This way, the migration cost paid by Simplified Chinese this time becomes a one-time architecture cost, rather than one that every other language has to pay again later.

This is also the role I have always hoped the first language would play.

It is not just about translating into Chinese; more importantly, it is about stabilizing the process that dozens of subsequent languages will need to reuse.

If I were to do it over, I would reverse the order

If I were to start this batch of Learn / Docs pages over, I would now adopt a different order.

The previous process was closer to: find the main pages first, then start translating; after translation and review are completed, discover omissions, and finally perform a membership migration.

Now, I would first inventory the canonical source, build a complete candidate membership list, check entry pages and special pages, lock down the formal membership for this round, and only then start Generation.

This step might only require adding a bit of upfront check time, but it protects the entire lifecycle that follows.

In terms of return on investment, it is usually very worth it.

Finally

This recent change of learn-docs-v1 from 49 Pages to 51 Pages made me truly realize a very simple but important rule:

The earlier a content scope error is fixed, the more it resembles a normal edit; the later it is fixed, the more it resembles a formal migration.

When a content package has not yet entered the formal lifecycle, 49 → 51 might just be modifying a membership definition.

But once the 49 pages already have translation results, candidate snapshots, independent reviews, and final confirmations, that same 49 → 51 is an entirely different matter.

So, when adding a whole new batch of pages in the future, I will try my best to organize the current formal membership completely first.

This is not because content can absolutely never be added later, but because if two pages that already exist today originally belonged to this batch, then the cheapest time to handle it is before the first Generation begins.

What truly needs to be avoided is not all future migrations, but rather those migrations that could have been avoided through a complete inventory.

系列导航

关于作者 · 持续学习与技术实践

我是一名拥有 15 年以上开发经验的技术从业者,自 2013 年起持续运营个人技术博客,记录工作与个人项目中遇到的真实问题,以及解决问题过程中的探索、实践和思考。

除了技术写作,我也在持续开发和维护自己的独立项目,探索新技术和新工具在实际场景中的应用。我始终相信,没有不值得去解决的问题,也没有不值得去学习的技术。

如果这篇文章对你有所帮助,欢迎浏览博客中的其他文章,也欢迎交流技术经验与想法。

关于我  ·  GitHub  ·  邮件联系