<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://mw.eckford.ca:443/index.php?action=history&amp;feed=atom&amp;title=ROUTINE-Data-Model</id>
	<title>ROUTINE-Data-Model - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://mw.eckford.ca:443/index.php?action=history&amp;feed=atom&amp;title=ROUTINE-Data-Model"/>
	<link rel="alternate" type="text/html" href="https://mw.eckford.ca:443/index.php?title=ROUTINE-Data-Model&amp;action=history"/>
	<updated>2026-07-17T13:00:52Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.39.17</generator>
	<entry>
		<id>https://mw.eckford.ca:443/index.php?title=ROUTINE-Data-Model&amp;diff=173&amp;oldid=prev</id>
		<title>Tux at 01:27, 7 March 2026</title>
		<link rel="alternate" type="text/html" href="https://mw.eckford.ca:443/index.php?title=ROUTINE-Data-Model&amp;diff=173&amp;oldid=prev"/>
		<updated>2026-03-07T01:27:41Z</updated>

		<summary type="html">&lt;p&gt;&lt;/p&gt;
&lt;a href=&quot;https://mw.eckford.ca:443/index.php?title=ROUTINE-Data-Model&amp;amp;diff=173&amp;amp;oldid=172&quot;&gt;Show changes&lt;/a&gt;</summary>
		<author><name>Tux</name></author>
	</entry>
	<entry>
		<id>https://mw.eckford.ca:443/index.php?title=ROUTINE-Data-Model&amp;diff=172&amp;oldid=prev</id>
		<title>Tux: Release notes with Version 1 created</title>
		<link rel="alternate" type="text/html" href="https://mw.eckford.ca:443/index.php?title=ROUTINE-Data-Model&amp;diff=172&amp;oldid=prev"/>
		<updated>2026-03-07T01:21:56Z</updated>

		<summary type="html">&lt;p&gt;Release notes with Version 1 created&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;Good idea. A TL;DR at the top saves future-you (and Simon) from rereading the whole document.&lt;br /&gt;
&lt;br /&gt;
Here’s a clean one you can drop **at the very top of the notes**.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# TL;DR – ROUTINE Release Model&lt;br /&gt;
&lt;br /&gt;
ROUTINE releases are defined entirely by **two tables**:&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
mw_tags&lt;br /&gt;
mw_tag_pages&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
* `mw_tags.tag_id` stores the ROUTINE label (e.g. `ROUTINE_4.110`)&lt;br /&gt;
* `mw_tag_pages` maps each ROUTINE to the **exact page revision** that belongs to that release&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
tag_id      → release label&lt;br /&gt;
tag_page    → page_id&lt;br /&gt;
tag_rev     → approved revision for that release&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Everything else is derived.&lt;br /&gt;
&lt;br /&gt;
### Source of truth&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
mw_tags&lt;br /&gt;
mw_tag_pages&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
### Supporting wiki data&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
mw_page&lt;br /&gt;
mw_revision&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
### Derived runtime table&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
mw_approved_revs&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
`mw_approved_revs` is **not migration data** and can always be regenerated from the ROUTINE snapshot.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# Operational Behavior&lt;br /&gt;
&lt;br /&gt;
**Activate ROUTINE**&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
ROUTINE tag selected&lt;br /&gt;
      ↓&lt;br /&gt;
mw_tag_pages snapshot identified&lt;br /&gt;
      ↓&lt;br /&gt;
