Page MenuHomePhabricator

Redefine "task completion" for HotCat essential task using on-wiki signals
Open, HighPublic2 Estimated Story Points

Description

Background

The impact dashboard (T430096: Add an impact dashboard for the Starter Kit) reports "tasks completed" based on client-side analytics events:
a task counts as done when the user clicks the completion button in StarterKit, which emits a starterkit.essential.{tool}.complete event and writes a task_completions row.

Problem

The in-app click is a weak proxy for what we actually want to measure — the on-wiki action the task teaches. Auditing the HotCat task (install-gadget) against public wiki data showed both failure directions:

  • False negative: a user on kai.wikipedia.org opened the suggested article and added a category with HotCat 49 seconds later (added [[Category:Mbèesu]] using HotCat), but never returned to the app to click "Done". A real completion, counted as nothing.
  • False positive: the only recorded complete event was clicked 8 seconds after opening the article, with no corresponding edit anywhere on the wiki.
NOTE: The false-positive hole is closed as of 2026-07-21 — the Done button is now gated on a live category check. But users who complete the task on-wiki and never return to the app (at least within that session) remain structurally invisible to the current definition.

What data we have

Since 2026-07-18, the open-article CTA event carries username, wiki_url, title, and a timestamp — a complete tuple for later on-wiki verification. HotCat edits are publicly identifiable via their edit summary (... using [[Help:Gadget-HotCat|HotCat]]).

Definition — what does "HotCat task done" mean

Τhe user's own edit gave the suggested article a category, verified server-side. The in-app "Done" click becomes UI-only: today the flow checks the article's category status merely to enable the button, and the click creates the record. Under the new definition the successful check itself records the completion; the click just navigates. The check must therefore also confirm the user made the edit (one revisions?rvuser= call) — "article has a category" alone is too weak to create a record, since a suggested article can be categorized by someone else.

Mechanism proposed

Οne shared verification module, invoked from three trigger points. Because the HotCat task is repeatable (task_completions.run_count increments per run, T431065) and completions must be credited immediately when verifiable (a user must never see a task pending that is actually done), verification is tracked per run in a ledger keyed by article title:

  • Verification ledger: a task_verifications table, one row per credited run — wiki_url, task_key, username, article_title, rev_id, verified_at, source, with UNIQUE(wiki_url, task_key, username, article_title). This enforces the rule that re-doing the task on the same title never credits twice, makes concurrent trigger paths race-safe (no double run_count increment), and records which titles each run completed. Crediting = transactional ledger insert + existing run_count upsert; task_completions needs no migration.
  • Trigger 1 — in-app check: the existing category-status check on step 3 (visibilitychange / "Check again"), extended to attest the user's edit; on success it credits via the module (idempotent, so repeat checks are no-ops).
  • Trigger 2 — completion-status read: whenever the client fetches essential-task completion status (dashboard load, task view load, new tab, refresh — login is just one instance), the server flags pending opens on the session wiki (cheap local lookup, pendingVerification in the response) and the task card shows a loading state only in that case while the module verifies. This covers the user who completes the edit and then opens the dashboard in a fresh tab without ever returning to the task tab. Hard timeout (~5s): on slow/unavailable wiki API the card falls back to current state; the sweep is the backstop. Idempotency makes repeated reads safe; a per-open last_checked_at cooldown caps API calls for never-completing pending opens.
  • Trigger 3 — periodic sweep: an in-process timer (not a separate cron process — single SQLite writer, no cross-process locking, credit + ledger insert trivially atomic) verifying pending opens from the last ~30 days. Covers users who never return; the lookback bounds the scan, it is not a correctness rule — no completion windows, no watermarks.
  • Pending definition: a titled open-article event whose (user, wiki, task, title) is not in the ledger, within the sweep lookback.
  • Historical backfill: a one-off --all run (dry-run + --apply) crediting verifiable completions from existing events. Only titled events are verifiable under this definition; the 5 pre-2026-07-18 title-less opens were each checked manually — exactly 1 is creditable (kai.wikipedia.org, title recovered from the user's public HotCat edit) and can be credited from the recovered data.

Scope — HotCat first, then the same on-wiki-signal review task-by-task for the other essential tasks (each has a different verifiable artifact: created article, imported infobox, …).

Acceptance criteria

Details

Related Changes in GitLab:
TitleReferenceAuthorSource BranchDest Branch
Feat: Verify HotCat task completion from on-wiki editsrepos/lpl/starterkit-v1!144ngkountasfeat/hotcat-onwiki-completion-T433014main
Customize query in GitLab

Event Timeline

ngkountas added a project: Starter Kit.
ngkountas set the point value for this task to 2.

@eamedina just flagging this task needs a prompt review when you have a moment