Automation creates a seductive expectation: if a machine can complete an operation in seconds, it should run without interruption from discovering a file to changing a live website. In practice, the faster a system moves and the more authority it holds, the more it needs a deliberate stopping point before the first write. That pause is not leftover bureaucracy. It is the boundary between describing an intended change and making that change real.
Without such a boundary, a small ambiguity can spread quickly. A filename may be temporary. A browser session may have expired. A category may exist under a different parent. A bilingual article may contain only one finished language. If the system discovers each problem after it has begun writing, the website can be left with a chain of partially completed objects that a person must reconstruct later.
A preflight stop does not mean that a human must approve every article with a button. It means the system has a read-only phase in which it resolves every question that can be resolved before mutation. It validates the directory, metadata, bilingual titles, body lengths, category hierarchy, tags, slug policy, publication status, timing and browser authentication. Only when the complete batch passes does the program cross the write boundary.
A file is not automatically a publishing instruction
The appearance of a new Markdown file proves only that a file exists. It may still be under revision. It may be a research note, an outline, a series index or a Chinese draft awaiting an independently written English version. A scanner that treats any new file as publishable quietly turns a directory into a publication button, even when the writer does not know that saving a file has pressed it.
A safer queue requires two explicit layers of intent. The publication metadata describes the batch: whether it is enabled, whether it is ready, which category path it belongs to, which tags are shared, whether the items are drafts or public posts, and whether the batch is immediate or scheduled. Each article then has its own metadata: stable ID, source file, order, slug, Chinese and English titles, article-specific tags and a declared policy for an existing slug.
This is also why the queue must be separate from archives, drafts, scripts and source material. Scanning an entire project may look convenient, but it expands the system’s authority to files it cannot reliably interpret. A narrow queue is a security boundary. The publisher does not need to understand every document in the repository; it needs to reject everything outside the one directory that has been placed under its control.
Valid prose is not the same as a complete destination
An article can be well written and still be an incomplete publishing task. Without a fixed slug, category and tags, the machine must invent part of the site’s structure. One run may classify a piece under Digital Life, while a later version creates a new AI category because the title contains a fashionable term. Over time, temporary guesses made for operational convenience become permanent changes to the intellectual map of the site.
Metadata turns those guesses into reviewable inputs. The system may create a missing subcategory when the hierarchy is explicitly declared, but it should not infer a new hierarchy from a similarity score. A category path is an editorial decision expressed in a form that code can validate. Tags are handled in the same way: they are named, given stable slugs and checked for duplicates before any request reaches WordPress.
Bilingual titles deserve their own fields. Combining Chinese and English into one WordPress title avoids a translation step, but both language versions then display a mixed heading. The better pattern is to store the English title as the default WordPress title and save the Chinese title as the TranslatePress translation of that exact string. The English and Chinese pages share one slug while presenting an H1 appropriate to each language.
That process only works when the intended titles are unambiguous. Before writing, the queue validator should require both titles and compare them with the first two H1 lines of the source document. Later, the browser should select a TranslatePress source string that exactly equals the English title. A fuzzy match is unsafe: a site may contain similar titles, menu labels or excerpts, and choosing the nearest text can alter an unrelated translation.
Possessing a credential is not the same as being ready to execute
A WordPress OAuth access token can authorise REST API requests, but it does not become an authenticated wp-admin browser session. TranslatePress title editing occurs through the browser interface and therefore needs a genuine session established through the site’s normal login process. These are two different credentials for two different surfaces.
If the publisher creates the article first and only then discovers that the browser cookie has expired, it leaves a half-finished result: the body exists, but the Chinese title does not. The safer order is to launch headless Chromium before any API write, navigate to wp-admin and prove that the stored session is still authenticated. If the preflight fails, the entire batch stops while the site remains unchanged.
This design also avoids storing a long-lived WordPress password in the automation. A user can complete a normal login and any second-factor challenge in a trusted local browser. The resulting time-limited session state is then stored as a protected runtime secret for the background job. The job consumes the session without learning the password. When WordPress expires the session, the job fails closed and asks for a new legitimate login rather than attempting to evade the authentication boundary.
A successful request is not proof of a correct result
An HTTP success response means that a server accepted a request. It does not prove that the post is in the intended category, that its status is really draft, or that the Chinese page displays the Chinese title. Reliable automation needs verification at several levels.
The REST response should preserve the WordPress object ID, slug, link and status. Categories and tags should be bound by the IDs returned by the site, not merely assumed from their names. After TranslatePress saves the title, the browser should open both language versions. The English H1 must exactly equal the English metadata title; the Chinese H1 must exactly equal the Chinese metadata title; the slug must remain the same apart from the Chinese language prefix.
Drafts need these checks too. A draft is not publicly visible, but it is still a real database object that can be previewed, edited or accidentally published later. Marking a test article as draft reduces its immediate impact; it does not remove the need for correctness. A meaningful smoke test proves the entire chain works: a GitHub change, a private container image, Azure identity, runtime secrets, the WordPress API, headless Chromium and bilingual verification. Demonstrating that a local script can run is only one small part of that chain.
Retryable does not mean duplicable
Cloud tasks sometimes fail for ordinary reasons: a connection closes, a runner restarts, an API slows down or a browser page exceeds its timeout. Retrying is therefore a normal capability. But if every retry creates another post, the reliability mechanism becomes a duplicate-content generator.
The slug can serve as an idempotency key. Before a write, the publisher searches for an existing object with that slug and follows an explicit policy: skip it, update it, or treat it as an error. A test draft is well suited to the update policy. The first successful run creates one draft; a retry repairs or completes that same object instead of making a second copy.
Idempotency is not permission to overwrite anything. The update policy must be chosen in the article metadata, not invented by the program when it encounters a conflict. Overwriting a public article that may already have readers, links or editorial changes is especially consequential. A trustworthy system exposes the conflict and stops unless its instructions clearly authorise the change.
A background service does not have to be permanently alive
Publishing does not require a continuously running server or an externally accessible user interface. A finite background job fits the work better. GitHub Actions observes a meaningful queue change, builds a private image, updates a Container Apps Job with no ingress, and starts one execution. The job validates, writes, verifies and exits. With no new work, there is no running instance.
The trigger deserves the same careful boundary. A source-code change may rebuild and deploy the image, but it should not publish an article. A documentation edit should not publish one either. The execution should start only when real queue inputs change: publication metadata, article metadata, article bodies or a declared series page. Deployment and publication are separate actions, and separating them makes it possible to improve the machinery without unexpectedly changing the website.
This model also produces a useful cost and security property. The container exists only for the duration of the task, and there is no inbound endpoint for strangers to probe. Its WordPress token and browser state are injected at runtime. The private image contains only the publishing code and the explicitly queued content, not the rest of the author’s working directories.
A stored secret must not become source code
The OAuth token, browser session and image-pull credential belong to the execution environment. They may be referenced by a Container Apps Job, but their values should never appear in a Git commit, build log, command output or article metadata. The repository can safely contain the names of environment variables and secret references. It must not contain the values.
This remains important even when the repository is private. Version history is durable and widely replicated, while runtime credentials need to be rotated and revoked independently. A browser session should expire without requiring a code change. An OAuth token should be replaceable without rebuilding an article. Keeping secrets outside the repository preserves that separation.
Logs need the same discipline. A good execution report can identify the publication ID, slug, WordPress object ID, action, status and verification result without printing an access token or cookie. Observability does not mean disclosing everything. It means preserving enough non-sensitive evidence to understand where the system continued and where it stopped.
Trustworthy automation is designed to stop early
The objective is not a system that never stops. It is a system that stops while mistakes are still cheap. A directory error found during local validation costs a small edit. An expired browser session found during preflight costs a new login. A slug collision found before writing costs an explicit policy decision. When those same problems survive until after public release, the cost becomes duplicate removal, broken-link repair, translation reconstruction and an explanation to readers who encountered incomplete work.
The pause before writing is therefore not the opposite of automation. It is the structure that makes sustained automation credible. Inputs have a narrow boundary. Intent is recorded as metadata. Credentials are isolated in the runtime. Writes are idempotent. The browser authenticates before mutation. Results are verified in both languages. The job exits when the work is complete.
The more clearly a system can explain why it is continuing and why it has stopped, the more safely people can entrust consequential work to it. Speed matters, but a dependable publishing system earns trust through controlled boundaries, precise evidence and the ability to leave the site unchanged when any prerequisite is uncertain.
Discover more from Geoffrey Chen
Subscribe to get the latest posts sent to your email.