mw_approved_revs rebuilt&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**Rollback**&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
Activate older ROUTINE tag&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Approved revisions immediately revert to that snapshot.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# Key Insight (Breakthrough)&lt;br /&gt;
&lt;br /&gt;
The ROUTINE system does **not store approval history in mw_approved_revs**.&lt;br /&gt;
&lt;br /&gt;
Instead it stores the **release snapshot** in:&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
mw_tag_pages&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
That snapshot defines exactly which revision of each page belongs to a release.&lt;br /&gt;
&lt;br /&gt;
`mw_approved_revs` is only a **runtime projection** used by the ApprovedRevs extension.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# Safe Test Dataset&lt;br /&gt;
&lt;br /&gt;
To build an offsite development stub you only need:&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
mw_tags&lt;br /&gt;
mw_tag_pages&lt;br /&gt;
mw_page&lt;br /&gt;
mw_revision&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
`mw_approved_revs` can be empty and regenerated during activation.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# One Sentence Summary&lt;br /&gt;
&lt;br /&gt;
**ROUTINE releases are simply named snapshots of page revisions stored in `mw_tag_pages`.**&lt;br /&gt;
&lt;br /&gt;
Everything else can be rebuilt.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
If you&amp;#039;d like, I can also give you a **very small ASCII diagram of the data relationships** that fits on one screen. It&amp;#039;s surprisingly helpful when someone new inherits the system (Simon in particular).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# ROUTINE Data Model and Test Stub Notes&lt;br /&gt;
&lt;br /&gt;
These notes describe the data structures used by the ROUTINE workflow in MediaWiki and how to construct a reusable development stub dataset for offsite work.&lt;br /&gt;
&lt;br /&gt;
The goal is to preserve the important relationships between ROUTINE labels, pages, and revisions without requiring production data.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# 1. Authoritative ROUTINE Data&lt;br /&gt;
&lt;br /&gt;
The authoritative release mapping lives in two tables.&lt;br /&gt;
&lt;br /&gt;
## `mw_tags`&lt;br /&gt;
&lt;br /&gt;
Defines each ROUTINE label.&lt;br /&gt;
&lt;br /&gt;
Example fields:&lt;br /&gt;
&lt;br /&gt;
| Field     | Purpose                                           |&lt;br /&gt;
| --------- | ------------------------------------------------- |&lt;br /&gt;
| `tag_id`  | ROUTINE identifier (e.g. `ROUTINE_4.110`)         |&lt;br /&gt;
| `publish` | Indicates whether the tag is considered published |&lt;br /&gt;
| `locked`  | Prevents edits to the tag                         |&lt;br /&gt;
| `deleted` | Soft delete flag                                  |&lt;br /&gt;
| `comment` | Optional deployment comment                       |&lt;br /&gt;
&lt;br /&gt;
Important note:&lt;br /&gt;
&lt;br /&gt;
In this system the ROUTINE identifier is stored in **`tag_id`**, not `tag_name`.&lt;br /&gt;
&lt;br /&gt;
All extension logic joins on:&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
mw_tags.tag_id&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Example values:&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
ROUTINE_4.110&lt;br /&gt;
ROUTINE_4.111&lt;br /&gt;
ROUTINE_4.112&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## `mw_tag_pages`&lt;br /&gt;
&lt;br /&gt;
Defines which revision of each page belongs to a ROUTINE release.&lt;br /&gt;
&lt;br /&gt;
Fields:&lt;br /&gt;
&lt;br /&gt;
| Field      | Purpose              |&lt;br /&gt;
| ---------- | -------------------- |&lt;br /&gt;
| `tag_id`   | ROUTINE label        |&lt;br /&gt;
| `tag_page` | Page ID              |&lt;br /&gt;
| `tag_rev`  | Approved revision ID |&lt;br /&gt;
&lt;br /&gt;
This table represents the **release snapshot**.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
| tag_id        | tag_page | tag_rev |&lt;br /&gt;
| ------------- | -------- | ------- |&lt;br /&gt;
| ROUTINE_4.110 | 101      | 5001    |&lt;br /&gt;
| ROUTINE_4.110 | 102      | 5002    |&lt;br /&gt;
| ROUTINE_4.111 | 101      | 5001    |&lt;br /&gt;
| ROUTINE_4.111 | 102      | 5009    |&lt;br /&gt;
&lt;br /&gt;
This means:&lt;br /&gt;
&lt;br /&gt;
* page 101 did not change between releases&lt;br /&gt;
* page 102 received a new revision in 4.111&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# 2. Supporting MediaWiki Core Data&lt;br /&gt;
&lt;br /&gt;
The ROUTINE workflow relies on normal MediaWiki tables.&lt;br /&gt;
&lt;br /&gt;
## `mw_page`&lt;br /&gt;
&lt;br /&gt;
Identifies pages.&lt;br /&gt;
&lt;br /&gt;
Important fields:&lt;br /&gt;
&lt;br /&gt;
| Field            | Purpose                 |&lt;br /&gt;
| ---------------- | ----------------------- |&lt;br /&gt;
| `page_id`        | Primary page identifier |&lt;br /&gt;
| `page_namespace` | Namespace               |&lt;br /&gt;
| `page_title`     | Page title              |&lt;br /&gt;
| `page_latest`    | Current revision ID     |&lt;br /&gt;
&lt;br /&gt;
Relationship:&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
mw_revision.rev_page = mw_page.page_id&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## `mw_revision`&lt;br /&gt;
&lt;br /&gt;
Stores revision history.&lt;br /&gt;
&lt;br /&gt;
Important fields:&lt;br /&gt;
&lt;br /&gt;
| Field           | Purpose            |&lt;br /&gt;
| --------------- | ------------------ |&lt;br /&gt;
| `rev_id`        | Revision ID        |&lt;br /&gt;
| `rev_page`      | Page ID            |&lt;br /&gt;
| `rev_timestamp` | Revision timestamp |&lt;br /&gt;
&lt;br /&gt;
Relationship used by ROUTINE logic:&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
mw_tag_pages.tag_rev = mw_revision.rev_id&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# 3. Derived Runtime Table&lt;br /&gt;
&lt;br /&gt;
## `mw_approved_revs`&lt;br /&gt;
&lt;br /&gt;
This table is **not part of the migrated ROUTINE data**.&lt;br /&gt;
&lt;br /&gt;
It is a runtime projection used by the **ApprovedRevs extension**.&lt;br /&gt;
&lt;br /&gt;
Schema:&lt;br /&gt;
&lt;br /&gt;
| Field           | Purpose            |&lt;br /&gt;
| --------------- | ------------------ |&lt;br /&gt;
| `page_id`       | Page identifier    |&lt;br /&gt;
| `rev_id`        | Approved revision  |&lt;br /&gt;
| `approver_id`   | User who approved  |&lt;br /&gt;
| `approval_date` | Approval timestamp |&lt;br /&gt;
&lt;br /&gt;
Important constraint:&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
page_id UNIQUE&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Only one approved revision per page can exist at a time.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# Important Operational Insight&lt;br /&gt;
&lt;br /&gt;
`mw_approved_revs` was **not included in the ROUTINE migration**.&lt;br /&gt;
&lt;br /&gt;
On the sh0re environment the table still existed only because the environment was not dropped during migration.&lt;br /&gt;
&lt;br /&gt;
Therefore:&lt;br /&gt;
&lt;br /&gt;
**`mw_approved_revs` should be considered derived state.**&lt;br /&gt;
&lt;br /&gt;
It can always be rebuilt from:&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
mw_tags&lt;br /&gt;
mw_tag_pages&lt;br /&gt;
mw_revision&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# 4. Activation Workflow&lt;br /&gt;
&lt;br /&gt;
When a ROUTINE tag is activated:&lt;br /&gt;
&lt;br /&gt;
1. The selected ROUTINE label is verified in `mw_tags`.&lt;br /&gt;
2. All pages belonging to that tag are identified via `mw_tag_pages`.&lt;br /&gt;
3. `mw_approved_revs` is refreshed to match the snapshot.&lt;br /&gt;
&lt;br /&gt;
Conceptually:&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
mw_tag_pages → mw_revision → mw_approved_revs&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Rollback is therefore simple:&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
activate ROUTINE_4.110&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
and the approved revisions revert to that snapshot.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# 5. Reusable Test Dataset&lt;br /&gt;
&lt;br /&gt;
A reusable development stub should include:&lt;br /&gt;
&lt;br /&gt;
### Required tables&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
mw_tags&lt;br /&gt;
mw_tag_pages&lt;br /&gt;
mw_page&lt;br /&gt;
mw_revision&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
### Optional&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
mw_approved_revs (empty)&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# Recommended Stub Structure&lt;br /&gt;
&lt;br /&gt;
A useful small dataset contains:&lt;br /&gt;
&lt;br /&gt;
| Item         | Suggested Count |&lt;br /&gt;
| ------------ | --------------- |&lt;br /&gt;
| ROUTINE tags | 3               |&lt;br /&gt;
| pages        | 5–8             |&lt;br /&gt;
| revisions    | 6–10            |&lt;br /&gt;
| tag mappings | 8–15            |&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# Example Release Story&lt;br /&gt;
&lt;br /&gt;
### ROUTINE_4.110&lt;br /&gt;
&lt;br /&gt;
Pages:&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
Startup_Procedure&lt;br /&gt;
Shutdown_Procedure&lt;br /&gt;
Network_Check&lt;br /&gt;
Incident_Escalation&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
### ROUTINE_4.111&lt;br /&gt;
&lt;br /&gt;
Pages:&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
Startup_Procedure (unchanged)&lt;br /&gt;
Shutdown_Procedure (new revision)&lt;br /&gt;
Backup_Verification (new page)&lt;br /&gt;
Incident_Escalation (unchanged)&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
This creates realistic test scenarios:&lt;br /&gt;
&lt;br /&gt;
| Scenario       | Purpose                |&lt;br /&gt;
| -------------- | ---------------------- |&lt;br /&gt;
| unchanged page | verify revision reuse  |&lt;br /&gt;
| updated page   | verify revision update |&lt;br /&gt;
| removed page   | verify exclusion       |&lt;br /&gt;
| new page       | verify clone/import    |&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# 6. Minimal Fields That Must Be Accurate&lt;br /&gt;
&lt;br /&gt;
The following identifiers must remain correct in any stub dataset:&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
mw_tags.tag_id&lt;br /&gt;
mw_tag_pages.tag_id&lt;br /&gt;
mw_tag_pages.tag_page&lt;br /&gt;
mw_tag_pages.tag_rev&lt;br /&gt;
mw_page.page_id&lt;br /&gt;
mw_page.page_title&lt;br /&gt;
mw_revision.rev_id&lt;br /&gt;
mw_revision.rev_page&lt;br /&gt;
mw_revision.rev_timestamp&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Everything else may be dummy data if necessary.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# 7. Future Importer Design&lt;br /&gt;
&lt;br /&gt;
If a JSON/API importer is later introduced, its logical structure should mirror the release mapping.&lt;br /&gt;
&lt;br /&gt;
Example conceptual payload:&lt;br /&gt;
&lt;br /&gt;
```json&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;tag_id&amp;quot;: &amp;quot;ROUTINE_4.112&amp;quot;,&lt;br /&gt;
  &amp;quot;pages&amp;quot;: [&lt;br /&gt;
    {&lt;br /&gt;
      &amp;quot;page_id&amp;quot;: 101,&lt;br /&gt;
      &amp;quot;rev_id&amp;quot;: 5001&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      &amp;quot;page_id&amp;quot;: 102,&lt;br /&gt;
      &amp;quot;rev_id&amp;quot;: 5009&lt;br /&gt;
    }&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
This maps directly to `mw_tag_pages`.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# Final Operational Principle&lt;br /&gt;
&lt;br /&gt;
The **source of truth** for ROUTINE releases is:&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
mw_tags + mw_tag_pages&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Everything else can be regenerated.&lt;br /&gt;
&lt;br /&gt;
This makes rollback, cloning, and importer workflows safe and predictable.&lt;br /&gt;
&lt;br /&gt;
---&lt;/div&gt;</summary>
		<author><name>Tux</name></author>
	</entry>
</feed>