Background
T433014: Redefine "task completion" for HotCat essential task using on-wiki signals established the model for the HotCat task: a task run is complete when a server-verified, user-attributable on-wiki artifact exists — the in-app "Done" click is UI-only. It introduced the task_verifications ledger (UNIQUE(wiki_url, task_key, username, article_title)), three idempotent verification triggers (in-flow check, completion-status read, in-process sweep), and a historical backfill script. The stated scope was to then extend this task-by-task.
This task extends it to "Create essential articles", which is more complex than HotCat, as it has two approaches — translate (via ContentTranslation) and write-from-scratch — with different verifiable artifacts. It is also becoming repeatable (T431065: Make certain essential tasks repeatable): each run should produce a different article, and the run history must be per-user. The first implementation attempt surfaced that the current state model can't support this (see Problem).
Current definition of done: a 0–4 status computed on every completions read — 0 nothing, 1 in progress, 2 published via CT, 3 published + "Mark as done" clicked, 4 article exists on the target wiki but not via CT. Statuses 3 and 4 count as completed. Write-from-scratch has no wiki-side check at all: done = the click (isDone ? 3 : 1).
Problem
The only completion we have ever counted is hollow. On din.wikipedia.org (2026-06-09) a staff account clicked open-editor and mark-done 16 seconds apart. The picked article ("2010") does not exist on that wiki and the account has zero contributions there. This is one of the two task_completions rows in prod.
Real completions were counted as nothing (false negatives):
kcg.wikipedia.org: a user clicked open-editor in the tool (2026-06-28 18:10 UTC) and created A̱sukuru (Screw) at 19:16 the same evening. No completion row, no event.
mni.wikipedia.org: another user confirmed the article pick (2026-07-02 07:53 UTC) and created ꯑꯦꯝꯐꯤꯕꯤꯌꯟ (Amphibian) 16 minutes later. No completion row, no event.
Status 4 credits nobody-in-particular, i.e. everybody. It is computed from wiki-global state (shared article pick + langlink existence), so a pre-existing article marks the task done for every user of that wiki: on pa.wikipedia.org the picked article (Mahatma Gandhi) has existed since 2012 — anyone opening the dashboard there sees the task completed.
The state model is per-wiki where it must be per-user. Which article is being worked on (task_metadata) and the checklist (task_checklists) are single rows keyed (wiki_url, task_key):
- The kcg case above shows it live: the pick was made by a staff account on June 10; a different user inherited and executed it 18 days later.
- A repeat (or any user's new pick) overwrites the shared row, which retroactively changes everyone's computed status — including flipping the original completer back to "not done".
- A repeat run would inherit the previous run's fully-checked checklist, so run_count could be inflated with a couple of clicks and no work.
- There is no record of which article each run produced, so "repeat = a different article" is unenforceable.
What data we have
- Analytics events (starterkit.essential.create_essential_article.*): username, wiki, timestamps, step context, and (since late June) approach — historical events (pre-2026-07-18) carry no title; current events do, via commit e7dcc16. The title lives only in the shared metadata row (last-write-wins, no username, no history).
- task_metadata: 13 wikis have a pick — English source title + approach.
- On-wiki, all public, no OAuth: enwiki langlinks resolve the source title to the target-wiki title; prop=revisions / list=usercontribs attest who created/edited an article and when; the CX API attributes published translations to the translating user (startedTranslator).
Proposed approach
Definition. A run of Create essential articles is complete when the user created the picked article on the target wiki:
- translate: their published CX translation created the page (the CX API attributes publications to the translating user), or they created it manually — the article resolved via langlink exists and its creating revision is theirs.
- write-from-scratch: the article at the captured target title exists and its creating revision is the user's. Knowing that title requires the target-title input introduced in the companion task (write-from-scratch title input, filed separately T433039: Create essential article: Write-from-scratch opens the editor with a hardcoded English title).
- Improving, overwriting, or expanding an article someone else created does not count — the task is create, and suggestions are meant to be missing articles (see "When the picked article already exists" below).
- "Mark as done" click = UI-only, exactly as in T433014: Redefine "task completion" for HotCat essential task using on-wiki signals. The verification is the completion record.
Mechanism. Extend T433014's machinery rather than building new:
- Add create-essential-article to VERIFIABLE_TASKS with its own verifier (per-approach attestation above).
- One ledger row per verified (wiki, task, user, article title); run_count = ledger inserts. The UNIQUE key makes re-crediting the same article impossible — repeating means verifying a new title.
Same three triggers: in-flow status check, any completion-status read (pendingVerification + client resolution), in-process periodic sweep.
A caller's status (the 0–4 scale) is derived from their own ledger/CX state — never from another user's shared row. Status 4 is only reported to a caller who can claim it (own completion row or own edits on the article).
Repeatability model
- Per-run, per-user working state: task_metadata and task_checklists move to (wiki_url, task_key, username) keying; starting a repeat begins with a clean pick and a clean checklist, and never touches anyone else's state.
- The task card's run counter reads the caller's ledger rows.
When the picked article already exists (created in the meanwhile)
The picker only suggests missing articles, but that is not an invariant: races happen (runs span weeks), the missing-check is Wikidata-sitelink-based (articles unconnected to their item pass as missing), the code → dbname heuristic has known failure wikis, and the Wanted-pages source is a cached report. When the "Translate or write" step detects that the picked article now exists and was not created by the user:
- write-from-scratch: hide the checklist (and with it the Mark-as-done action) and show an explanatory warning: someone created this article in the meantime, so this pick can no longer be completed — pick a new article (the re-pick affordance is the "Change article" control from the companion back-button task T433042: Create essential articles: add a way back from "Translate or write" to the article pick step).
- translate: keep the flow, but show a caution message explaining that (1) the article has been created in the meanwhile; (2) they can still publish their translation and overwrite the existing page, but should do so with caution — only if they feel it adds more value; (3) they can instead expand the existing article by translating missing sections; and (4) none of these efforts count as completing this task — to complete it, they need to pick a new article to create.
- Detection uses the same per-caller attestation the verification does (for write-from-scratch it needs the captured target title, another dependency on the title-input companion task T433039: Create essential article: Write-from-scratch opens the editor with a hardcoded English title).
Backfill. Same script pattern as T433014 (dry-run default, --apply, DB backup first):
Resolve historical picks via langlink, attest creator/edits, credit what qualifies. The kcg and mni completions above are recoverable this way.
Scope. This task covers create-essential-article only
The per-user re-keying of task_metadata/task_checklists is designed here but is the general fix for all per-user tasks; remaining essential tasks get their own follow-up tasks under the same model.
Acceptance criteria
- Completion for create-essential-article is recorded by server-side verification of an on-wiki article attributable to the user (both approaches); the "Mark as done" click is UI-only and POST /tasks/complete rejects the task
- Each verified run is a task_verifications ledger row keyed by article title; run_count derives from ledger inserts and the same article can never credit twice
- The 0–4 status returned to a caller is computed from that caller's own state; an article that exists but is not attributable to the caller does not mark the task done for them
- task_metadata and task_checklists for this task are keyed per user; a repeat run starts with a clean pick and checklist and cannot alter another user's state or completed status
- The write-from-scratch flow captures the target article title so its runs are verifiable (delivered by the companion target-title-input task T433039: Create essential article: Write-from-scratch opens the editor with a hardcoded English title; this task consumes the captured title)
- Only article creation credits a run: overwriting or expanding an article someone else created never counts, for either approach
- Write-from-scratch, picked article exists: the checklist and Mark-as-done are hidden and a warning explains the user needs to pick a new article
- Translate, picked article exists: a caution message explains they may overwrite (with care, only if it adds value) or expand the existing article, and that neither completes the task — only picking a new article to create does
- Verification runs through the three T433014: Redefine "task completion" for HotCat essential task using on-wiki signals triggers (in-flow check, completion-status read, periodic sweep), idempotently
- A backfill script (dry-run/--apply, with DB backup) credits historically attributable completions, attributes legacy rows' usernames from exact analytics correlations, and removes the unattributable pre-logging row
- The impact dashboard's "tasks completed" for this task reads reconciled completions, not raw complete events
- CTA events for this task are stamped with the picked article title (done in e7dcc16, 2026-07-18)