<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>IT Template Library</title><link>https://templates.metacog.co.kr/</link><description>Recent content on IT Template Library</description><generator>Hugo</generator><language>en-us</language><lastBuildDate>Sun, 23 Aug 2026 16:51:20 -0500</lastBuildDate><atom:link href="https://templates.metacog.co.kr/index.xml" rel="self" type="application/rss+xml"/><item><title>Project Charter</title><link>https://templates.metacog.co.kr/docs/project-management/project-charter/</link><pubDate>Sun, 23 Aug 2026 00:00:00 +0000</pubDate><guid>https://templates.metacog.co.kr/docs/project-management/project-charter/</guid><description>&lt;p&gt;A charter is the document that turns an idea into a funded project. Its real job is not description — it is authorisation and boundary setting. It names the sponsor who can say yes, the manager who can spend, and the things this project is explicitly &lt;em&gt;not&lt;/em&gt; going to do.&lt;/p&gt;
&lt;h2 id="when-to-use-it"&gt;When to use it &lt;a href="#when-to-use-it" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;At project initiation, before any team member is assigned.&lt;/li&gt;
&lt;li&gt;When a piece of work that started informally has grown enough that people are arguing about its scope.&lt;/li&gt;
&lt;li&gt;When the sponsor changes and the mandate needs re-confirming.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="what-it-must-answer"&gt;What it must answer &lt;a href="#what-it-must-answer" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Question&lt;/th&gt;
 &lt;th&gt;Why it belongs in the charter&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;Why now?&lt;/td&gt;
 &lt;td&gt;Separates a real trigger (contract expiry, audit finding, capacity ceiling) from a preference.&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Who is accountable?&lt;/td&gt;
 &lt;td&gt;One sponsor, one manager. Two of either means neither.&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;What is out of scope?&lt;/td&gt;
 &lt;td&gt;The only section that reliably prevents a fight in month four.&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;What does success look like?&lt;/td&gt;
 &lt;td&gt;Measurable, with a baseline. &amp;ldquo;Improve performance&amp;rdquo; is not a success criterion.&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;What is the budget and deadline?&lt;/td&gt;
 &lt;td&gt;An order of magnitude is fine; a blank is not.&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="template"&gt;Template &lt;a href="#template" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock "&gt;
 &lt;pre id="bc16b0e" class="language-markdown "&gt;
 &lt;code&gt;# Project Charter: &amp;lt;Project Name&amp;gt;

| Field | Value |
|---|---|
| Charter version | 1.0 |
| Date | YYYY-MM-DD |
| Sponsor | Name, role |
| Project manager | Name, role |
| Status | Draft / Approved |

## 1. Business case
Two or three sentences. What changes in the business if this succeeds, and what
happens if we do nothing.

## 2. Objectives and success criteria
| # | Objective | Measure | Baseline | Target | Measured by |
|---|---|---|---|---|---|
| 1 | | | | | |

## 3. Scope
**In scope**
- ...

**Out of scope**
- ...

**Assumptions**
- ...

## 4. Deliverables and milestones
| Milestone | Deliverable | Target date |
|---|---|---|

## 5. Budget
| Category | Amount | Notes |
|---|---|---|
| People | | |
| Licences / cloud | | |
| Contingency | | |

## 6. Key risks
Top three only; the full list lives in the RAID log.

## 7. Stakeholders and governance
| Name | Role | Decision rights | Cadence |
|---|---|---|---|

## 8. Approval
| Name | Role | Date | Signature |
|---|---|---|---|&lt;/code&gt;
 &lt;/pre&gt;
 &lt;/div&gt;
&lt;h2 id="worked-example"&gt;Worked example &lt;a href="#worked-example" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock "&gt;
 &lt;pre id="bbfd970" class="language-markdown "&gt;
 &lt;code&gt;# Project Charter: Payment Gateway Migration

| Field | Value |
|---|---|
| Charter version | 1.0 |
| Date | 2026-03-02 |
| Sponsor | R. Okafor, VP Engineering |
| Project manager | S. Lindqvist |
| Status | Approved |

## 1. Business case
Our contract with the incumbent payment provider ends 2027-01-31 and renewal
pricing is 40% higher. Migrating to the new provider saves roughly EUR 380k
per year and removes the single-region dependency that caused the outage in
January. Doing nothing means auto-renewal at the higher rate.

## 2. Objectives and success criteria
| # | Objective | Measure | Baseline | Target | Measured by |
|---|---|---|---|---|---|
| 1 | Migrate all card traffic | % of volume on new provider | 0% | 100% | 2026-12-15 |
| 2 | Hold authorisation rate | Weekly auth success rate | 96.4% | &amp;gt;= 96.4% | 2027-01-15 |
| 3 | Reduce annual cost | Provider fees per year | EUR 950k | &amp;lt;= EUR 570k | FY2027 close |

## 3. Scope
**In scope**
- Card payments (credit, debit) on web and mobile.
- Refunds, chargeback handling, reconciliation feeds to Finance.
- Dual-running both providers during cutover.

**Out of scope**
- Bank transfers and direct debit — remain with the incumbent until 2028.
- Repricing of merchant fees to customers.
- Replacing the internal ledger service.

**Assumptions**
- The new provider&amp;#39;s sandbox is available from 2026-04-01.
- Finance can accept two reconciliation feeds during dual-running.

## 4. Deliverables and milestones
| Milestone | Deliverable | Target date |
|---|---|---|
| M1 | Integration spec signed off | 2026-05-15 |
| M2 | Sandbox integration passing test suite | 2026-07-31 |
| M3 | 5% live traffic on new provider | 2026-09-30 |
| M4 | 100% traffic migrated | 2026-12-15 |
| M5 | Incumbent card contract terminated | 2027-01-31 |

## 5. Budget
| Category | Amount | Notes |
|---|---|---|
| People | EUR 640k | 4 engineers, 1 QA, 0.5 PM for 9 months |
| Licences / cloud | EUR 45k | Sandbox, additional egress during dual-run |
| Contingency | EUR 100k | 15% |

## 6. Key risks
1. Authorisation rate drops after cutover and revenue falls before we can react.
2. The provider&amp;#39;s PSD2 flow differs enough to require checkout redesign.
3. Finance reconciliation cannot handle dual feeds, delaying month-end close.

## 7. Stakeholders and governance
| Name | Role | Decision rights | Cadence |
|---|---|---|---|
| R. Okafor | Sponsor | Budget, go/no-go on cutover | Monthly steering |
| M. Duarte | Head of Finance | Accepts reconciliation design | Monthly steering |
| S. Lindqvist | PM | Day-to-day scope within charter | Weekly |
| A. Berg | Security lead | Accepts PCI scope changes | Gate reviews |

## 8. Approval
| Name | Role | Date | Signature |
|---|---|---|---|
| R. Okafor | Sponsor | 2026-03-02 | signed |
| M. Duarte | Head of Finance | 2026-03-04 | signed |&lt;/code&gt;
 &lt;/pre&gt;
 &lt;/div&gt;
&lt;h2 id="common-mistakes"&gt;Common mistakes &lt;a href="#common-mistakes" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;No out-of-scope section.&lt;/strong&gt; This is the single most common defect. Without it, every adjacent idea is arguably in scope.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Objectives without a baseline.&lt;/strong&gt; &amp;ldquo;Reduce latency by 30%&amp;rdquo; is meaningless if nobody wrote down today&amp;rsquo;s number before the work started.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Two sponsors.&lt;/strong&gt; Shared accountability produces deadlock at exactly the moment a decision is needed.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Charter as a design document.&lt;/strong&gt; Architecture belongs in the &lt;a data-bs-delay="{&amp;#34;hide&amp;#34;:300,&amp;#34;show&amp;#34;:550}" data-bs-html="true" data-bs-title="&lt;a href='https://templates.metacog.co.kr/docs/architecture-design/solution-architecture-document/'&gt;&lt;p&gt;ARCHITECTURE &amp; DESIGN&lt;/p&gt;</description></item><item><title>Project Plan</title><link>https://templates.metacog.co.kr/docs/project-management/project-plan/</link><pubDate>Sun, 23 Aug 2026 00:00:00 +0000</pubDate><guid>https://templates.metacog.co.kr/docs/project-management/project-plan/</guid><description>&lt;p&gt;The project plan converts the charter&amp;rsquo;s milestones into dated, owned, sequenced work. The mistake is treating it as a Gantt chart to be admired; the useful version is a small table plus an explicit statement of what is on the critical path and what the plan assumes.&lt;/p&gt;
&lt;h2 id="when-to-use-it"&gt;When to use it &lt;a href="#when-to-use-it" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Immediately after the &lt;a data-bs-delay="{&amp;#34;hide&amp;#34;:300,&amp;#34;show&amp;#34;:550}" data-bs-html="true" data-bs-title="&lt;a href='https://templates.metacog.co.kr/docs/project-management/project-charter/'&gt;&lt;p&gt;PROJECT MANAGEMENT&lt;/p&gt;&lt;strong&gt;Project Charter&lt;/strong&gt;&lt;br&gt;The one-page authorisation that says a project exists, who runs it, and what 'done' means.&lt;/a&gt;" data-bs-toggle="tooltip" href="https://templates.metacog.co.kr/docs/project-management/project-charter/"&gt;Project Charter&lt;/a&gt; is approved.&lt;/li&gt;
&lt;li&gt;Before committing to an external date (a contract, a regulatory deadline, a marketing launch).&lt;/li&gt;
&lt;li&gt;Whenever a dependency changes enough that the finish date moves.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="what-it-must-answer"&gt;What it must answer &lt;a href="#what-it-must-answer" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;What are the work packages, and who owns each one?&lt;/li&gt;
&lt;li&gt;What must finish before what — and which of those chains determines the end date?&lt;/li&gt;
&lt;li&gt;Where does the plan depend on people or systems outside the team&amp;rsquo;s control?&lt;/li&gt;
&lt;li&gt;How much buffer exists, and where is it held?&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="template"&gt;Template &lt;a href="#template" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock "&gt;
 &lt;pre id="d1431e0" class="language-markdown "&gt;
 &lt;code&gt;# Project Plan: &amp;lt;Project Name&amp;gt;

| Field | Value |
|---|---|
| Plan version | |
| Baseline date | |
| Owner | |
| Related charter | link |

## 1. Approach
One paragraph: delivery method (iterative / phased), why it suits this work,
and how progress will be measured.

## 2. Work breakdown
| ID | Work package | Owner | Effort (days) | Depends on | Start | Finish |
|---|---|---|---|---|---|---|
| 1.1 | | | | — | | |

## 3. Milestones
| Milestone | Definition of done | Date | Owner |
|---|---|---|---|

## 4. Critical path
List the chain of work packages that determines the end date, and the total
float on the next-nearest chain.

## 5. Resourcing
| Role | Person | Allocation | Period | Confirmed? |
|---|---|---|---|---|

## 6. External dependencies
| Dependency | Provider | Needed by | Status | Escalation route |
|---|---|---|---|---|

## 7. Assumptions and buffer
- Assumptions this plan rests on.
- Where contingency is held and who may release it.

## 8. Change control
How a date change gets approved, and by whom.&lt;/code&gt;
 &lt;/pre&gt;
 &lt;/div&gt;
&lt;h2 id="worked-example"&gt;Worked example &lt;a href="#worked-example" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock "&gt;
 &lt;pre id="c467c35" class="language-markdown "&gt;
 &lt;code&gt;# Project Plan: Payment Gateway Migration

| Field | Value |
|---|---|
| Plan version | 2.1 (rebaselined after M2 slip) |
| Baseline date | 2026-08-04 |
| Owner | S. Lindqvist |

## 1. Approach
Incremental migration behind a routing flag, with traffic moved in steps
(5% / 25% / 100%). Progress is measured by percentage of live card volume on
the new provider, not by code completeness, because the integration is only
proven under real traffic.

## 2. Work breakdown
| ID | Work package | Owner | Effort (days) | Depends on | Start | Finish |
|---|---|---|---|---|---|---|
| 1.1 | Integration spec | A. Vogel | 15 | — | 2026-04-06 | 2026-05-15 |
| 1.2 | Sandbox client library | J. Marek | 25 | 1.1 | 2026-05-18 | 2026-06-26 |
| 1.3 | Routing flag service | J. Marek | 10 | — | 2026-05-18 | 2026-06-01 |
| 1.4 | Reconciliation feed | P. Nowak | 20 | 1.1 | 2026-06-01 | 2026-07-10 |
| 1.5 | Test suite against sandbox | H. Ito | 20 | 1.2 | 2026-06-29 | 2026-07-31 |
| 1.6 | 5% traffic ramp | J. Marek | 10 | 1.3, 1.5 | 2026-09-01 | 2026-09-30 |
| 1.7 | Full ramp | J. Marek | 30 | 1.6 | 2026-10-05 | 2026-12-15 |

## 3. Milestones
| Milestone | Definition of done | Date | Owner |
|---|---|---|---|
| M2 | Full sandbox suite green for 5 consecutive nightly runs | 2026-07-31 | H. Ito |
| M3 | 5% of card volume settled and reconciled through new provider | 2026-09-30 | S. Lindqvist |
| M4 | 100% volume, incumbent in standby only | 2026-12-15 | S. Lindqvist |

## 4. Critical path
1.1 -&amp;gt; 1.2 -&amp;gt; 1.5 -&amp;gt; 1.6 -&amp;gt; 1.7. Total float on the reconciliation chain
(1.1 -&amp;gt; 1.4) is 15 working days, so a two-week slip there does not move M4;
a two-week slip in 1.5 does.

## 5. Resourcing
| Role | Person | Allocation | Period | Confirmed? |
|---|---|---|---|---|
| Backend | J. Marek | 100% | Apr–Dec | Yes |
| Backend | A. Vogel | 50% | Apr–Jul | Yes |
| Data | P. Nowak | 50% | Jun–Jul | No — shared with Reporting |
| QA | H. Ito | 100% | Jun–Dec | Yes |

## 6. External dependencies
| Dependency | Provider | Needed by | Status | Escalation route |
|---|---|---|---|---|
| Sandbox credentials | Payment provider | 2026-04-01 | Received 2026-04-03 | Account manager |
| PCI scope sign-off | Internal security | 2026-08-15 | In review | A. Berg -&amp;gt; CISO |
| Finance dual-feed capacity | Finance systems | 2026-08-31 | Not started | M. Duarte |

## 7. Assumptions and buffer
- P. Nowak&amp;#39;s 50% allocation holds; if Reporting reclaims it, 1.4 slips 3 weeks
 and consumes all its float.
- 15 working days of contingency sit before M4, released only by the sponsor.

## 8. Change control
Any change to M4 requires sponsor approval at monthly steering. Changes inside
the plan that do not move a milestone are the PM&amp;#39;s to make.&lt;/code&gt;
 &lt;/pre&gt;
 &lt;/div&gt;
&lt;h2 id="common-mistakes"&gt;Common mistakes &lt;a href="#common-mistakes" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A schedule with no critical path.&lt;/strong&gt; If everything looks equally urgent, the team optimises the wrong task.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Unconfirmed resources shown as confirmed.&lt;/strong&gt; Mark them honestly; an unconfirmed 50% allocation is a risk, and belongs in the &lt;a data-bs-delay="{&amp;#34;hide&amp;#34;:300,&amp;#34;show&amp;#34;:550}" data-bs-html="true" data-bs-title="&lt;a href='https://templates.metacog.co.kr/docs/project-management/raid-log/'&gt;&lt;p&gt;PROJECT MANAGEMENT&lt;/p&gt;</description></item><item><title>Status Report</title><link>https://templates.metacog.co.kr/docs/project-management/status-report/</link><pubDate>Sun, 23 Aug 2026 00:00:00 +0000</pubDate><guid>https://templates.metacog.co.kr/docs/project-management/status-report/</guid><description>&lt;p&gt;Most status reports are written to reassure. A useful one is written to surface the two or three things a reader can act on, and to report schedule confidence honestly enough that bad news arrives early rather than at the deadline.&lt;/p&gt;
&lt;h2 id="when-to-use-it"&gt;When to use it &lt;a href="#when-to-use-it" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;On a fixed weekly or fortnightly cadence for any project with a sponsor.&lt;/li&gt;
&lt;li&gt;Ad hoc when a milestone date changes — do not wait for the next scheduled report.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="what-it-must-answer"&gt;What it must answer &lt;a href="#what-it-must-answer" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Is the end date still credible, and has that answer changed since last time?&lt;/li&gt;
&lt;li&gt;What did we finish, and what did we say we would finish and did not?&lt;/li&gt;
&lt;li&gt;What decision or unblocking do I need from the reader, by when?&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="template"&gt;Template &lt;a href="#template" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock "&gt;
 &lt;pre id="44cd113" class="language-markdown "&gt;
 &lt;code&gt;# Status Report: &amp;lt;Project&amp;gt; — week ending YYYY-MM-DD

**Overall:** Green / Amber / Red (last period: X)
**Next milestone:** &amp;lt;name&amp;gt;, due YYYY-MM-DD, confidence High / Medium / Low

## Decisions needed
| # | Decision | Owner | Needed by | Impact if late |
|---|---|---|---|---|

## Progress this period
- Completed: ...
- Slipped: ... (planned &amp;lt;date&amp;gt;, now &amp;lt;date&amp;gt;, cause)

## Plan for next period
- ...

## Risks and issues (changes only)
| ID | Item | Change since last report |
|---|---|---|

## Metrics
| Metric | Last | Now | Target |
|---|---|---|---|

## Budget
Spent to date / forecast at completion / approved.&lt;/code&gt;
 &lt;/pre&gt;
 &lt;/div&gt;
&lt;h2 id="worked-example"&gt;Worked example &lt;a href="#worked-example" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock "&gt;
 &lt;pre id="a41e2be" class="language-markdown "&gt;
 &lt;code&gt;# Status Report: Payment Gateway Migration — week ending 2026-08-21

**Overall:** Amber (last period: Green)
**Next milestone:** M3 — 5% live traffic, due 2026-09-30, confidence Medium

## Decisions needed
| # | Decision | Owner | Needed by | Impact if late |
|---|---|---|---|---|
| 1 | Confirm P. Nowak stays at 50% through September | M. Duarte | 2026-08-28 | Reconciliation feed slips 3 weeks and consumes all float |
| 2 | Accept 3DS challenge rate rising to 8% during ramp | R. Okafor | 2026-09-04 | Ramp cannot start; M3 slips |

## Progress this period
- Completed: sandbox test suite green on 5 consecutive nightly runs — M2 met,
 one week late.
- Completed: routing flag service deployed to production, disabled.
- Slipped: reconciliation feed UAT (planned 2026-08-19, now 2026-09-02).
 Cause: Finance systems team unavailable during month-end close. Known
 dependency, not a new one.

## Plan for next period
- Dry-run the ramp procedure against 0% traffic in production.
- Reconciliation feed UAT with Finance, 2026-09-01.
- Close out the PCI scope review with Security.

## Risks and issues (changes only)
| ID | Item | Change since last report |
|---|---|---|
| R-04 | Auth rate drop after cutover | Unchanged. Mitigation (automatic rollback below 95.5%) implemented this week. |
| R-07 | Shared data engineer | Escalated to Amber — this is decision 1 above. |
| I-02 | Sandbox rate limits | Closed. Provider raised the limit on 2026-08-18. |

## Metrics
| Metric | Last | Now | Target |
|---|---|---|---|
| Sandbox suite pass rate | 92% | 100% | 100% |
| Live volume on new provider | 0% | 0% | 5% by 2026-09-30 |
| Open defects (sev 1–2) | 3 | 1 | 0 before ramp |

## Budget
Spent EUR 402k of EUR 785k approved. Forecast at completion EUR 760k,
including EUR 45k of the EUR 100k contingency. No new budget request.&lt;/code&gt;
 &lt;/pre&gt;
 &lt;/div&gt;
&lt;h2 id="common-mistakes"&gt;Common mistakes &lt;a href="#common-mistakes" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Green until the week it is Red.&lt;/strong&gt; A status that never goes Amber is not being measured; it is being performed. State milestone confidence separately from overall status so the trend is visible.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A list of activity instead of outcomes.&lt;/strong&gt; &amp;ldquo;Held three workshops&amp;rdquo; is not progress. &amp;ldquo;Integration spec signed by Finance&amp;rdquo; is.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Decisions buried in prose.&lt;/strong&gt; Put them in a table at the top with a date. A decision needed &amp;ldquo;soon&amp;rdquo; will not be made.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Restating the whole risk register every week.&lt;/strong&gt; Report the &lt;em&gt;changes&lt;/em&gt;; the full list lives in the &lt;a data-bs-delay="{&amp;#34;hide&amp;#34;:300,&amp;#34;show&amp;#34;:550}" data-bs-html="true" data-bs-title="&lt;a href='https://templates.metacog.co.kr/docs/project-management/raid-log/'&gt;&lt;p&gt;PROJECT MANAGEMENT&lt;/p&gt;</description></item><item><title>RAID Log</title><link>https://templates.metacog.co.kr/docs/project-management/raid-log/</link><pubDate>Sun, 23 Aug 2026 00:00:00 +0000</pubDate><guid>https://templates.metacog.co.kr/docs/project-management/raid-log/</guid><description>&lt;p&gt;RAID stands for Risks, Assumptions, Issues, Dependencies. Keeping all four in one place works because they convert into each other: an assumption that fails becomes an issue, a dependency that slips becomes a risk. A log that only tracks risks loses those transitions.&lt;/p&gt;
&lt;h2 id="when-to-use-it"&gt;When to use it &lt;a href="#when-to-use-it" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;From project kickoff to closure, reviewed at every status cycle.&lt;/li&gt;
&lt;li&gt;As the standing input to the risk section of the &lt;a data-bs-delay="{&amp;#34;hide&amp;#34;:300,&amp;#34;show&amp;#34;:550}" data-bs-html="true" data-bs-title="&lt;a href='https://templates.metacog.co.kr/docs/project-management/status-report/'&gt;&lt;p&gt;PROJECT MANAGEMENT&lt;/p&gt;</description></item><item><title>Meeting Minutes</title><link>https://templates.metacog.co.kr/docs/project-management/meeting-minutes/</link><pubDate>Sun, 23 Aug 2026 00:00:00 +0000</pubDate><guid>https://templates.metacog.co.kr/docs/project-management/meeting-minutes/</guid><description>&lt;p&gt;Minutes are not a transcript. Their value is in two things a recording cannot give you: what was &lt;em&gt;decided&lt;/em&gt;, and what someone committed to do by when. Everything else is optional context.&lt;/p&gt;
&lt;h2 id="when-to-use-it"&gt;When to use it &lt;a href="#when-to-use-it" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Any meeting where a decision is made, money is committed, or scope changes.&lt;/li&gt;
&lt;li&gt;Governance meetings — steering, change advisory board, design review — where an audit trail is expected.&lt;/li&gt;
&lt;li&gt;Not for standups or informal syncs; a shared task board is cheaper.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="what-it-must-answer"&gt;What it must answer &lt;a href="#what-it-must-answer" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Who was there, and who was invited but absent (absence matters when a decision binds them).&lt;/li&gt;
&lt;li&gt;What was decided, by whom, and on what basis.&lt;/li&gt;
&lt;li&gt;Which actions were accepted, by which named person, by which date.&lt;/li&gt;
&lt;li&gt;What was explicitly deferred, so it does not silently disappear.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="template"&gt;Template &lt;a href="#template" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock "&gt;
 &lt;pre id="8f93747" class="language-markdown "&gt;
 &lt;code&gt;# &amp;lt;Meeting name&amp;gt; — YYYY-MM-DD

| Field | Value |
|---|---|
| Chair | |
| Minutes by | |
| Attendees | |
| Apologies | |
| Distribution | |

## Decisions
| # | Decision | Rationale | Decided by | Reversible? |
|---|---|---|---|---|

## Actions
| # | Action | Owner | Due | Status |
|---|---|---|---|---|

## Discussion notes
Brief, per agenda item. Record positions where people disagreed — not who
&amp;#34;lost&amp;#34;, but what the competing arguments were.

## Deferred
| Item | Deferred until | Why |
|---|---|---|

## Next meeting
Date, and what must be ready beforehand.&lt;/code&gt;
 &lt;/pre&gt;
 &lt;/div&gt;
&lt;h2 id="worked-example"&gt;Worked example &lt;a href="#worked-example" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock "&gt;
 &lt;pre id="f870667" class="language-markdown "&gt;
 &lt;code&gt;# Payment Migration Steering — 2026-08-19

| Field | Value |
|---|---|
| Chair | R. Okafor (Sponsor) |
| Minutes by | S. Lindqvist |
| Attendees | R. Okafor, M. Duarte, A. Berg, S. Lindqvist, J. Marek |
| Apologies | P. Nowak (data) — represented by M. Duarte |
| Distribution | Attendees &amp;#43; programme mailbox |

## Decisions
| # | Decision | Rationale | Decided by | Reversible? |
|---|---|---|---|---|
| D-14 | Ramp starts at 5%, not the originally planned 10% | Auth-rate signal is statistically usable at 5% within 48h, and halves revenue exposure if the rate drops | R. Okafor | Yes — step size can be raised at the next gate |
| D-15 | Automatic rollback threshold set at 95.5% rolling auth rate over 30 minutes | 0.9pp below current baseline; below this the revenue loss exceeds the cost of a rollback | R. Okafor, on Finance&amp;#39;s numbers | Yes, by steering only |
| D-16 | Dual-running extended to 8 weeks from 4 | Finance needs two full month-end cycles to trust the new reconciliation feed | M. Duarte | No — provider contract dates now assume it |

## Actions
| # | Action | Owner | Due | Status |
|---|---|---|---|---|
| A-31 | Confirm P. Nowak&amp;#39;s allocation through September in writing | M. Duarte | 2026-08-28 | Open |
| A-32 | Implement 95.5% rollback trigger and prove it in a game day | J. Marek | 2026-09-11 | Open |
| A-33 | Re-forecast provider costs with 8-week dual-run | S. Lindqvist | 2026-09-02 | Open |

## Discussion notes
**Ramp size.** Engineering argued for 10% to reach statistical significance in
24h; Finance argued for 5% to cap exposure. Both accepted that 5% reaches
significance in 48h, which does not move M3. Decision D-14 taken on that basis.

**PCI scope.** Security has not completed the scope review (dependency D-01,
now 4 days late). A. Berg confirmed no new scope is expected but would not
sign before review completion. No decision taken.

## Deferred
| Item | Deferred until | Why |
|---|---|---|
| Bank transfer migration | FY2027 planning | Out of scope in the current charter; needs its own business case |
| Merchant fee repricing | After M4 | Depends on realised provider costs |

## Next meeting
2026-09-16. Required beforehand: PCI scope sign-off (D-01), rollback game day
result (A-32), revised cost forecast (A-33).&lt;/code&gt;
 &lt;/pre&gt;
 &lt;/div&gt;
&lt;h2 id="common-mistakes"&gt;Common mistakes &lt;a href="#common-mistakes" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Actions without a named person.&lt;/strong&gt; &amp;ldquo;The team will investigate&amp;rdquo; is an action nobody has.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Recording only the outcome of a contested discussion.&lt;/strong&gt; Six months later, someone will re-open it. Two lines on the competing arguments prevent re-litigating from zero.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No &amp;ldquo;reversible?&amp;rdquo; marker on decisions.&lt;/strong&gt; Reversible decisions can be made quickly by one person; irreversible ones deserve the meeting&amp;rsquo;s full attention. Marking them changes how the next one is handled.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Publishing days later.&lt;/strong&gt; Minutes lose most of their value after 48 hours; people have already acted on their own recollection.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Minuting everything.&lt;/strong&gt; If a meeting produces no decision and no action, the minutes should say exactly that — in one line.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="related-templates"&gt;Related templates &lt;a href="#related-templates" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a data-bs-delay="{&amp;#34;hide&amp;#34;:300,&amp;#34;show&amp;#34;:550}" data-bs-html="true" data-bs-title="&lt;a href='https://templates.metacog.co.kr/docs/project-management/status-report/'&gt;&lt;p&gt;PROJECT MANAGEMENT&lt;/p&gt;</description></item><item><title>Business Requirements Document</title><link>https://templates.metacog.co.kr/docs/requirements/business-requirements-document/</link><pubDate>Sun, 23 Aug 2026 00:00:00 +0000</pubDate><guid>https://templates.metacog.co.kr/docs/requirements/business-requirements-document/</guid><description>&lt;p&gt;A BRD describes the problem in business terms. Its discipline is negative: it must not contain a solution. The moment it names a technology, the option space closes before anyone has costed the alternatives.&lt;/p&gt;
&lt;h2 id="when-to-use-it"&gt;When to use it &lt;a href="#when-to-use-it" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Before a build-or-buy decision, or before an RFP goes out.&lt;/li&gt;
&lt;li&gt;When several departments have overlapping demands and someone must reconcile them.&lt;/li&gt;
&lt;li&gt;Not for small changes inside an existing product — a &lt;a data-bs-delay="{&amp;#34;hide&amp;#34;:300,&amp;#34;show&amp;#34;:550}" data-bs-html="true" data-bs-title="&lt;a href='https://templates.metacog.co.kr/docs/requirements/user-story/'&gt;&lt;p&gt;REQUIREMENTS &amp; ANALYSIS&lt;/p&gt;</description></item><item><title>Software Requirements Specification</title><link>https://templates.metacog.co.kr/docs/requirements/software-requirements-specification/</link><pubDate>Sun, 23 Aug 2026 00:00:00 +0000</pubDate><guid>https://templates.metacog.co.kr/docs/requirements/software-requirements-specification/</guid><description>&lt;p&gt;An SRS states what the system must do, precisely enough that two independent teams would build something equivalent and a tester could write cases without asking questions. It is the bridge between the business intent in a &lt;a data-bs-delay="{&amp;#34;hide&amp;#34;:300,&amp;#34;show&amp;#34;:550}" data-bs-html="true" data-bs-title="&lt;a href='https://templates.metacog.co.kr/docs/requirements/business-requirements-document/'&gt;&lt;p&gt;REQUIREMENTS &amp; ANALYSIS&lt;/p&gt;&lt;strong&gt;Business Requirements Document&lt;/strong&gt;&lt;br&gt;What the business needs and why, stated without prescribing a solution.&lt;/a&gt;" data-bs-toggle="tooltip" href="https://templates.metacog.co.kr/docs/requirements/business-requirements-document/"&gt;BRD&lt;/a&gt; and the design in an architecture document.&lt;/p&gt;
&lt;h2 id="when-to-use-it"&gt;When to use it &lt;a href="#when-to-use-it" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;For systems built under contract, or where a formal acceptance gate exists.&lt;/li&gt;
&lt;li&gt;In regulated environments where evidence of specification is required.&lt;/li&gt;
&lt;li&gt;For anything with meaningful non-functional demands — throughput, latency, retention, availability.&lt;/li&gt;
&lt;li&gt;A backlog of &lt;a data-bs-delay="{&amp;#34;hide&amp;#34;:300,&amp;#34;show&amp;#34;:550}" data-bs-html="true" data-bs-title="&lt;a href='https://templates.metacog.co.kr/docs/requirements/user-story/'&gt;&lt;p&gt;REQUIREMENTS &amp; ANALYSIS&lt;/p&gt;</description></item><item><title>User Story</title><link>https://templates.metacog.co.kr/docs/requirements/user-story/</link><pubDate>Sun, 23 Aug 2026 00:00:00 +0000</pubDate><guid>https://templates.metacog.co.kr/docs/requirements/user-story/</guid><description>&lt;p&gt;A user story is a placeholder for a conversation, plus a written record of how that conversation ended. The story text matters much less than the acceptance criteria — those are what a developer builds against and a tester verifies.&lt;/p&gt;
&lt;h2 id="when-to-use-it"&gt;When to use it &lt;a href="#when-to-use-it" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Iterative product delivery with a stable team and a product owner available for questions.&lt;/li&gt;
&lt;li&gt;Any change small enough to finish inside one iteration.&lt;/li&gt;
&lt;li&gt;Not for cross-team contracts or fixed-price scope; use an &lt;a data-bs-delay="{&amp;#34;hide&amp;#34;:300,&amp;#34;show&amp;#34;:550}" data-bs-html="true" data-bs-title="&lt;a href='https://templates.metacog.co.kr/docs/requirements/software-requirements-specification/'&gt;&lt;p&gt;REQUIREMENTS &amp; ANALYSIS&lt;/p&gt;</description></item><item><title>Use Case Specification</title><link>https://templates.metacog.co.kr/docs/requirements/use-case-specification/</link><pubDate>Sun, 23 Aug 2026 00:00:00 +0000</pubDate><guid>https://templates.metacog.co.kr/docs/requirements/use-case-specification/</guid><description>&lt;p&gt;A use case documents a complete interaction from trigger to outcome. Its distinctive value is the alternate and exception flows: the numbered branches where things deviate. Those branches are where most defects and most missing requirements live.&lt;/p&gt;
&lt;h2 id="when-to-use-it"&gt;When to use it &lt;a href="#when-to-use-it" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Interactions with many decision points, states or error paths — payments, claims, onboarding, regulated workflows.&lt;/li&gt;
&lt;li&gt;When several actors, including systems and timers, participate in one flow.&lt;/li&gt;
&lt;li&gt;When a &lt;a data-bs-delay="{&amp;#34;hide&amp;#34;:300,&amp;#34;show&amp;#34;:550}" data-bs-html="true" data-bs-title="&lt;a href='https://templates.metacog.co.kr/docs/requirements/user-story/'&gt;&lt;p&gt;REQUIREMENTS &amp; ANALYSIS&lt;/p&gt;</description></item><item><title>Requirements Traceability Matrix</title><link>https://templates.metacog.co.kr/docs/requirements/requirements-traceability-matrix/</link><pubDate>Sun, 23 Aug 2026 00:00:00 +0000</pubDate><guid>https://templates.metacog.co.kr/docs/requirements/requirements-traceability-matrix/</guid><description>&lt;p&gt;The RTM answers two questions that nothing else answers cheaply: is every requirement covered by a test, and does every piece of built functionality trace back to a requirement? The second direction catches gold-plating and scope creep.&lt;/p&gt;
&lt;h2 id="when-to-use-it"&gt;When to use it &lt;a href="#when-to-use-it" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Regulated delivery (medical, financial, safety, public sector) where coverage evidence is mandatory.&lt;/li&gt;
&lt;li&gt;Fixed-price contracts, where acceptance depends on demonstrable coverage.&lt;/li&gt;
&lt;li&gt;Any project large enough that &amp;ldquo;did we test that?&amp;rdquo; cannot be answered from memory.&lt;/li&gt;
&lt;li&gt;Skip it for small internal product work where the &lt;a data-bs-delay="{&amp;#34;hide&amp;#34;:300,&amp;#34;show&amp;#34;:550}" data-bs-html="true" data-bs-title="&lt;a href='https://templates.metacog.co.kr/docs/testing-qa/test-plan/'&gt;&lt;p&gt;TESTING &amp; QA&lt;/p&gt;</description></item><item><title>Solution Architecture Document</title><link>https://templates.metacog.co.kr/docs/architecture-design/solution-architecture-document/</link><pubDate>Sun, 23 Aug 2026 00:00:00 +0000</pubDate><guid>https://templates.metacog.co.kr/docs/architecture-design/solution-architecture-document/</guid><description>&lt;p&gt;A solution architecture document (SAD) describes a system at the level where changing your mind is still cheap: components, boundaries, data flows, and the quality attributes that drove them. If it reads like a description of the code, it will be obsolete in a month and nobody will update it.&lt;/p&gt;
&lt;h2 id="when-to-use-it"&gt;When to use it &lt;a href="#when-to-use-it" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;New systems, or significant re-platforming of existing ones.&lt;/li&gt;
&lt;li&gt;When more than one team must build against the same structure.&lt;/li&gt;
&lt;li&gt;Before a procurement or security review that needs a system-level view.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="what-it-must-answer"&gt;What it must answer &lt;a href="#what-it-must-answer" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;What are the components, and what is each one responsible for?&lt;/li&gt;
&lt;li&gt;Where are the trust and ownership boundaries?&lt;/li&gt;
&lt;li&gt;How does data flow, and where does it rest?&lt;/li&gt;
&lt;li&gt;Which quality attributes drove the structure, and what did we trade away?&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="template"&gt;Template &lt;a href="#template" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock "&gt;
 &lt;pre id="163673f" class="language-markdown "&gt;
 &lt;code&gt;# Solution Architecture: &amp;lt;System&amp;gt;

| Field | Value |
|---|---|
| Version / date | |
| Architect | |
| Status | Draft / Reviewed / Approved |
| Related | Charter, SRS, ADRs |

## 1. Context
Business purpose in five sentences. Who uses it, what it replaces.

## 2. Drivers and constraints
| # | Driver / constraint | Type | Source | Architectural consequence |
|---|---|---|---|---|

## 3. Quality attribute scenarios
| Attribute | Stimulus | Response | Measure |
|---|---|---|---|

## 4. Logical view
Components and responsibilities. One diagram plus a table — the table is what
people actually read.

| Component | Responsibility | Owner | Technology | Notes |
|---|---|---|---|---|

## 5. Data view
Entities, stores, classification, retention, residency.

## 6. Integration and interfaces
Inbound and outbound, protocols, contracts, failure behaviour.

## 7. Deployment view
Environments, regions, network zones, scaling model.

## 8. Cross-cutting concerns
Identity and access, secrets, observability, error handling, tenancy,
configuration.

## 9. Availability and recovery
SLO, failure modes, RPO/RTO, degraded operation.

## 10. Security
Trust boundaries, threat summary, controls, residual risk.

## 11. Alternatives considered
| Option | Why rejected |
|---|---|

## 12. Risks and open decisions
| # | Item | Owner | Needed by |
|---|---|---|---|&lt;/code&gt;
 &lt;/pre&gt;
 &lt;/div&gt;
&lt;h2 id="worked-example"&gt;Worked example &lt;a href="#worked-example" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock "&gt;
 &lt;pre id="a95d36c" class="language-markdown "&gt;
 &lt;code&gt;# Solution Architecture: Access Provisioning Service (extract)

## 2. Drivers and constraints
| # | Driver / constraint | Type | Source | Consequence |
|---|---|---|---|---|
| D1 | Every entitlement change must be attributable for 7 years | Compliance | Audit finding 2025-11 | Append-only audit store, separate from the operational database, written before the grant is considered successful |
| D2 | HR system is read-only and cannot be replaced | Constraint | BRD §7 | Event-driven ingest with local projection; no writes back to HR |
| D3 | Two of eleven targets have no modern API | Constraint | Discovery | Adapter layer with a batch adapter for the legacy ERP; provisioning latency for those targets is inherently nightly |
| D4 | People Ops must change bundles without a release | Business | BR-04 | Bundle definitions are data, versioned in the database, not code |
| D5 | No new identity licences before FY2027 | Budget | BRD §7 | Reuse existing identity platform for SCIM; no third-party IGA product |

## 3. Quality attribute scenarios
| Attribute | Stimulus | Response | Measure |
|---|---|---|---|
| Latency | Joiner event arrives | Entitlements applied and audited | p95 &amp;lt;= 30 min, excluding batch targets |
| Availability | One target system unavailable | Other entitlements still applied; failed one queued and ticketed | No cascading failure; partial state visible |
| Auditability | Auditor asks who granted X to Y on date Z | Answer from the audit store | &amp;lt; 5 minutes, without engineer involvement |
| Elasticity | 500 joiners in one day (graduate intake) | Processed within the working day | No manual intervention |

## 4. Logical view
| Component | Responsibility | Owner | Technology | Notes |
|---|---|---|---|---|
| Ingest | Receive, deduplicate and validate HR events | Platform | Go service | Idempotent on HR event ID |
| Bundle resolver | Map job code to entitlement set | Platform | Go &amp;#43; Postgres | Bundles are versioned rows; resolution pins a bundle version onto the request |
| Approval | State machine for non-standard entitlements | Platform | Go | States: DRAFT, AWAITING_BUNDLE, AWAITING_APPROVAL, APPROVED, APPLYING, COMPLETE, PARTIAL, REJECTED |
| Adapters (11) | Talk to each target system | Platform | SCIM client; SFTP batch for ERP | One adapter per target, uniform interface, per-adapter retry policy |
| Audit sink | Append-only record of grants and revocations | Security | Object storage, daily signed export | Write precedes success; failure to write fails the grant |
| Admin UI | Bundle maintenance for People Ops | Platform | Server-rendered | Changes are reviewed by a second People Ops user before taking effect |

## 8. Cross-cutting concerns
- **Identity:** the service authenticates to targets with per-target service
 credentials from the secrets manager, rotated every 90 days. It never holds
 end-user credentials.
- **Observability:** correlation ID minted at ingest, propagated to every
 adapter call and written to the audit record. Golden signals per adapter.
- **Error handling:** adapters are the only place that retries; the core state
 machine treats every adapter outcome as final for that attempt.

## 9. Availability and recovery
SLO 99.5% monthly during business hours. Degraded mode: events queue for up to
4 hours without loss. RPO 15 min (Postgres PITR), RTO 4 hours. A queued event
is never dropped; the queue is the durability boundary.

## 11. Alternatives considered
| Option | Why rejected |
|---|---|
| Commercial IGA product | EUR 90k/yr recurring, exceeds FY2027 budget constraint D5; also requires works council review, adding ~6 weeks |
| Direct HR-to-target integrations, no service | No central audit point, which is the whole reason for the project (D1) |
| Synchronous provisioning at HR event time | Couples availability to eleven targets; one target&amp;#39;s outage would fail the joiner entirely |

## 12. Risks and open decisions
| # | Item | Owner | Needed by |
|---|---|---|---|
| 1 | Legacy ERP revocation latency is 26h worst case, against a 1h requirement | A. Vogel | Before UAT — see RTM accepted gaps |
| 2 | Bundle version pinning: do in-flight requests follow bundle edits? Decided no — see ADR-0012 | A. Vogel | Closed |&lt;/code&gt;
 &lt;/pre&gt;
 &lt;/div&gt;
&lt;h2 id="common-mistakes"&gt;Common mistakes &lt;a href="#common-mistakes" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Diagrams without a component table.&lt;/strong&gt; Boxes and arrows do not say who owns a component or what it is responsible for; the table does, and it survives being pasted into a review document.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No drivers section.&lt;/strong&gt; A structure with no stated drivers is indefensible and unmaintainable — the next person cannot tell which parts are load-bearing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Missing alternatives.&lt;/strong&gt; &amp;ldquo;Why not the obvious cheaper thing?&amp;rdquo; will be asked in every review. Answer it once, in writing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cross-cutting concerns left implicit.&lt;/strong&gt; Identity, secrets, observability and error handling are where most production surprises come from.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Document versioned separately from the system.&lt;/strong&gt; Keep it in the repository so a change to structure and a change to the document arrive in the same pull request.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="related-templates"&gt;Related templates &lt;a href="#related-templates" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a data-bs-delay="{&amp;#34;hide&amp;#34;:300,&amp;#34;show&amp;#34;:550}" data-bs-html="true" data-bs-title="&lt;a href='https://templates.metacog.co.kr/docs/architecture-design/architecture-decision-record/'&gt;&lt;p&gt;ARCHITECTURE &amp; DESIGN&lt;/p&gt;</description></item><item><title>Architecture Decision Record</title><link>https://templates.metacog.co.kr/docs/architecture-design/architecture-decision-record/</link><pubDate>Sun, 23 Aug 2026 00:00:00 +0000</pubDate><guid>https://templates.metacog.co.kr/docs/architecture-design/architecture-decision-record/</guid><description>&lt;p&gt;An ADR captures a single significant decision at the moment it is made, while the alternatives are still fresh and nobody yet knows how it turns out. Its purpose is to stop the same argument being had every eighteen months by people who lack the original context.&lt;/p&gt;
&lt;h2 id="when-to-use-it"&gt;When to use it &lt;a href="#when-to-use-it" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Any decision that is expensive to reverse: a datastore, a protocol, a boundary, a vendor, an auth model.&lt;/li&gt;
&lt;li&gt;Any decision where a reasonable engineer would choose differently — that is exactly what needs recording.&lt;/li&gt;
&lt;li&gt;Not for reversible, local choices. If undoing it is an afternoon&amp;rsquo;s work, skip it.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="what-it-must-answer"&gt;What it must answer &lt;a href="#what-it-must-answer" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;What forces were in play at the time, including the non-technical ones?&lt;/li&gt;
&lt;li&gt;What was chosen, stated in one sentence?&lt;/li&gt;
&lt;li&gt;What was rejected, and why — specifically enough that it is not re-proposed unchanged?&lt;/li&gt;
&lt;li&gt;What does this cost us, now and later?&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="template"&gt;Template &lt;a href="#template" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock "&gt;
 &lt;pre id="c995d82" class="language-markdown "&gt;
 &lt;code&gt;# ADR-&amp;lt;NNNN&amp;gt;: &amp;lt;Decision, phrased as a statement&amp;gt;

- **Status:** Proposed / Accepted / Superseded by ADR-XXXX / Deprecated
- **Date:** YYYY-MM-DD
- **Deciders:** names
- **Consulted:** names
- **Supersedes:** ADR-XXXX (if any)

## Context
The forces at play: requirements, constraints, deadlines, team skills, existing
commitments. Write what was true *then*; do not update this section later.

## Decision
One sentence in the active voice: &amp;#34;We will ...&amp;#34;.
Then the detail needed to act on it.

## Options considered
### Option A — &amp;lt;name&amp;gt;
Pros / cons / why not chosen.

### Option B — &amp;lt;name&amp;gt;
...

## Consequences
**Positive:** ...
**Negative:** ...
**Neutral / follow-up work:** ...

## Compliance
How we will notice if this decision is being violated in practice.

## Notes
Links to spikes, benchmarks, discussions.&lt;/code&gt;
 &lt;/pre&gt;
 &lt;/div&gt;
&lt;h2 id="worked-example"&gt;Worked example &lt;a href="#worked-example" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock "&gt;
 &lt;pre id="4133aef" class="language-markdown "&gt;
 &lt;code&gt;# ADR-0012: In-flight provisioning requests keep the bundle version pinned at creation

- **Status:** Accepted
- **Date:** 2026-06-24
- **Deciders:** A. Vogel (architect), J. Marek (lead), K. Ferreira (People Ops)
- **Consulted:** L. Haddad (Internal Audit)

## Context
Access bundles map a job code to a set of entitlements, and People Ops edits
them directly (BR-04) — roughly twice a month, sometimes reactively after an
audit query. A provisioning request can live for weeks: requests are created
when the HR record appears, but entitlements are applied one working day before
the start date.

That means a bundle can change between request creation and application. Audit
requires that we can state, for any grant, which rule produced it (D1). Two
readings of &amp;#34;the correct entitlements&amp;#34; were in conflict: the bundle as it was
when the request was made, or as it is when access is granted.

Postgres row versioning was already in place for bundles; neither option
required new infrastructure.

## Decision
We will pin the bundle version onto the provisioning request at creation time,
and apply that pinned version even if the bundle has since changed.

A People Ops user may explicitly re-resolve a pending request against the
current bundle; this is an auditable action requiring a justification.

## Options considered

### Option A — Pin at creation (chosen)
Every grant traces to exactly one immutable bundle version. The audit answer is
a single row lookup. Cost: a bundle fix does not automatically reach the 30-odd
requests already pending, so a genuine correction needs an explicit re-resolve.

### Option B — Resolve at application time
Always applies the latest thinking, and corrections propagate automatically.
Rejected because the audit trail becomes ambiguous: a grant made at 06:00 and
one at 06:10 could differ with no visible cause, and reconstructing the reason
requires joining against bundle history by timestamp. Internal Audit stated
this would not satisfy the finding.

### Option C — Pin, but auto-re-resolve when the bundle changes
Rejected as the worst of both: the pin exists but is silently broken, so the
recorded version is not necessarily the one applied. Any implementation bug
here produces exactly the class of untraceable grant we are trying to remove.

## Consequences
**Positive**
- One row answers &amp;#34;which rule granted this?&amp;#34; — meets D1 directly.
- Bundle edits are safe to make at any time; they cannot retroactively alter
 what a pending request will do.

**Negative**
- Removing a wrongly-included entitlement requires re-resolving pending
 requests. Worst case observed in the September intake: 90 requests.
- People Ops needs a UI affordance to find and re-resolve pending requests,
 which is extra work (story AP-131).

**Neutral / follow-up**
- Bundle rows become immutable; edits create a new version. Storage growth is
 negligible (tens of rows per year).
- The re-resolve action must appear in the audit log with a justification.

## Compliance
A weekly check asserts that every grant record references a bundle version that
exists and is marked immutable. Any grant referencing a mutable or missing
bundle version alerts to the platform team.

## Notes
Spike results and the audit conversation are in the 2026-06-19 design review
minutes. This decision drove the state machine change recorded in the
technical design.&lt;/code&gt;
 &lt;/pre&gt;
 &lt;/div&gt;
&lt;h2 id="common-mistakes"&gt;Common mistakes &lt;a href="#common-mistakes" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Editing the context after the fact.&lt;/strong&gt; An ADR is a historical record. If the situation changes, write a new ADR that supersedes it; never rewrite the old one.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Options listed without reasons.&lt;/strong&gt; &amp;ldquo;We considered X&amp;rdquo; adds nothing. Why X was worse &lt;em&gt;given the context of the time&lt;/em&gt; is the entire value.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No negative consequences.&lt;/strong&gt; Every real decision costs something. An ADR with only benefits is marketing, and readers discount the whole document.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ADRs for everything.&lt;/strong&gt; Twenty ADRs a month means nobody reads any of them. Reserve them for decisions that are expensive to reverse.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Stored outside the repository.&lt;/strong&gt; ADRs in a wiki drift away from the code. Keep them in &lt;code&gt;docs/adr/&lt;/code&gt; next to what they govern.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="related-templates"&gt;Related templates &lt;a href="#related-templates" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a data-bs-delay="{&amp;#34;hide&amp;#34;:300,&amp;#34;show&amp;#34;:550}" data-bs-html="true" data-bs-title="&lt;a href='https://templates.metacog.co.kr/docs/architecture-design/solution-architecture-document/'&gt;&lt;p&gt;ARCHITECTURE &amp; DESIGN&lt;/p&gt;</description></item><item><title>API Specification</title><link>https://templates.metacog.co.kr/docs/architecture-design/api-specification/</link><pubDate>Sun, 23 Aug 2026 00:00:00 +0000</pubDate><guid>https://templates.metacog.co.kr/docs/architecture-design/api-specification/</guid><description>&lt;p&gt;An API specification is a contract, so it must be precise about the parts people argue over later: error semantics, idempotency, pagination, versioning and deprecation. The schema itself belongs in OpenAPI; this document holds the decisions the schema cannot express.&lt;/p&gt;
&lt;h2 id="when-to-use-it"&gt;When to use it &lt;a href="#when-to-use-it" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Before another team, or an external partner, writes code against your service.&lt;/li&gt;
&lt;li&gt;When a public or partner-facing interface needs a support and deprecation commitment.&lt;/li&gt;
&lt;li&gt;Alongside — not instead of — a machine-readable OpenAPI or protobuf definition.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="what-it-must-answer"&gt;What it must answer &lt;a href="#what-it-must-answer" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;What resources exist, and what operations are allowed on each?&lt;/li&gt;
&lt;li&gt;How does a caller authenticate, and what is it authorised to do?&lt;/li&gt;
&lt;li&gt;What errors can occur, how are they shaped, and which are retryable?&lt;/li&gt;
&lt;li&gt;What are the rate limits, the pagination rules, and the versioning policy?&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="template"&gt;Template &lt;a href="#template" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock "&gt;
 &lt;pre id="a3eb0fc" class="language-markdown "&gt;
 &lt;code&gt;# API Specification: &amp;lt;Service&amp;gt; v&amp;lt;major&amp;gt;

| Field | Value |
|---|---|
| Base URL | |
| Machine-readable spec | link to openapi.yaml |
| Owner team | |
| Support channel | |
| Stability | Experimental / Stable / Deprecated |

## 1. Purpose and audience
Who calls this, for what.

## 2. Authentication and authorisation
Scheme, token lifetime, scopes, and what each scope permits.

## 3. Conventions
Media types, date and money formats, casing, null vs absent, time zones,
correlation header.

## 4. Resources
### &amp;lt;Resource&amp;gt;
| Method | Path | Purpose | Idempotent? | Required scope |
|---|---|---|---|---|

Request and response examples for each non-trivial operation.

## 5. Errors
| HTTP | Code | Meaning | Retryable? | Caller action |
|---|---|---|---|---|

Error body shape, and the rule for machine-readable codes.

## 6. Idempotency and concurrency
Idempotency keys, optimistic concurrency (ETag / version), replay window.

## 7. Pagination, filtering, sorting
## 8. Rate limits and quotas
Limits, headers returned, behaviour at the limit.

## 9. Versioning and deprecation
How breaking changes are made, notice period, sunset headers.

## 10. Non-functional commitments
Latency targets, availability, and where they are measured.

## 11. Changelog&lt;/code&gt;
 &lt;/pre&gt;
 &lt;/div&gt;
&lt;h2 id="worked-example"&gt;Worked example &lt;a href="#worked-example" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock "&gt;
 &lt;pre id="8b75b62" class="language-markdown "&gt;
 &lt;code&gt;# API Specification: Provisioning API v1

| Field | Value |
|---|---|
| Base URL | https://provisioning.internal.example.com/v1 |
| Machine-readable spec | /openapi.yaml |
| Owner team | Platform Identity |
| Stability | Stable since 2026-09-01 |

## 2. Authentication and authorisation
OAuth 2.0 client credentials. Tokens live 15 minutes. Scopes:

| Scope | Permits |
|---|---|
| provisioning.read | Read requests and their status |
| provisioning.write | Create requests, re-resolve pending requests |
| provisioning.approve | Approve or reject non-standard entitlements |

Approval requires a user-delegated token; a service token with
provisioning.approve is rejected, because approval must be attributable to a
person (audit driver D1).

## 3. Conventions
JSON only (`application/json`). Timestamps are RFC 3339 in UTC with a trailing
`Z`. Field names are `snake_case`. Absent means &amp;#34;not supplied&amp;#34;; `null` means
&amp;#34;explicitly cleared&amp;#34; — the two are not interchangeable on PATCH. Every request
should carry `X-Correlation-Id`; if absent, the service mints one and returns
it in the response.

## 4. Resources

### Provisioning requests
| Method | Path | Purpose | Idempotent? | Scope |
|---|---|---|---|---|
| POST | /requests | Create a provisioning request | Yes, with Idempotency-Key | provisioning.write |
| GET | /requests/{id} | Fetch one request | Yes | provisioning.read |
| GET | /requests | List, filtered | Yes | provisioning.read |
| POST | /requests/{id}/approve | Approve pending entitlements | Yes, with If-Match | provisioning.approve |
| POST | /requests/{id}/reject | Reject pending entitlements | Yes, with If-Match | provisioning.approve |
| POST | /requests/{id}/re-resolve | Re-resolve against the current bundle | No | provisioning.write |

POST /requests
{
 &amp;#34;employee_id&amp;#34;: &amp;#34;E-40219&amp;#34;,
 &amp;#34;job_code&amp;#34;: &amp;#34;ENG-3&amp;#34;,
 &amp;#34;start_date&amp;#34;: &amp;#34;2026-10-05&amp;#34;,
 &amp;#34;manager_employee_id&amp;#34;: &amp;#34;E-11804&amp;#34;,
 &amp;#34;additional_entitlements&amp;#34;: [&amp;#34;repo:payments:write&amp;#34;]
}

201 Created
{
 &amp;#34;id&amp;#34;: &amp;#34;req_01J9F3K2&amp;#34;,
 &amp;#34;state&amp;#34;: &amp;#34;AWAITING_APPROVAL&amp;#34;,
 &amp;#34;bundle_version&amp;#34;: &amp;#34;eng-3@17&amp;#34;,
 &amp;#34;entitlements&amp;#34;: [
 {&amp;#34;name&amp;#34;: &amp;#34;sso:default&amp;#34;, &amp;#34;source&amp;#34;: &amp;#34;bundle&amp;#34;, &amp;#34;state&amp;#34;: &amp;#34;PENDING&amp;#34;},
 {&amp;#34;name&amp;#34;: &amp;#34;repo:payments:write&amp;#34;, &amp;#34;source&amp;#34;: &amp;#34;additional&amp;#34;, &amp;#34;state&amp;#34;: &amp;#34;AWAITING_APPROVAL&amp;#34;}
 ],
 &amp;#34;created_at&amp;#34;: &amp;#34;2026-09-18T09:12:44Z&amp;#34;
}

## 5. Errors
Body shape:
{&amp;#34;code&amp;#34;: &amp;#34;bundle_not_found&amp;#34;, &amp;#34;message&amp;#34;: &amp;#34;...&amp;#34;, &amp;#34;correlation_id&amp;#34;: &amp;#34;...&amp;#34;, &amp;#34;details&amp;#34;: {}}

| HTTP | Code | Meaning | Retryable? | Caller action |
|---|---|---|---|---|
| 400 | invalid_request | Schema or field validation failed | No | Fix the request |
| 401 | unauthenticated | Missing or expired token | After refresh | Get a new token |
| 403 | insufficient_scope | Token lacks the scope, or is a service token on /approve | No | Use a delegated token |
| 404 | not_found | Request ID unknown | No | — |
| 409 | state_conflict | Request is not in a state that allows this action | No | Re-read and decide |
| 412 | precondition_failed | If-Match did not match current version | No | Re-read, re-apply |
| 422 | bundle_not_found | Job code has no bundle | No | Route to People Ops |
| 429 | rate_limited | Quota exceeded | Yes, after Retry-After | Back off |
| 503 | target_unavailable | A downstream target system is down | Yes | Retry with backoff; request is queued regardless |

`code` values are stable and part of the contract; `message` is human-readable
and may change without notice. Never branch on `message`.

## 6. Idempotency and concurrency
POST /requests accepts `Idempotency-Key`; the same key with the same body
returns the original 201 for 24 hours. The same key with a *different* body
returns 409 `idempotency_key_reuse`. Approve and reject require `If-Match` with
the request&amp;#39;s ETag, so two managers cannot decide simultaneously.

## 8. Rate limits and quotas
600 requests per minute per client. Responses carry `RateLimit-Limit`,
`RateLimit-Remaining` and `RateLimit-Reset`. Bulk import is exempt but capped
at one concurrent job per client.

## 9. Versioning and deprecation
The major version is in the path. Additive changes (new optional fields, new
enum values on output) ship within v1 — clients must ignore unknown fields and
tolerate unknown enum values. Breaking changes require v2, with both versions
served for at least 6 months. Deprecated endpoints return `Deprecation` and
`Sunset` headers for the whole notice period.

## 10. Non-functional commitments
p95 &amp;lt; 300 ms for reads and &amp;lt; 800 ms for writes, measured at the service&amp;#39;s
ingress. 99.5% monthly availability. These are the numbers the owning team is
paged against.&lt;/code&gt;
 &lt;/pre&gt;
 &lt;/div&gt;
&lt;h2 id="common-mistakes"&gt;Common mistakes &lt;a href="#common-mistakes" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Documenting only the happy path.&lt;/strong&gt; Consumers spend most of their integration effort on errors. The error table is the most-read section of any API document.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No retryability guidance.&lt;/strong&gt; Without it, callers either retry nothing (and drop work) or retry everything (and duplicate it).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;message&lt;/code&gt; used as a machine-readable code.&lt;/strong&gt; State explicitly which field is stable, or clients will parse the prose and break on a typo fix.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Versioning policy left unstated.&lt;/strong&gt; &amp;ldquo;We will not break you&amp;rdquo; is not a policy. Notice period and sunset mechanics are.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Two sources of truth.&lt;/strong&gt; If this document and the OpenAPI file disagree, generate what you can from the schema and keep only the decisions here.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="related-templates"&gt;Related templates &lt;a href="#related-templates" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a data-bs-delay="{&amp;#34;hide&amp;#34;:300,&amp;#34;show&amp;#34;:550}" data-bs-html="true" data-bs-title="&lt;a href='https://templates.metacog.co.kr/docs/architecture-design/solution-architecture-document/'&gt;&lt;p&gt;ARCHITECTURE &amp; DESIGN&lt;/p&gt;</description></item><item><title>Data Model Document</title><link>https://templates.metacog.co.kr/docs/architecture-design/data-model-document/</link><pubDate>Sun, 23 Aug 2026 00:00:00 +0000</pubDate><guid>https://templates.metacog.co.kr/docs/architecture-design/data-model-document/</guid><description>&lt;p&gt;Code gets rewritten; data outlives it. A data model document records what each entity means, what makes it unique, how long it is kept, and how sensitive it is — facts that a schema dump does not carry and that privacy and audit reviews always ask for.&lt;/p&gt;
&lt;h2 id="when-to-use-it"&gt;When to use it &lt;a href="#when-to-use-it" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;New systems that own data, especially anything containing personal data.&lt;/li&gt;
&lt;li&gt;Before a migration, so the target model is agreed before anyone writes DDL.&lt;/li&gt;
&lt;li&gt;When preparing for a &lt;a data-bs-delay="{&amp;#34;hide&amp;#34;:300,&amp;#34;show&amp;#34;:550}" data-bs-html="true" data-bs-title="&lt;a href='https://templates.metacog.co.kr/docs/security-compliance/data-protection-impact-assessment/'&gt;&lt;p&gt;SECURITY &amp; COMPLIANCE&lt;/p&gt;</description></item><item><title>Technical Design Document</title><link>https://templates.metacog.co.kr/docs/architecture-design/technical-design-document/</link><pubDate>Sun, 23 Aug 2026 00:00:00 +0000</pubDate><guid>https://templates.metacog.co.kr/docs/architecture-design/technical-design-document/</guid><description>&lt;p&gt;A TDD (design document, not the testing acronym) sits below architecture and above code. It exists so that a reviewer can find the flaw in an approach in an hour of reading rather than a week of reviewing pull requests.&lt;/p&gt;
&lt;h2 id="when-to-use-it"&gt;When to use it &lt;a href="#when-to-use-it" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Work larger than roughly two weeks, or touching a boundary other teams depend on.&lt;/li&gt;
&lt;li&gt;Anything with tricky state, concurrency, migration or failure semantics.&lt;/li&gt;
&lt;li&gt;Not for routine feature work whose shape is obvious from the &lt;a data-bs-delay="{&amp;#34;hide&amp;#34;:300,&amp;#34;show&amp;#34;:550}" data-bs-html="true" data-bs-title="&lt;a href='https://templates.metacog.co.kr/docs/requirements/user-story/'&gt;&lt;p&gt;REQUIREMENTS &amp; ANALYSIS&lt;/p&gt;</description></item><item><title>Coding Standards</title><link>https://templates.metacog.co.kr/docs/development-release/coding-standards/</link><pubDate>Sun, 23 Aug 2026 00:00:00 +0000</pubDate><guid>https://templates.metacog.co.kr/docs/development-release/coding-standards/</guid><description>&lt;p&gt;A coding standard is only worth writing for rules that are contested and consequential. Formatting is not contested once a formatter is configured; error handling, logging, dependency policy and test expectations are. Write down the second kind.&lt;/p&gt;
&lt;h2 id="when-to-use-it"&gt;When to use it &lt;a href="#when-to-use-it" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;When a team grows past the point where conventions spread by osmosis.&lt;/li&gt;
&lt;li&gt;When several teams contribute to one repository and disagree in review.&lt;/li&gt;
&lt;li&gt;When onboarding time is dominated by &amp;ldquo;how do we do X here?&amp;rdquo; questions.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="what-it-must-answer"&gt;What it must answer &lt;a href="#what-it-must-answer" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Which rules are automated, and which require human judgement?&lt;/li&gt;
&lt;li&gt;What is the escape hatch when a rule does not fit, and who approves it?&lt;/li&gt;
&lt;li&gt;What are the rules that exist for safety rather than taste?&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="template"&gt;Template &lt;a href="#template" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock "&gt;
 &lt;pre id="b696f49" class="language-markdown "&gt;
 &lt;code&gt;# Coding Standards: &amp;lt;Team or repository&amp;gt;

| Field | Value |
|---|---|
| Applies to | |
| Owner | |
| Last reviewed | |

## 1. Automated rules
Everything here is enforced in CI; reviewers must not spend time on it.

| Rule | Tool | Config location | Failing behaviour |
|---|---|---|---|

## 2. Language conventions
Naming, file layout, package structure, public surface.

## 3. Error handling
When to wrap, when to return, what must never be swallowed.

## 4. Logging and observability
Levels, structure, required fields, what must never be logged.

## 5. Testing expectations
What must have a test, what kind, and what coverage means here.

## 6. Dependencies
Adding, pinning, updating, licence policy, and who approves a new one.

## 7. Security rules
Input handling, secrets, crypto, authorisation checks.

## 8. Exceptions
How to deviate: marker, justification, approver, review date.

## 9. Changing this document&lt;/code&gt;
 &lt;/pre&gt;
 &lt;/div&gt;
&lt;h2 id="worked-example"&gt;Worked example &lt;a href="#worked-example" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock "&gt;
 &lt;pre id="a280fc5" class="language-markdown "&gt;
 &lt;code&gt;# Coding Standards: Platform Identity (Go services)

## 1. Automated rules
| Rule | Tool | Config | Failing behaviour |
|---|---|---|---|
| Formatting | gofumpt | Makefile `fmt` | CI fails |
| Static analysis | golangci-lint (errcheck, ineffassign, gosec) | .golangci.yml | CI fails |
| Dependency vulnerabilities | govulncheck | CI workflow | CI fails on High/Critical |
| Licence policy | go-licenses | CI workflow | CI fails on GPL family |
| Test coverage on changed lines | CI script | ci/coverage.sh | Warning below 70%, fail below 50% |

Reviewers must not comment on anything in this table. If a rule is wrong,
change the config, not the review comment.

## 3. Error handling
- Wrap with context at boundaries: `fmt.Errorf(&amp;#34;resolve bundle %s: %w&amp;#34;, code, err)`.
 Do not wrap the same error twice in one call chain.
- Never discard an error with `_` except in deferred `Close()` on a read-only
 handle, and then with a comment saying why.
- Adapters are the only layer that retries. Everything else treats an error as
 final for that attempt. This is a safety rule: nested retries multiply and
 turned a 30-second outage into 40 minutes in incident INC-2026-0142.
- Errors crossing the API boundary map to a stable `code` (see the API
 specification); a new code is an API change and needs the same review.

## 4. Logging and observability
- Structured logs only (slog), never `fmt.Println`.
- Every log line inside a request must carry `correlation_id` and, where it
 exists, `request_id`. Get them from the context; do not pass them explicitly.
- Levels: `error` means someone should look; `warn` means it self-healed;
 `info` is a business event; `debug` is off in production.
- Never log: tokens, entitlement justification text (personal free text),
 full HR records. Log the employee ID, not the name.
- New code paths need a metric before they need a log line — logs are for
 detail, metrics are for detection.

## 5. Testing expectations
- Every bug fix starts with a failing test that reproduces it. No exceptions;
 this is the one rule reviewers do block on.
- State machines and adapters need table-driven tests covering every
 transition or error branch.
- Contract tests against recorded provider responses, refreshed quarterly.
- Coverage is a signal, not a target. 100% coverage of trivial getters is not
 worth a reviewer&amp;#39;s attention; an untested error branch is.

## 6. Dependencies
- A new direct dependency needs a one-paragraph justification in the pull
 request and an approval from a maintainer. Volume, not any single choice, is
 the risk.
- Prefer the standard library. `time`, `net/http` and `database/sql` cover most
 of what small helper libraries offer.
- Pin exact versions; renovate proposes updates weekly, and security updates
 merge without discussion once CI is green.

## 7. Security rules
- Authorisation is checked in the handler, never in the adapter. One place.
- Secrets come from the secrets manager at startup or on rotation; never from
 environment variables baked into an image, never from a file in the repo.
- SQL through parameterised queries only. String-built SQL fails review even
 if the input is &amp;#34;obviously&amp;#34; safe.

## 8. Exceptions
Deviate with a comment: `// standards-exception(&amp;lt;rule&amp;gt;): &amp;lt;why&amp;gt;. approved:
&amp;lt;name&amp;gt; &amp;lt;date&amp;gt;. review: &amp;lt;date&amp;gt;`. CI lists all exceptions in a weekly report so
they do not accumulate silently.

## 9. Changing this document
Open a pull request against it. Two maintainer approvals. A rule that cannot be
justified in two sentences gets deleted rather than debated.&lt;/code&gt;
 &lt;/pre&gt;
 &lt;/div&gt;
&lt;h2 id="common-mistakes"&gt;Common mistakes &lt;a href="#common-mistakes" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Documenting what the formatter already enforces.&lt;/strong&gt; It wastes the reader&amp;rsquo;s attention on the one section that never mattered.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rules with no rationale.&lt;/strong&gt; &amp;ldquo;Do not nest retries&amp;rdquo; is followed inconsistently; &amp;ldquo;do not nest retries — it turned a 30s outage into 40 minutes in INC-2026-0142&amp;rdquo; is followed.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No exception mechanism.&lt;/strong&gt; Teams then either violate the rule silently or contort the code to obey it. Both are worse than a recorded exception.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A standard nobody owns.&lt;/strong&gt; Without an owner and a review date, it fossilises and then gets ignored wholesale.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Coverage percentage as a gate.&lt;/strong&gt; It reliably produces tests for trivial code and leaves the error branches untested.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="related-templates"&gt;Related templates &lt;a href="#related-templates" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a data-bs-delay="{&amp;#34;hide&amp;#34;:300,&amp;#34;show&amp;#34;:550}" data-bs-html="true" data-bs-title="&lt;a href='https://templates.metacog.co.kr/docs/development-release/code-review-checklist/'&gt;&lt;p&gt;DEVELOPMENT &amp; RELEASE&lt;/p&gt;</description></item><item><title>Code Review Checklist</title><link>https://templates.metacog.co.kr/docs/development-release/code-review-checklist/</link><pubDate>Sun, 23 Aug 2026 00:00:00 +0000</pubDate><guid>https://templates.metacog.co.kr/docs/development-release/code-review-checklist/</guid><description>&lt;p&gt;Automation catches formatting, obvious bugs and known vulnerabilities. A human reviewer&amp;rsquo;s scarce attention should go to correctness under conditions the tests do not cover, to blast radius, and to whether the change matches the problem it claims to solve.&lt;/p&gt;
&lt;h2 id="when-to-use-it"&gt;When to use it &lt;a href="#when-to-use-it" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;As a reference for reviewers, especially new ones — it makes review quality less dependent on who is available.&lt;/li&gt;
&lt;li&gt;As the basis for a repository&amp;rsquo;s review guidance in &lt;code&gt;CONTRIBUTING.md&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Not as a form to complete on every change. A three-line config fix does not need eleven checks.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="what-it-must-answer"&gt;What it must answer &lt;a href="#what-it-must-answer" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Does this change do what its description says, and only that?&lt;/li&gt;
&lt;li&gt;What happens when it fails, retries, runs twice, or runs with production data volumes?&lt;/li&gt;
&lt;li&gt;Can it be deployed and rolled back safely?&lt;/li&gt;
&lt;li&gt;Will someone understand it in a year?&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="template"&gt;Template &lt;a href="#template" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock "&gt;
 &lt;pre id="2e38b4c" class="language-markdown "&gt;
 &lt;code&gt;# Code Review Checklist

## Before reviewing
- [ ] CI is green — do not review red pull requests
- [ ] The description explains the *why*, and links a story or issue
- [ ] The change is small enough to review properly (target &amp;lt; 400 lines)

## Correctness
- [ ] The change does what the description claims — no unrelated changes
- [ ] Edge cases: empty, one, many, maximum, null, duplicate
- [ ] Error paths return or propagate; nothing is silently swallowed
- [ ] Idempotent where it can be retried or replayed
- [ ] Concurrency: shared state, ordering assumptions, transaction boundaries

## Data
- [ ] Migrations are backwards compatible for the deploy window
- [ ] Migration is reversible, or the irreversibility is called out
- [ ] Query plans checked for anything touching a large table
- [ ] No unbounded result set or unbounded memory growth

## Security
- [ ] Authorisation checked at the right layer, for every new path
- [ ] Input validated at the trust boundary
- [ ] No secrets, tokens or personal data in code, logs or tests
- [ ] New dependency justified and licence-compatible

## Operability
- [ ] Metric or alert for the new failure mode
- [ ] Log lines carry correlation identifiers, and nothing sensitive
- [ ] Feature flag or another way to disable it without a deploy
- [ ] Runbook updated if operational behaviour changed

## Tests
- [ ] A failing test existed first, for a bug fix
- [ ] Tests assert behaviour, not implementation detail
- [ ] Failure modes are tested, not only the happy path

## Readability
- [ ] Names say what the thing is; comments say why, not what
- [ ] The next person can follow the control flow without a diagram

## Reviewer conduct
- [ ] Distinguish blocking from non-blocking: prefix &amp;#34;nit:&amp;#34; for preference
- [ ] Ask rather than assert when you might be missing context
- [ ] Approve when it is better than what is there, not when it is perfect&lt;/code&gt;
 &lt;/pre&gt;
 &lt;/div&gt;
&lt;h2 id="worked-example"&gt;Worked example &lt;a href="#worked-example" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock "&gt;
 &lt;pre id="6e7ce08" class="language-markdown "&gt;
 &lt;code&gt;## Review of PR #482 — &amp;#34;Pin bundle version at request creation&amp;#34;

**Blocking**

1. `resolveBundle` returns the latest version when the pinned version row is
 missing (bundles.go:88). That silently defeats ADR-0012 — the grant would
 trace to the wrong rule. Should be an error; a missing pinned version is a
 data-integrity problem, not something to paper over.

2. The migration adds `bundle_version NOT NULL` with no default, while the
 previous release still writes rows without it. During the rolling deploy the
 old pods will fail every insert. Two-step it: nullable now, backfill,
 NOT NULL next release.

**Non-blocking**

3. nit: `bv` reads as &amp;#34;bundle version&amp;#34; only if you already know. `bundleVer`
 costs nothing.

4. The table test covers 6 of the 8 transitions; APPROVED -&amp;gt; APPLYING and
 REJECTED -&amp;gt; APPLYING are missing. Not blocking since integration tests hit
 both, but they belong in the unit table.

**Question**

5. If People Ops re-resolves a pending request, does the audit record show both
 the original and the new pinned version? I could not tell from
 `reResolve()`. If not, an auditor cannot reconstruct the change — that would
 be blocking.

**Good**

6. The idempotency key on adapter calls is exactly right and was not asked for.&lt;/code&gt;
 &lt;/pre&gt;
 &lt;/div&gt;
&lt;h2 id="common-mistakes"&gt;Common mistakes &lt;a href="#common-mistakes" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Reviewing style that a linter should catch.&lt;/strong&gt; It trains authors to expect trivial feedback and to skim the substantive kind.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Not distinguishing blocking from preference.&lt;/strong&gt; Authors cannot tell what actually stops the merge, so everything becomes negotiable — or nothing does.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Approving huge pull requests.&lt;/strong&gt; Above roughly 400 lines, review quality collapses. Ask for a split; that is a legitimate review outcome.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Only reading the diff.&lt;/strong&gt; Some defects are only visible in the surrounding function, or in the caller that the diff does not touch.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No positive comments.&lt;/strong&gt; Reviews that only ever list defects make people avoid review, which is the opposite of the goal.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="related-templates"&gt;Related templates &lt;a href="#related-templates" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a data-bs-delay="{&amp;#34;hide&amp;#34;:300,&amp;#34;show&amp;#34;:550}" data-bs-html="true" data-bs-title="&lt;a href='https://templates.metacog.co.kr/docs/development-release/coding-standards/'&gt;&lt;p&gt;DEVELOPMENT &amp; RELEASE&lt;/p&gt;</description></item><item><title>Pull Request Template</title><link>https://templates.metacog.co.kr/docs/development-release/pull-request-template/</link><pubDate>Sun, 23 Aug 2026 00:00:00 +0000</pubDate><guid>https://templates.metacog.co.kr/docs/development-release/pull-request-template/</guid><description>&lt;p&gt;A pull request description is written once and read by every reviewer, every future archaeologist, and whoever is bisecting an incident at 2am. The template&amp;rsquo;s job is to make the author supply context they already have and would otherwise omit.&lt;/p&gt;
&lt;h2 id="when-to-use-it"&gt;When to use it &lt;a href="#when-to-use-it" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Commit it as &lt;code&gt;.github/pull_request_template.md&lt;/code&gt; (or the equivalent) in any repository with more than one contributor.&lt;/li&gt;
&lt;li&gt;Keep separate short templates for chores and docs if the full one causes people to delete it wholesale.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="what-it-must-answer"&gt;What it must answer &lt;a href="#what-it-must-answer" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;What changed, and why is that the right change?&lt;/li&gt;
&lt;li&gt;How do I know it works?&lt;/li&gt;
&lt;li&gt;What is the risk, and how do we back it out?&lt;/li&gt;
&lt;li&gt;What does the reviewer need to look at hardest?&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="template"&gt;Template &lt;a href="#template" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock "&gt;
 &lt;pre id="ed07cd5" class="language-markdown "&gt;
 &lt;code&gt;## What
One or two sentences. What behaviour changes for a user or a caller.

## Why
Link the story, incident or ADR. If there is no link, explain the trigger.

## How
The approach, and anything non-obvious about it. Skip if the diff is
self-explanatory.

## Testing
- [ ] Unit tests added or updated
- [ ] Integration/contract tests
- [ ] Manually verified: &amp;lt;what, in which environment&amp;gt;

## Risk and rollback
- Blast radius if this is wrong:
- Feature flag:
- Rollback procedure:
- Migration reversible? yes / no / n/a

## Checklist
- [ ] No secrets, tokens or personal data added
- [ ] Observability: metric/alert for any new failure mode
- [ ] Docs, runbook or API spec updated
- [ ] Breaking change? If yes, note it here and in the release notes

## Reviewer notes
Where to look first, and anything you are unsure about.

## Screenshots / output
For UI or CLI changes.&lt;/code&gt;
 &lt;/pre&gt;
 &lt;/div&gt;
&lt;h2 id="worked-example"&gt;Worked example &lt;a href="#worked-example" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock "&gt;
 &lt;pre id="4539cd6" class="language-markdown "&gt;
 &lt;code&gt;## What
Provisioning requests now pin the bundle version at creation time. A bundle
edited after a request is created no longer changes what that request applies.

## Why
ADR-0012, driven by audit finding 2025-11: every grant must trace to exactly
one rule version. Story AP-127.

## How
`request.bundle_version` is written at creation and read at application time.
Bundle rows become immutable — `UPDATE` is revoked at the database role level
and edits create a new version row. `reResolve()` is the only way to change a
pending request&amp;#39;s pinned version, and it writes an audit record with the old
and new version plus the operator&amp;#39;s justification.

## Testing
- [x] Unit tests: table-driven over all 8 state transitions, plus the
 missing-pinned-version error case
- [x] Contract tests unchanged and green
- [x] Manually verified in staging: created a request, edited the bundle,
 confirmed the applied entitlements matched the pinned version and that
 the audit record showed `eng-3@17` not `eng-3@18`

## Risk and rollback
- Blast radius: all provisioning requests. Wrong behaviour means wrong access
 granted, which is a security-relevant defect, not a cosmetic one.
- Feature flag: none — the pin is a data property, not a code path. Flagging it
 would create two grant semantics simultaneously, which is worse.
- Rollback: revert the code. The `bundle_version` column stays and is ignored
 by the previous release.
- Migration reversible? Yes. Step 1 of 2 — column added nullable here, made
 NOT NULL in the next release after backfill.

## Checklist
- [x] No secrets or personal data added
- [x] Metric `grants_with_missing_bundle_version` added, alerts at &amp;gt; 0
- [x] Data model document and ADR-0012 updated
- [ ] Breaking change? No — additive for API consumers

## Reviewer notes
Look hardest at `bundles.go:80-110`. An earlier draft fell back to the latest
version when the pinned row was missing, which quietly defeats the whole point;
it now errors. I would like a second opinion on whether `re-resolve` should be
allowed while a request is APPLYING — currently it is not, and I think that is
right, but it is a judgement call.&lt;/code&gt;
 &lt;/pre&gt;
 &lt;/div&gt;
&lt;h2 id="common-mistakes"&gt;Common mistakes &lt;a href="#common-mistakes" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A description that repeats the diff.&lt;/strong&gt; &amp;ldquo;Added a function to resolve bundles&amp;rdquo; is visible in the diff. Why, and what could go wrong, are not.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No link to a story, incident or decision.&lt;/strong&gt; In eighteen months, the link is the only way back to the reasoning.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A checklist that is always fully ticked.&lt;/strong&gt; If nobody ever leaves a box unticked, the checklist has stopped carrying information.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rollback left blank.&lt;/strong&gt; For anything touching data or shared state, this is the section the on-call engineer will need.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A template so long that people delete it.&lt;/strong&gt; Aim for something an author can complete honestly in five minutes.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="related-templates"&gt;Related templates &lt;a href="#related-templates" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a data-bs-delay="{&amp;#34;hide&amp;#34;:300,&amp;#34;show&amp;#34;:550}" data-bs-html="true" data-bs-title="&lt;a href='https://templates.metacog.co.kr/docs/development-release/code-review-checklist/'&gt;&lt;p&gt;DEVELOPMENT &amp; RELEASE&lt;/p&gt;</description></item><item><title>Release Notes</title><link>https://templates.metacog.co.kr/docs/development-release/release-notes/</link><pubDate>Sun, 23 Aug 2026 00:00:00 +0000</pubDate><guid>https://templates.metacog.co.kr/docs/development-release/release-notes/</guid><description>&lt;p&gt;Release notes are written for someone deciding whether to upgrade and what it will cost them. That makes &amp;ldquo;Action required&amp;rdquo; the most important section and the changelog the least — a generated list of commits is not release notes.&lt;/p&gt;
&lt;h2 id="when-to-use-it"&gt;When to use it &lt;a href="#when-to-use-it" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Every release of anything another team or customer consumes.&lt;/li&gt;
&lt;li&gt;Especially when a release contains a breaking change, a deprecation, or a security fix.&lt;/li&gt;
&lt;li&gt;Internal-only services still need them; the audience is the on-call engineer trying to correlate a behaviour change with a deploy.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="what-it-must-answer"&gt;What it must answer &lt;a href="#what-it-must-answer" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Do I need to do anything, and by when?&lt;/li&gt;
&lt;li&gt;What changed that could affect me?&lt;/li&gt;
&lt;li&gt;What is being removed, and what replaces it?&lt;/li&gt;
&lt;li&gt;If something goes wrong, how do I go back?&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="template"&gt;Template &lt;a href="#template" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock "&gt;
 &lt;pre id="73e8cde" class="language-markdown "&gt;
 &lt;code&gt;# &amp;lt;Product&amp;gt; v&amp;lt;version&amp;gt; — YYYY-MM-DD

## Summary
Two sentences. Who should care about this release.

## Action required
| Action | Who | By when | Consequence if skipped |
|---|---|---|---|

If none: &amp;#34;None.&amp;#34;

## Breaking changes
Each with: what changed, why, and the migration path.

## New
## Improved
## Fixed
Reference the issue or defect ID.

## Security
Advisory IDs, severity, and whether exploitation was observed.

## Deprecated
| Item | Deprecated in | Removed in | Replacement |
|---|---|---|---|

## Known issues
| Issue | Impact | Workaround | Fix expected |
|---|---|---|---|

## Upgrade notes
Order of operations, downtime, compatibility window, rollback.&lt;/code&gt;
 &lt;/pre&gt;
 &lt;/div&gt;
&lt;h2 id="worked-example"&gt;Worked example &lt;a href="#worked-example" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock "&gt;
 &lt;pre id="f6bde45" class="language-markdown "&gt;
 &lt;code&gt;# Provisioning API v1.14.0 — 2026-11-12

## Summary
Adds re-resolution of pending requests and tightens bundle version handling.
Callers who read `bundle_version` should note it is now always present.
One security fix, no exploitation observed.

## Action required
| Action | Who | By when | Consequence if skipped |
|---|---|---|---|
| Stop relying on `GET /requests?state=PENDING` — it is removed in v2 | Service desk tooling team | 2027-02-28 | Tooling breaks at the v2 cutover |
| Upgrade the Go client to &amp;gt;= 1.9.0 if you parse `bundle_version` | All API consumers | Before v1.15.0 | Older clients reject the now-always-present field |

## Breaking changes
None in v1. See Deprecated for what changes in v2.

## New
- `POST /requests/{id}/re-resolve` re-evaluates a pending request against the
 current bundle. Requires `provisioning.write` and a justification of at least
 20 characters. Both the old and new bundle version appear in the audit record.
 (AP-131)
- `RateLimit-*` response headers on all endpoints. (AP-140)

## Improved
- Bundle resolution p95 down from 240 ms to 55 ms by caching immutable bundle
 versions. No behaviour change. (AP-138)
- Clearer error when a job code has no bundle: `bundle_not_found` now includes
 the job code in `details`. (AP-142)

## Fixed
- DEF-2026-0311: a request whose pinned bundle version was missing silently fell
 back to the latest version, so a grant could trace to the wrong rule. It now
 fails with `bundle_version_missing` and alerts. Affected 3 requests between
 2026-10-28 and 2026-11-04; all three were reviewed and re-issued, and
 Internal Audit was notified on 2026-11-05.
- DEF-2026-0318: the 72-hour approval escalation did not fire if the service
 restarted within the window. Timers are now persisted.

## Security
- GHSA-xxxx-yyyy-zzzz (High) in a transitive JSON dependency, allowing
 excessive memory allocation on malformed input. Dependency updated. Our
 ingress limits request bodies to 256 KB, so exploitation was not possible
 through the public path; no exploitation observed in logs.

## Deprecated
| Item | Deprecated in | Removed in | Replacement |
|---|---|---|---|
| `GET /requests?state=PENDING` (the PENDING pseudo-state) | v1.14.0 | v2.0.0 (no earlier than 2027-03-01) | `?state=AWAITING_APPROVAL` or `?state=AWAITING_BUNDLE` |
| `X-Request-Trace` header | v1.12.0 | v2.0.0 | `X-Correlation-Id` |

Deprecated endpoints return `Deprecation` and `Sunset` headers from this
release onwards.

## Known issues
| Issue | Impact | Workaround | Fix expected |
|---|---|---|---|
| Legacy ERP revocation runs on the nightly batch | Worst-case 26h revocation latency vs the 1h target | Daily exception report reviewed by People Ops | Blocked on the ERP replacement, FY2027 |

## Upgrade notes
Rolling deploy, no downtime. The database migration is additive and reversible.
Rollback to v1.13.x is safe: `bundle_version` is ignored by that release.&lt;/code&gt;
 &lt;/pre&gt;
 &lt;/div&gt;
&lt;h2 id="common-mistakes"&gt;Common mistakes &lt;a href="#common-mistakes" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A generated commit list.&lt;/strong&gt; Nobody upgrades because of &amp;ldquo;Merge pull request #482&amp;rdquo;. Write for the reader&amp;rsquo;s decision, not the tool&amp;rsquo;s convenience.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Burying the required action.&lt;/strong&gt; If a reader must do something, it goes at the top with a date.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Vague security entries.&lt;/strong&gt; &amp;ldquo;Fixed a security issue&amp;rdquo; invites everyone to assume the worst. Give the advisory ID, severity, and whether exploitation was possible in your configuration.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Deprecation without a removal date.&lt;/strong&gt; Consumers will not act, and you will be unable to remove the thing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Silent fixes of data-affecting bugs.&lt;/strong&gt; The DEF-2026-0311 entry above names the blast radius and the notification. Omitting that is how a defect becomes an audit finding.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="related-templates"&gt;Related templates &lt;a href="#related-templates" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a data-bs-delay="{&amp;#34;hide&amp;#34;:300,&amp;#34;show&amp;#34;:550}" data-bs-html="true" data-bs-title="&lt;a href='https://templates.metacog.co.kr/docs/development-release/deployment-runbook/'&gt;&lt;p&gt;DEVELOPMENT &amp; RELEASE&lt;/p&gt;</description></item><item><title>Deployment Runbook</title><link>https://templates.metacog.co.kr/docs/development-release/deployment-runbook/</link><pubDate>Sun, 23 Aug 2026 00:00:00 +0000</pubDate><guid>https://templates.metacog.co.kr/docs/development-release/deployment-runbook/</guid><description>&lt;p&gt;A deployment runbook is executed under time pressure by someone who may not have written the change. Every step should be a command that can be copied, and every step should have a way to tell whether it worked. The rollback section is written first, not last.&lt;/p&gt;
&lt;h2 id="when-to-use-it"&gt;When to use it &lt;a href="#when-to-use-it" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Any deployment involving a migration, a cutover, a coordinated multi-service change, or an out-of-hours window.&lt;/li&gt;
&lt;li&gt;Not for routine continuous deployment where the pipeline is the runbook — in that case document the pipeline&amp;rsquo;s abort and rollback behaviour instead.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="what-it-must-answer"&gt;What it must answer &lt;a href="#what-it-must-answer" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;What must be true before we start, and who says go?&lt;/li&gt;
&lt;li&gt;What exactly do we run, in what order, and how do we know each step worked?&lt;/li&gt;
&lt;li&gt;At what point does rollback become impossible, and what is the plan after that?&lt;/li&gt;
&lt;li&gt;Who is watching what, for how long, afterwards?&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="template"&gt;Template &lt;a href="#template" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock "&gt;
 &lt;pre id="2f0e39e" class="language-markdown "&gt;
 &lt;code&gt;# Deployment Runbook: &amp;lt;Release / change&amp;gt;

| Field | Value |
|---|---|
| Change reference | CR-xxxx |
| Scheduled window | |
| Deployer | |
| Approver present | |
| Comms channel | |
| Expected duration | |
| Point of no return | Step N |

## 1. Pre-checks (T-24h)
- [ ] Change approved
- [ ] CI green on the exact commit: &amp;lt;sha&amp;gt;
- [ ] Backup verified, restore tested: &amp;lt;evidence&amp;gt;
- [ ] Dependent teams notified
- [ ] Rollback rehearsed in staging on &amp;lt;date&amp;gt;

## 2. Go/no-go (T-0)
| Condition | Check | Go? |
|---|---|---|

## 3. Steps
| # | Action | Command | Expected result | Verify | Owner |
|---|---|---|---|---|---|

Mark the point of no return explicitly.

## 4. Verification
| Check | How | Pass criteria | Owner |
|---|---|---|---|

## 5. Rollback
Trigger conditions, procedure, expected duration, data implications.

## 6. Post-deployment
Monitoring period, who watches what, when the change is declared stable.

## 7. Comms
Who is told at start, at completion, and on rollback.&lt;/code&gt;
 &lt;/pre&gt;
 &lt;/div&gt;
&lt;h2 id="worked-example"&gt;Worked example &lt;a href="#worked-example" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock "&gt;
 &lt;pre id="e974acb" class="language-markdown "&gt;
 &lt;code&gt;# Deployment Runbook: Provisioning API v1.14.0

| Field | Value |
|---|---|
| Change reference | CR-2026-0884 |
| Scheduled window | 2026-11-12, 07:00–08:00 UTC (before the HR feed&amp;#39;s 09:00 burst) |
| Deployer | J. Marek |
| Approver present | A. Vogel |
| Comms channel | #platform-deploys |
| Expected duration | 25 minutes |
| Point of no return | Step 5 (migration applied) |

## 1. Pre-checks (T-24h)
- [x] CR-2026-0884 approved at CAB 2026-11-10
- [x] CI green on commit 9f3c1ab
- [x] Postgres PITR verified; restore of a 2026-11-09 snapshot into staging
 completed in 41 minutes
- [x] Service desk notified — bulk import unavailable for ~10 minutes
- [x] Rollback rehearsed in staging 2026-11-07

## 2. Go/no-go (T-0)
| Condition | Check | Go? |
|---|---|---|
| No open Sev-1/2 incident | Incident board | |
| Error rate at baseline | Dashboard &amp;#34;Provisioning — pipeline&amp;#34; | |
| No HR bulk load running | `SELECT count(*) FROM due_action WHERE state=&amp;#39;RUNNING&amp;#39;` returns 0 | |
| Approver present | — | |

## 3. Steps
| # | Action | Command | Expected result | Verify | Owner |
|---|---|---|---|---|---|
| 1 | Announce start | post in #platform-deploys | — | — | J. Marek |
| 2 | Pause the HR ingest consumer | `provctl ingest pause` | &amp;#34;paused&amp;#34; | `provctl ingest status` shows paused | J. Marek |
| 3 | Confirm the pipeline has drained | — | 0 requests in APPLYING | `requests_by_state{state=&amp;#34;APPLYING&amp;#34;}` = 0 on dashboard | J. Marek |
| 4 | Snapshot the database | `provctl db snapshot --tag pre-1.14.0` | Snapshot ID printed | Snapshot listed and marked complete | J. Marek |
| 5 | **Apply migration (point of no return for schema)** | `provctl migrate up --to 0042` | &amp;#34;applied 1 migration&amp;#34; | `provctl migrate status` shows 0042 current | J. Marek |
| 6 | Deploy v1.14.0 | `provctl deploy --version 1.14.0` | Rolling update completes | All pods Ready, version endpoint reports 1.14.0 | J. Marek |
| 7 | Resume ingest | `provctl ingest resume` | &amp;#34;running&amp;#34; | Backlog drains within 5 minutes | J. Marek |
| 8 | Announce completion | post in #platform-deploys | — | — | J. Marek |

Migration 0042 is additive (adds a nullable column and an index) and is
reversible with `migrate down --to 0041`; &amp;#34;point of no return&amp;#34; here means any
rollback after step 5 must go through the documented down-migration rather than
a simple redeploy.

## 4. Verification
| Check | How | Pass criteria | Owner |
|---|---|---|---|
| Service healthy | `/healthz` on each pod | All 200 | J. Marek |
| Contract tests | `make contract-test ENV=prod-readonly` | All pass | H. Ito |
| Real request end to end | Create a test request for job code TEST-1 | Reaches COMPLETE, audit record written | H. Ito |
| Error rate | Dashboard, 15 minutes | 5xx rate &amp;lt;= baseline &amp;#43; 0.1pp | A. Vogel |
| New metric present | `grants_with_missing_bundle_version` | Exists and is 0 | J. Marek |

## 5. Rollback
**Trigger any of:** 5xx rate above baseline &amp;#43; 1pp for 5 minutes; any request
reaching PARTIAL that would not have before; contract tests failing;
`grants_with_missing_bundle_version` &amp;gt; 0.

**Procedure (approx. 12 minutes):**
1. `provctl ingest pause`
2. `provctl deploy --version 1.13.4`
3. `provctl migrate down --to 0041` — only if v1.13.4 fails to start; the
 column is otherwise ignored and can stay.
4. `provctl ingest resume`
5. Verify with the same checks in section 4.

**Data implications:** requests created under v1.14.0 have a populated
`bundle_version`, which v1.13.4 ignores. No data loss on rollback. Any
re-resolve actions performed under v1.14.0 remain in the audit log and cannot
be undone — this is intentional.

## 6. Post-deployment
Deployer watches the dashboard for 60 minutes. On-call is briefed at handover.
The change is declared stable after the next HR bulk event (09:00) processes
cleanly. If stable, close CR-2026-0884 by 12:00.

## 7. Comms
Start and completion in #platform-deploys. On rollback: #platform-deploys plus
a direct message to the service desk lead, since bulk import stays paused
during rollback.&lt;/code&gt;
 &lt;/pre&gt;
 &lt;/div&gt;
&lt;h2 id="common-mistakes"&gt;Common mistakes &lt;a href="#common-mistakes" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Steps described rather than given.&lt;/strong&gt; &amp;ldquo;Apply the migration&amp;rdquo; leaves the deployer guessing at flags at 07:00. Paste the command.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No verification per step.&lt;/strong&gt; Without it, a half-failed step is discovered three steps later, with unclear state.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rollback written after the deployment section.&lt;/strong&gt; Writing it first often changes the deployment design — a rollback you cannot describe is a deployment you should not do.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The point of no return left implicit.&lt;/strong&gt; People need to know when the cheap option expires.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Written once, never re-run.&lt;/strong&gt; A runbook that has not been executed in staging is a hypothesis.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="related-templates"&gt;Related templates &lt;a href="#related-templates" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a data-bs-delay="{&amp;#34;hide&amp;#34;:300,&amp;#34;show&amp;#34;:550}" data-bs-html="true" data-bs-title="&lt;a href='https://templates.metacog.co.kr/docs/development-release/release-notes/'&gt;&lt;p&gt;DEVELOPMENT &amp; RELEASE&lt;/p&gt;</description></item><item><title>Test Plan</title><link>https://templates.metacog.co.kr/docs/testing-qa/test-plan/</link><pubDate>Sun, 23 Aug 2026 00:00:00 +0000</pubDate><guid>https://templates.metacog.co.kr/docs/testing-qa/test-plan/</guid><description>&lt;p&gt;A test plan is a scoping document, not a list of tests. Its most valuable sections are the ones that say what will &lt;em&gt;not&lt;/em&gt; be covered and what conditions stop testing — those are the statements that get renegotiated under deadline pressure, and having them written down is what makes that renegotiation visible.&lt;/p&gt;
&lt;h2 id="when-to-use-it"&gt;When to use it &lt;a href="#when-to-use-it" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Releases with an acceptance gate, external users, or regulatory exposure.&lt;/li&gt;
&lt;li&gt;Any test effort involving more than one team or a shared environment.&lt;/li&gt;
&lt;li&gt;Not for a single story; its acceptance criteria are its test plan.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="what-it-must-answer"&gt;What it must answer &lt;a href="#what-it-must-answer" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;What is in scope, and at which level is each thing tested?&lt;/li&gt;
&lt;li&gt;What environments and data are needed, and who provides them?&lt;/li&gt;
&lt;li&gt;What are the entry and exit criteria, in numbers?&lt;/li&gt;
&lt;li&gt;What risks are we accepting by not testing something?&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="template"&gt;Template &lt;a href="#template" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock "&gt;
 &lt;pre id="a881a76" class="language-markdown "&gt;
 &lt;code&gt;# Test Plan: &amp;lt;Release or system&amp;gt;

| Field | Value |
|---|---|
| Version / date | |
| Test lead | |
| Approvers | |
| Related | SRS v_, RTM v_ |

## 1. Scope
In scope / out of scope, by feature and by quality attribute.

## 2. Test levels and responsibility
| Level | What it proves | Owner | Automation |
|---|---|---|---|

## 3. Approach per quality attribute
Functional, performance, security, resilience, accessibility, data migration.

## 4. Environments
| Environment | Purpose | Data | Refresh | Owner |
|---|---|---|---|---|

## 5. Test data
Source, anonymisation, volume, and how personal data is handled.

## 6. Entry criteria
## 7. Exit criteria
Numbers, not adjectives.

## 8. Suspension and resumption criteria
When testing stops, and what must happen before it restarts.

## 9. Defect management
Severity definitions, triage cadence, who decides on deferral.

## 10. Risks to the test effort
| Risk | Impact | Mitigation |
|---|---|---|

## 11. Schedule and resources
## 12. Deliverables&lt;/code&gt;
 &lt;/pre&gt;
 &lt;/div&gt;
&lt;h2 id="worked-example"&gt;Worked example &lt;a href="#worked-example" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock "&gt;
 &lt;pre id="662c441" class="language-markdown "&gt;
 &lt;code&gt;# Test Plan: Access Provisioning Service, release 1.0

| Field | Value |
|---|---|
| Version / date | 2.0 / 2026-09-08 |
| Test lead | H. Ito |
| Approvers | A. Vogel (engineering), K. Ferreira (business), L. Haddad (audit) |

## 1. Scope
**In scope:** all Must and Should requirements in SRS v2.0; the eleven target
system adapters; the joiner, mover and leaver flows; audit log completeness;
performance at graduate-intake volume; DR recovery.
**Out of scope:** the admin UI&amp;#39;s visual design (accessibility is in scope, look
and feel is not); the HR system itself; contractor identities (not built).

## 2. Test levels and responsibility
| Level | What it proves | Owner | Automation |
|---|---|---|---|
| Unit | State transitions, bundle resolution, validation | Developers | 100% automated, runs per commit |
| Contract | Adapter behaviour against recorded provider responses | Developers | Automated, nightly refresh check |
| Integration | End-to-end through real sandbox targets | QA | Automated, nightly |
| UAT | People Ops and managers can complete real tasks | Business | Manual, scripted |
| Performance | Intake volumes, p95 latency | QA | Automated, per release candidate |
| Security | Authorisation, secrets handling, injection | External pen test | Manual, once per release |
| DR | RPO/RTO under a simulated region loss | Platform | Manual exercise, once |

## 4. Environments
| Environment | Purpose | Data | Refresh | Owner |
|---|---|---|---|---|
| dev | Developer testing | Synthetic, 50 employees | On demand | Platform |
| int | Automated integration | Synthetic, 4,000 employees | Nightly rebuild | QA |
| uat | Business acceptance | Anonymised production copy | Weekly | QA |
| perf | Load and soak | Synthetic, 6,000 employees | Per test | QA |

Only int and uat are connected to real vendor sandboxes. There is one uat
environment shared with the Finance reconciliation project — a scheduling
conflict risk, see section 10.

## 5. Test data
UAT data is a production copy with names, emails and free-text justifications
replaced by generated values; employee IDs are pseudonymised consistently so
relationships survive. No production personal data reaches dev, int or perf.
The anonymisation script is itself tested (TC-240) because a failure there
would be a personal data breach, not a test failure.

## 6. Entry criteria
- All Must requirements implemented and unit tested.
- Contract tests green against current sandbox recordings.
- Zero open Sev-1 defects; no more than 3 open Sev-2.
- uat refreshed within the last 7 days.

## 7. Exit criteria
- 100% of Must requirements have at least one passing test (per the RTM).
- &amp;gt;= 95% of Should requirements passing.
- Zero open Sev-1; zero open Sev-2 without a written, approved deferral.
- p95 provisioning latency &amp;lt;= 30 minutes at 40 events/hour, and the 500-event
 intake completes within one working day.
- DR exercise achieves RTO &amp;lt;= 4h and RPO &amp;lt;= 15 min.
- Pen test has no unresolved High or Critical finding.
- Audit log completeness check: 100% of grants in a 1,000-grant sample have a
 matching audit record.

## 8. Suspension and resumption criteria
Testing is suspended if the int environment is unavailable for more than four
hours, if a Sev-1 defect blocks more than 30% of planned cases, or if a
sandbox provider changes behaviour mid-cycle. Resumption requires the blocking
condition cleared and a re-run of the affected suite from a clean state.

## 9. Defect management
| Severity | Definition | Response |
|---|---|---|
| Sev-1 | Wrong access granted or revocation fails; data loss; audit record missing | Stop the line, fix immediately |
| Sev-2 | Core flow blocked, no workaround | Fix before release |
| Sev-3 | Workaround exists | Fix or defer with approval |
| Sev-4 | Cosmetic | Backlog |

Triage daily at 09:30 during the cycle. Only the test lead plus the business
approver may defer a Sev-2, and only in writing.

## 10. Risks to the test effort
| Risk | Impact | Mitigation |
|---|---|---|
| uat shared with the Finance project | Cycle delayed by contention | Booked slots agreed 2026-09-01; escalation to M. Duarte |
| Vendor sandbox behaviour diverges from production | False confidence — assumption A-03 | 5% live ramp before full cutover; treat the ramp as a test phase |
| Anonymisation script defect | Personal data in a lower environment | TC-240 verifies it; uat refresh blocked if it fails |

## 12. Deliverables
Test plan (this), test cases in the tracker, defect reports, weekly progress
summary, RTM coverage extract, and the test summary report at exit.&lt;/code&gt;
 &lt;/pre&gt;
 &lt;/div&gt;
&lt;h2 id="common-mistakes"&gt;Common mistakes &lt;a href="#common-mistakes" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Exit criteria written as adjectives.&lt;/strong&gt; &amp;ldquo;Quality is acceptable&amp;rdquo; cannot be argued with data. Numbers can.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No suspension criteria.&lt;/strong&gt; Teams grind on against a broken environment, producing results nobody trusts.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Out-of-scope section missing.&lt;/strong&gt; Everyone then assumes their concern is covered, and discovers otherwise after release.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Test data handling unstated.&lt;/strong&gt; Copying production data into a test environment is one of the most common sources of real breaches.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A plan that duplicates the test cases.&lt;/strong&gt; Keep cases in the tracker; the plan says what kinds exist and why.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="related-templates"&gt;Related templates &lt;a href="#related-templates" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a data-bs-delay="{&amp;#34;hide&amp;#34;:300,&amp;#34;show&amp;#34;:550}" data-bs-html="true" data-bs-title="&lt;a href='https://templates.metacog.co.kr/docs/testing-qa/test-case-specification/'&gt;&lt;p&gt;TESTING &amp; QA&lt;/p&gt;</description></item><item><title>Test Case Specification</title><link>https://templates.metacog.co.kr/docs/testing-qa/test-case-specification/</link><pubDate>Sun, 23 Aug 2026 00:00:00 +0000</pubDate><guid>https://templates.metacog.co.kr/docs/testing-qa/test-case-specification/</guid><description>&lt;p&gt;A test case is a repeatable experiment. If the preconditions are vague or the expected result is &amp;ldquo;works correctly&amp;rdquo;, the case cannot fail cleanly — and a case that cannot fail cleanly generates argument instead of information.&lt;/p&gt;
&lt;h2 id="when-to-use-it"&gt;When to use it &lt;a href="#when-to-use-it" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Manual test execution, especially by people who did not write the software.&lt;/li&gt;
&lt;li&gt;Regulated environments where executed evidence must be retained.&lt;/li&gt;
&lt;li&gt;As the specification for automated cases, so intent survives when the code is refactored.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="what-it-must-answer"&gt;What it must answer &lt;a href="#what-it-must-answer" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;What state must exist before this case runs?&lt;/li&gt;
&lt;li&gt;What exactly does the tester do?&lt;/li&gt;
&lt;li&gt;What is the observable expected result, including in the system&amp;rsquo;s data and logs?&lt;/li&gt;
&lt;li&gt;Which requirement does this case exist to verify?&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="template"&gt;Template &lt;a href="#template" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock "&gt;
 &lt;pre id="3831190" class="language-markdown "&gt;
 &lt;code&gt;| Field | Value |
|---|---|
| Case ID | TC-nnn |
| Title | |
| Verifies | FR/NFR/BR IDs |
| Level | Unit / Integration / System / UAT |
| Type | Positive / Negative / Boundary / Security / Performance |
| Priority | |
| Automated | Yes / No / Planned |
| Preconditions | |
| Test data | |

## Steps
| # | Action | Expected result |
|---|---|---|

## Postconditions
State the system should be left in, including data and audit records.

## Cleanup&lt;/code&gt;
 &lt;/pre&gt;
 &lt;/div&gt;
&lt;h2 id="worked-example"&gt;Worked example &lt;a href="#worked-example" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock "&gt;
 &lt;pre id="99c939e" class="language-markdown "&gt;
 &lt;code&gt;| Field | Value |
|---|---|
| Case ID | TC-124 |
| Title | Approval times out after 72 hours and escalates to the manager&amp;#39;s manager |
| Verifies | FR-03, UC-07 extension 4a4 |
| Level | Integration |
| Type | Boundary / negative |
| Priority | High — this is the path that silently blocks a joiner&amp;#39;s start date |
| Automated | Yes (int suite, clock injected) |
| Preconditions | Service running with `approval_state_machine` enabled; employee E-TEST-01 exists with manager E-TEST-02, whose manager is E-TEST-03; notification service reachable |
| Test data | Job code ENG-3 (bundle eng-3@17); additional entitlement `repo:payments:write` |

## Steps
| # | Action | Expected result |
|---|---|---|
| 1 | Create a request for E-TEST-01 with the additional entitlement | 201; state AWAITING_APPROVAL; bundle_version = eng-3@17 |
| 2 | Confirm no entitlement has been applied | All entitlements in state PENDING or AWAITING_APPROVAL; no adapter call recorded |
| 3 | Confirm notification to E-TEST-02 | Notification record exists within 5 minutes, addressed to E-TEST-02 |
| 4 | Advance the injected clock to T&amp;#43;71h59m | State unchanged; no escalation notification |
| 5 | Advance the injected clock to T&amp;#43;72h01m | Within one poll interval (60s): notification sent to E-TEST-03; audit record `approval_escalated` written with both employee IDs |
| 6 | Confirm bundle entitlements applied | The 9 bundle entitlements move to APPLIED; `repo:payments:write` remains AWAITING_APPROVAL |
| 7 | Approve as E-TEST-03 with justification &amp;#34;Covering approver, joiner starts Monday&amp;#34; | 200; `repo:payments:write` moves to APPLIED; audit record shows approver E-TEST-03 and the justification |
| 8 | Query the audit log for the request | Exactly one record per grant, one for the escalation, one for the approval; no duplicates |

## Postconditions
Request in state COMPLETE with 10 applied entitlements. Audit log contains 12
records for this request. No open service desk ticket.

## Cleanup
Revoke all entitlements for E-TEST-01 via the deprovisioning flow (not by
direct database edit — the audit log must reflect the revocation). Reset the
injected clock.&lt;/code&gt;
 &lt;/pre&gt;
 &lt;/div&gt;
&lt;h2 id="common-mistakes"&gt;Common mistakes &lt;a href="#common-mistakes" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&amp;ldquo;Verify the system works correctly.&amp;rdquo;&lt;/strong&gt; Not a result. Say what is observably true afterwards.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Preconditions that assume yesterday&amp;rsquo;s leftovers.&lt;/strong&gt; Cases that only pass in a particular order are worthless in parallel execution and in CI.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Checking the UI only.&lt;/strong&gt; Step 8 above — checking the audit records — is what catches double-writes that the screen hides.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No cleanup, or cleanup by direct database edit.&lt;/strong&gt; Editing data behind the application&amp;rsquo;s back leaves a state the application can never produce, and later failures get blamed on the wrong thing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;One case covering six requirements.&lt;/strong&gt; When it fails, nobody knows which requirement is broken. Keep it to one intent per case.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="related-templates"&gt;Related templates &lt;a href="#related-templates" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a data-bs-delay="{&amp;#34;hide&amp;#34;:300,&amp;#34;show&amp;#34;:550}" data-bs-html="true" data-bs-title="&lt;a href='https://templates.metacog.co.kr/docs/testing-qa/test-plan/'&gt;&lt;p&gt;TESTING &amp; QA&lt;/p&gt;</description></item><item><title>Defect Report</title><link>https://templates.metacog.co.kr/docs/testing-qa/defect-report/</link><pubDate>Sun, 23 Aug 2026 00:00:00 +0000</pubDate><guid>https://templates.metacog.co.kr/docs/testing-qa/defect-report/</guid><description>&lt;p&gt;The measure of a defect report is whether a developer who has never seen the system can reproduce it from the report alone. Everything else — severity debates, assignment, status — is administration around that one requirement.&lt;/p&gt;
&lt;h2 id="when-to-use-it"&gt;When to use it &lt;a href="#when-to-use-it" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Any behaviour that differs from a specified or reasonably expected result.&lt;/li&gt;
&lt;li&gt;Also for defects found in production, where it becomes the input to an &lt;a data-bs-delay="{&amp;#34;hide&amp;#34;:300,&amp;#34;show&amp;#34;:550}" data-bs-html="true" data-bs-title="&lt;a href='https://templates.metacog.co.kr/docs/operations-incident/incident-report/'&gt;&lt;p&gt;OPERATIONS &amp; INCIDENT&lt;/p&gt;</description></item><item><title>UAT Plan</title><link>https://templates.metacog.co.kr/docs/testing-qa/uat-plan/</link><pubDate>Sun, 23 Aug 2026 00:00:00 +0000</pubDate><guid>https://templates.metacog.co.kr/docs/testing-qa/uat-plan/</guid><description>&lt;p&gt;User acceptance testing answers a different question from system testing: not &amp;ldquo;does it meet the specification&amp;rdquo; but &amp;ldquo;can these people do their job with it&amp;rdquo;. That means real users, real tasks and real data shapes, and an acceptance decision that is defined before testing starts.&lt;/p&gt;
&lt;h2 id="when-to-use-it"&gt;When to use it &lt;a href="#when-to-use-it" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Before go-live for anything with a business user population.&lt;/li&gt;
&lt;li&gt;Before accepting a supplier&amp;rsquo;s delivery under contract.&lt;/li&gt;
&lt;li&gt;When a process, not just a system, is changing — UAT is where process gaps surface.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="what-it-must-answer"&gt;What it must answer &lt;a href="#what-it-must-answer" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Who accepts, on what basis, and what does &amp;ldquo;accepted with conditions&amp;rdquo; mean?&lt;/li&gt;
&lt;li&gt;Which real business scenarios must be completable, by whom?&lt;/li&gt;
&lt;li&gt;What environment and data do participants get?&lt;/li&gt;
&lt;li&gt;How do participants raise problems, and how fast do they get answers?&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="template"&gt;Template &lt;a href="#template" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock "&gt;
 &lt;pre id="9270a96" class="language-markdown "&gt;
 &lt;code&gt;# UAT Plan: &amp;lt;System&amp;gt;

| Field | Value |
|---|---|
| Business owner (accepts) | |
| UAT coordinator | |
| Window | |
| Environment | |
| Related | Test Plan v_, BRD v_ |

## 1. Objectives
What acceptance will and will not prove.

## 2. Participants
| Name | Role | Scenarios | Time committed |
|---|---|---|---|

## 3. Scenarios
| # | Business scenario | Participant | Data needed | Acceptance condition |
|---|---|---|---|---|

## 4. Environment and data
## 5. Entry criteria
## 6. Acceptance criteria
Including what &amp;#34;accept with conditions&amp;#34; requires.

## 7. Defect handling during UAT
Severity, response times, who decides.

## 8. Schedule
| Day | Activity | Who |
|---|---|---|

## 9. Sign-off
| Name | Role | Decision | Date | Conditions |
|---|---|---|---|---|&lt;/code&gt;
 &lt;/pre&gt;
 &lt;/div&gt;
&lt;h2 id="worked-example"&gt;Worked example &lt;a href="#worked-example" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock "&gt;
 &lt;pre id="261de56" class="language-markdown "&gt;
 &lt;code&gt;# UAT Plan: Access Provisioning Service

| Field | Value |
|---|---|
| Business owner (accepts) | K. Ferreira, Head of People Operations |
| UAT coordinator | H. Ito |
| Window | 2026-11-17 to 2026-11-28 |
| Environment | uat, refreshed 2026-11-14 with anonymised production data |

## 1. Objectives
Prove that People Ops can run joiner, mover and leaver events without IT
involvement, that line managers can approve from a phone, and that Internal
Audit can answer an access question from the audit export unaided. It does not
prove performance or resilience — those are covered by the system test plan.

## 2. Participants
| Name | Role | Scenarios | Time committed |
|---|---|---|---|
| K. Ferreira | Head of People Ops | 1, 2, 6 | 4h |
| T. Blomqvist | People Ops administrator | 1–5 | 12h |
| Three line managers (rotating) | Approvers | 3 | 30 min each |
| L. Haddad | Internal Audit | 7 | 3h |
| D. Achebe | Service desk lead | 5, 8 | 4h |

## 3. Scenarios
| # | Business scenario | Participant | Data needed | Acceptance condition |
|---|---|---|---|---|
| 1 | Standard engineering joiner, start date in 10 days | T. Blomqvist | Anonymised joiner record | Access complete one working day before the start date, with no ticket raised |
| 2 | Joiner with an unmapped job code | T. Blomqvist | Job code with no bundle | Lands in the People Ops queue; administrator assigns a bundle and completes it without IT |
| 3 | Joiner needing extra access | Line manager | As scenario 1 plus an additional entitlement | Manager receives the request on a phone and approves it in under 3 minutes |
| 4 | Internal move between departments | T. Blomqvist | Mover record | Old entitlements removed, new applied, no manual cleanup |
| 5 | Leaver with immediate effect | D. Achebe | Leaver record dated today | All non-batch entitlements revoked within 1 hour; the ERP exception appears on the daily report |
| 6 | Bundle change | K. Ferreira | — | A bundle edit takes effect for new requests without an IT release, and does not alter pending requests |
| 7 | Audit question: who granted X to Y on date Z, and under which rule? | L. Haddad | Historical export | Answered from the export in under 5 minutes, without engineering help |
| 8 | Something goes wrong: a target system is down | D. Achebe | Simulated adapter outage | A ticket is raised with the correlation ID, and other entitlements still apply |

## 5. Entry criteria
System test exit criteria met; zero open Sev-1; uat refreshed within 7 days;
participants trained (one 90-minute session on 2026-11-14).

## 6. Acceptance criteria
- All eight scenarios completed with their acceptance condition met.
- No Sev-1 or Sev-2 defect open at the end of the window.
- Participants complete scenarios without IT intervention, except where the
 scenario explicitly involves the service desk.

**Accept with conditions** is permitted only where the condition is written
down with an owner and a date. &amp;#34;Accept with conditions&amp;#34; without a dated
remediation is a rejection.

## 7. Defect handling during UAT
Raised in the tracker with the UAT label; triaged twice daily at 10:00 and
15:00. Sev-1 gets a fix or a workaround within one working day, Sev-2 within
three. The business owner decides severity disputes, not engineering.

## 9. Sign-off
| Name | Role | Decision | Date | Conditions |
|---|---|---|---|---|
| K. Ferreira | Business owner | Accepted with conditions | 2026-11-28 | ERP revocation latency: daily exception report to run from go-live, reviewed by People Ops; ERP fix tracked on the FY2027 roadmap. Owner: K. Ferreira, review 2027-03-31 |
| L. Haddad | Internal Audit | Accepted | 2026-11-27 | — |&lt;/code&gt;
 &lt;/pre&gt;
 &lt;/div&gt;
&lt;h2 id="common-mistakes"&gt;Common mistakes &lt;a href="#common-mistakes" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;UAT run by the project team.&lt;/strong&gt; If a tester is the person who built or specified it, they will not find the process gaps — they will unconsciously avoid them.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Scripted click-through instead of business scenarios.&lt;/strong&gt; &amp;ldquo;Click new, enter name, click save&amp;rdquo; tests the software. &amp;ldquo;Onboard this engineer starting in ten days&amp;rdquo; tests the process.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Acceptance defined after testing.&lt;/strong&gt; The criteria must exist before, or the decision becomes a negotiation about how tired everyone is.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&amp;ldquo;Accepted with conditions&amp;rdquo; as a rubber stamp.&lt;/strong&gt; Every condition needs an owner and a date, otherwise it is an unrecorded defect.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Synthetic data only.&lt;/strong&gt; Real data shapes — long names, missing managers, historical anomalies — are exactly where UAT earns its cost.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="related-templates"&gt;Related templates &lt;a href="#related-templates" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a data-bs-delay="{&amp;#34;hide&amp;#34;:300,&amp;#34;show&amp;#34;:550}" data-bs-html="true" data-bs-title="&lt;a href='https://templates.metacog.co.kr/docs/testing-qa/test-plan/'&gt;&lt;p&gt;TESTING &amp; QA&lt;/p&gt;</description></item><item><title>Test Summary Report</title><link>https://templates.metacog.co.kr/docs/testing-qa/test-summary-report/</link><pubDate>Sun, 23 Aug 2026 00:00:00 +0000</pubDate><guid>https://templates.metacog.co.kr/docs/testing-qa/test-summary-report/</guid><description>&lt;p&gt;The test summary report is the evidence behind a release decision. It is not a recommendation to ship — that decision belongs to the business owner. Keeping those separate is what lets a tester state uncomfortable facts without appearing to block the release.&lt;/p&gt;
&lt;h2 id="when-to-use-it"&gt;When to use it &lt;a href="#when-to-use-it" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;At the end of every formal test cycle, before a go/no-go decision.&lt;/li&gt;
&lt;li&gt;As the retained evidence for audit and for contractual acceptance.&lt;/li&gt;
&lt;li&gt;As the input to the release decision meeting, circulated beforehand.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="what-it-must-answer"&gt;What it must answer &lt;a href="#what-it-must-answer" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Was the plan executed, and where did execution deviate from it?&lt;/li&gt;
&lt;li&gt;What are the results against the stated exit criteria?&lt;/li&gt;
&lt;li&gt;What is still open, and what is the risk of shipping with it open?&lt;/li&gt;
&lt;li&gt;What could we not test, and what does that leave unknown?&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="template"&gt;Template &lt;a href="#template" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock "&gt;
 &lt;pre id="055881d" class="language-markdown "&gt;
 &lt;code&gt;# Test Summary Report: &amp;lt;Release&amp;gt;

| Field | Value |
|---|---|
| Cycle / dates | |
| Test lead | |
| Build tested | commit / version |
| Related | Test Plan v_, RTM v_ |

## 1. Summary
Three sentences: what was tested, headline result, what remains open.

## 2. Execution
| Suite | Planned | Executed | Passed | Failed | Blocked | Not run |
|---|---|---|---|---|---|---|

Explain every deviation from plan.

## 3. Exit criteria status
| Criterion | Target | Actual | Met? |
|---|---|---|---|

## 4. Defects
| Severity | Found | Fixed | Open | Deferred |
|---|---|---|---|---|

Open defects listed individually with impact and workaround.

## 5. Coverage
By requirement priority; reference the RTM.

## 6. Non-functional results
Performance, resilience, security, accessibility — numbers, not verdicts.

## 7. Untested areas and residual risk
| Area | Why not tested | Residual risk | Accepted by |
|---|---|---|---|

## 8. Environment and data notes
Anything that limits confidence in the results.

## 9. Conclusion
State the facts against the criteria. The release decision belongs to the
business owner and is recorded separately.&lt;/code&gt;
 &lt;/pre&gt;
 &lt;/div&gt;
&lt;h2 id="worked-example"&gt;Worked example &lt;a href="#worked-example" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock "&gt;
 &lt;pre id="b1af6e8" class="language-markdown "&gt;
 &lt;code&gt;# Test Summary Report: Access Provisioning Service 1.0

| Field | Value |
|---|---|
| Cycle / dates | System test 2026-10-05 to 2026-11-14; UAT 2026-11-17 to 2026-11-28 |
| Test lead | H. Ito |
| Build tested | v1.0.0-rc4, commit 9f3c1ab |

## 1. Summary
All Must requirements are covered and passing except FR-04 for the legacy ERP,
where revocation is nightly rather than hourly. One Sev-1 defect was found late
(DEF-2026-0311) and fixed. Two Sev-3 defects remain open with workarounds, and
one accepted gap is carried into production with a compensating control.

## 2. Execution
| Suite | Planned | Executed | Passed | Failed | Blocked | Not run |
|---|---|---|---|---|---|---|
| Integration | 186 | 186 | 184 | 2 | 0 | 0 |
| Contract | 44 | 44 | 44 | 0 | 0 | 0 |
| Performance | 9 | 9 | 9 | 0 | 0 | 0 |
| Security (pen test) | — | 1 engagement | — | — | — | — |
| DR exercise | 1 | 1 | 1 | 0 | 0 | 0 |
| UAT scenarios | 8 | 8 | 7 | 1 | 0 | 0 |

Deviation: integration testing was suspended 2026-10-21 to 2026-10-23 when the
vendor sandbox changed its 3DS response shape without notice. The affected 26
cases were re-run from a clean state after contract recordings were refreshed.

## 3. Exit criteria status
| Criterion | Target | Actual | Met? |
|---|---|---|---|
| Must requirements with a passing test | 100% | 11 of 12 | No — see accepted gap |
| Should requirements passing | &amp;gt;= 95% | 100% (3 of 3) | Yes |
| Open Sev-1 | 0 | 0 | Yes |
| Open Sev-2 without approved deferral | 0 | 0 | Yes |
| p95 provisioning latency at 40 events/h | &amp;lt;= 30 min | 11 min | Yes |
| 500-event intake within one working day | Yes | 3h 12m | Yes |
| DR: RTO / RPO | 4h / 15 min | 2h 51m / 4 min | Yes |
| Pen test High/Critical unresolved | 0 | 0 (2 Medium open, scheduled) | Yes |
| Audit log completeness on 1,000-grant sample | 100% | 100% | Yes |

## 4. Defects
| Severity | Found | Fixed | Open | Deferred |
|---|---|---|---|---|
| Sev-1 | 1 | 1 | 0 | 0 |
| Sev-2 | 6 | 6 | 0 | 0 |
| Sev-3 | 19 | 17 | 2 | 0 |
| Sev-4 | 31 | 12 | 19 | 19 |

Open Sev-3:
- DEF-2026-0327: bundle admin screen paginates incorrectly beyond 200 bundles.
 Impact: People Ops cannot see bundles past page 4. Workaround: search by job
 code. Fix scheduled 1.0.1.
- DEF-2026-0333: the daily exception report lists leavers in a non-obvious
 order. Impact: cosmetic but slows the review. Workaround: sort in the
 spreadsheet. Fix scheduled 1.0.1.

## 6. Non-functional results
- Performance: p95 11 min, p99 19 min at 40 events/hour. Bottleneck is adapter
 latency, not the service.
- Resilience: with one adapter fully down, other entitlements continued to
 apply; requests ended PARTIAL with tickets raised, as designed.
- Security: pen test found 2 Medium (verbose error message on the admin login;
 missing `Cache-Control: no-store` on an authenticated response). Both fixed
 in rc4 and retested; no High or Critical.
- Accessibility: admin UI at WCAG 2.1 AA except two contrast failures on the
 status badges — DEF-2026-0339, fix scheduled 1.0.1.

## 7. Untested areas and residual risk
| Area | Why not tested | Residual risk | Accepted by |
|---|---|---|---|
| Contractor identities | Not built | None for this release | K. Ferreira |
| Sustained load beyond 500 events/day | No business case for higher volumes | Unknown behaviour above ~2x peak; would need a load test before any acquisition-driven intake | A. Vogel |
| ERP behaviour under simultaneous joiner and leaver for the same person | Cannot be produced in the vendor sandbox | Ordering ambiguity in a rare case; mitigated by the daily exception report | A. Vogel, L. Haddad |

## 8. Environment and data notes
UAT ran on anonymised production data refreshed 2026-11-14. Two UAT scenarios
used manually constructed records because the anonymised set contained no
employee without a manager — the very case that scenario 2 needed. That case is
therefore less well evidenced than the others.

## 9. Conclusion
Exit criteria are met except &amp;#34;100% of Must requirements passing&amp;#34;, which stands
at 11 of 12 due to the legacy ERP nightly revocation window (FR-04). That gap
is documented in the RTM with a compensating control accepted by Internal Audit
and the business owner. All other criteria are met with margin.&lt;/code&gt;
 &lt;/pre&gt;
 &lt;/div&gt;
&lt;h2 id="common-mistakes"&gt;Common mistakes &lt;a href="#common-mistakes" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A recommendation instead of evidence.&lt;/strong&gt; &amp;ldquo;QA recommends release&amp;rdquo; transfers a business decision to the wrong person and discourages honest reporting.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pass rates without the denominator&amp;rsquo;s story.&lt;/strong&gt; 184 of 186 looks fine until you learn 26 cases were re-run after a mid-cycle environment change.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No untested-areas section.&lt;/strong&gt; What was not tested is the part a release decision most needs and least often gets.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Open defects summarised only as counts.&lt;/strong&gt; List them individually with impact and workaround; a count tells the reader nothing about risk.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Written after the go-live decision.&lt;/strong&gt; Then it is a record of a decision, not an input to one.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="related-templates"&gt;Related templates &lt;a href="#related-templates" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a data-bs-delay="{&amp;#34;hide&amp;#34;:300,&amp;#34;show&amp;#34;:550}" data-bs-html="true" data-bs-title="&lt;a href='https://templates.metacog.co.kr/docs/testing-qa/test-plan/'&gt;&lt;p&gt;TESTING &amp; QA&lt;/p&gt;</description></item><item><title>Operational Runbook</title><link>https://templates.metacog.co.kr/docs/operations-incident/operational-runbook/</link><pubDate>Sun, 23 Aug 2026 00:00:00 +0000</pubDate><guid>https://templates.metacog.co.kr/docs/operations-incident/operational-runbook/</guid><description>&lt;p&gt;A runbook is read in the worst conditions a document ever faces: at night, under stress, by someone unfamiliar with the system. Optimise for that reader. Commands to copy, one alert per section, and an explicit &amp;ldquo;if this does not work, escalate to&amp;rdquo; line.&lt;/p&gt;
&lt;h2 id="when-to-use-it"&gt;When to use it &lt;a href="#when-to-use-it" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Before any service goes live — an on-call rotation without runbooks is an on-call rotation that pages the author every time.&lt;/li&gt;
&lt;li&gt;After every incident that revealed a missing procedure.&lt;/li&gt;
&lt;li&gt;Alongside each alert: if an alert has no runbook section, either write one or delete the alert.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="what-it-must-answer"&gt;What it must answer &lt;a href="#what-it-must-answer" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;What does this service do, and what does it depend on?&lt;/li&gt;
&lt;li&gt;For each alert: what does it mean, how do I check, what do I do?&lt;/li&gt;
&lt;li&gt;What am I allowed to do without waking someone up?&lt;/li&gt;
&lt;li&gt;Who do I escalate to, and when?&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="template"&gt;Template &lt;a href="#template" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock "&gt;
 &lt;pre id="ead7c54" class="language-markdown "&gt;
 &lt;code&gt;# Runbook: &amp;lt;Service&amp;gt;

| Field | Value |
|---|---|
| Owning team | |
| On-call rotation | |
| Escalation | L1 -&amp;gt; L2 -&amp;gt; owner |
| Dashboards | |
| Logs | |
| Source | repo link |
| Last reviewed | |

## 1. What this service does
Three sentences. Business impact if it is down.

## 2. Dependencies
| Depends on | Impact if unavailable | Their on-call |
|---|---|---|

## 3. Health checks
How to tell in 60 seconds whether it is healthy.

## 4. Alerts
### &amp;lt;ALERT_NAME&amp;gt;
- **Means:**
- **Impact:**
- **Check:** commands
- **Fix:** steps
- **If that fails:** escalation
- **Do not:** actions that make it worse

## 5. Common procedures
Restart, scale, drain, replay, pause, backfill.

## 6. Safe / unsafe actions
| Action | Safe? | Notes |
|---|---|---|

## 7. Maintenance
Certificates, credential rotation, log volume, capacity headroom.

## 8. Recovery
Backup locations, restore procedure, RPO/RTO, last exercise date.

## 9. Known issues&lt;/code&gt;
 &lt;/pre&gt;
 &lt;/div&gt;
&lt;h2 id="worked-example"&gt;Worked example &lt;a href="#worked-example" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock "&gt;
 &lt;pre id="324033a" class="language-markdown "&gt;
 &lt;code&gt;# Runbook: Access Provisioning Service

| Field | Value |
|---|---|
| Owning team | Platform Identity |
| On-call | #platform-oncall, PagerDuty schedule &amp;#34;platform-primary&amp;#34; |
| Escalation | Primary -&amp;gt; secondary (15 min) -&amp;gt; A. Vogel (30 min) |
| Dashboards | &amp;#34;Provisioning — pipeline&amp;#34;, &amp;#34;Provisioning — adapters&amp;#34; |
| Last reviewed | 2026-11-30 |

## 1. What this service does
Grants and revokes system access for employees, driven by HR events. If it is
down, new joiners do not get access and leavers are not revoked on time. It is
not customer-facing: a four-hour outage during the working day is a
significant problem; a four-hour outage overnight usually is not.

## 2. Dependencies
| Depends on | Impact if unavailable | Their on-call |
|---|---|---|
| HR feed (webhook) | No new events; existing queue still drains | #hr-platform |
| Postgres (primary) | Service is down; requests queue at ingest | #dba-oncall |
| Secrets manager | Adapters fail auth after the current lease expires (max 1h) | #security-oncall |
| Target systems (11) | Only those entitlements fail; requests end PARTIAL | Varies — see adapter table |

## 4. Alerts

### PROV_DUE_ACTIONS_OVERDUE
- **Means:** the poller has not processed scheduled actions for over 10 minutes.
 Approval escalations and start-date applications are stalled.
- **Impact:** joiners may not have access on their start date. Silent — nobody
 will report it until someone cannot log in.
- **Check:**
 `provctl poller status` — is a leader elected?
 `SELECT count(*), min(due_at) FROM due_action WHERE state=&amp;#39;PENDING&amp;#39; AND due_at &amp;lt; now();`
- **Fix:**
 1. If no leader: `provctl poller elect --force` and confirm within 60s.
 2. If a leader exists but is stuck, restart it: `provctl restart poller`.
 Safe at any time — due actions are idempotent.
 3. Confirm the overdue count returns to 0 within 5 minutes.
- **If that fails:** escalate to secondary. Do not delete rows from
 `due_action` to clear the alert — that silently drops joiner provisioning.
- **Do not:** run the poller in two places manually. Two leaders double-apply
 entitlements, which is a security-relevant event requiring an incident.

### PROV_ADAPTER_ERROR_RATE
- **Means:** one adapter is failing more than 20% of calls over 5 minutes.
- **Impact:** entitlements for that target are not applied; requests end
 PARTIAL and tickets accumulate. Everything else continues.
- **Check:** dashboard &amp;#34;Provisioning — adapters&amp;#34;, identify which target.
 `provctl adapter status &amp;lt;target&amp;gt;` shows last error and retry state.
- **Fix:**
 1. If the target is in a known maintenance window (see #change-calendar),
 pause the adapter: `provctl adapter pause &amp;lt;target&amp;gt;`. Queued work resumes
 when unpaused. Note it in the incident channel.
 2. If auth errors: check credential lease age with
 `provctl secrets status &amp;lt;target&amp;gt;`. Rotate with
 `provctl secrets rotate &amp;lt;target&amp;gt;` — safe, takes ~30 seconds.
 3. Otherwise contact the target system&amp;#39;s on-call from the adapter table.
- **If that fails:** if more than 3 adapters are affected, this is likely
 network or secrets, not the targets. Escalate to secondary immediately.
- **Do not:** raise retry limits to push work through. That was the cause of
 INC-2026-0142, where nested retries turned a 30-second blip into 40 minutes.

### PROV_MISSING_BUNDLE_VERSION
- **Means:** a grant referenced a bundle version that does not exist.
- **Impact:** security-relevant. A grant may be unattributable.
- **Check:** `provctl audit orphan-grants --since 24h`
- **Fix:** none at 3am. Page the owner (A. Vogel) regardless of hour, and open
 a Sev-1 incident. Do not attempt to reconstruct the bundle version.

## 6. Safe / unsafe actions
| Action | Safe? | Notes |
|---|---|---|
| Restart any service pod | Yes | Stateless; in-flight work resumes from the database |
| Pause ingest | Yes | Events queue at the webhook; no loss for up to 24h |
| Pause an adapter | Yes | Other targets unaffected |
| Rotate adapter credentials | Yes | ~30s of failures during rotation |
| Delete rows from `due_action` | **No** | Silently drops provisioning; no recovery path |
| Edit `request.state` directly | **No** | Bypasses the audit log; creates states the application cannot produce |
| Re-run a completed request | **No** | Use the re-resolve action, which is audited |

## 8. Recovery
Postgres PITR, 15-minute RPO, snapshots retained 35 days. Restore procedure is
in the DBA runbook, section 4. Last DR exercise 2026-10-22: RTO 2h51m against
a 4h target. Next exercise due 2027-04.

## 9. Known issues
- Legacy ERP revokes on the nightly batch only; worst case 26h latency against
 a 1h target. The daily exception report (delivered 07:00 to People Ops) is
 the compensating control. Do not raise an incident for this — it is expected.&lt;/code&gt;
 &lt;/pre&gt;
 &lt;/div&gt;
&lt;h2 id="common-mistakes"&gt;Common mistakes &lt;a href="#common-mistakes" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Alerts with no runbook section.&lt;/strong&gt; The on-call engineer then improvises, and improvisation at 3am is how small incidents become large ones.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No &amp;ldquo;do not&amp;rdquo; list.&lt;/strong&gt; The dangerous action is usually the one that appears to clear the alert fastest.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Describing commands instead of giving them.&lt;/strong&gt; &amp;ldquo;Check the poller&amp;rsquo;s leadership status&amp;rdquo; versus a command that can be pasted — the difference is minutes and mistakes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Never reviewed.&lt;/strong&gt; Commands rot. A runbook not reviewed in a year is a set of confident-sounding wrong instructions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Missing the &amp;ldquo;expected, do not escalate&amp;rdquo; section.&lt;/strong&gt; Known issues that page people erode trust in every other alert.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="related-templates"&gt;Related templates &lt;a href="#related-templates" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a data-bs-delay="{&amp;#34;hide&amp;#34;:300,&amp;#34;show&amp;#34;:550}" data-bs-html="true" data-bs-title="&lt;a href='https://templates.metacog.co.kr/docs/operations-incident/incident-report/'&gt;&lt;p&gt;OPERATIONS &amp; INCIDENT&lt;/p&gt;</description></item><item><title>Incident Report</title><link>https://templates.metacog.co.kr/docs/operations-incident/incident-report/</link><pubDate>Sun, 23 Aug 2026 00:00:00 +0000</pubDate><guid>https://templates.metacog.co.kr/docs/operations-incident/incident-report/</guid><description>&lt;p&gt;An incident report records what happened. It is deliberately separate from the &lt;a data-bs-delay="{&amp;#34;hide&amp;#34;:300,&amp;#34;show&amp;#34;:550}" data-bs-html="true" data-bs-title="&lt;a href='https://templates.metacog.co.kr/docs/operations-incident/postmortem/'&gt;&lt;p&gt;OPERATIONS &amp; INCIDENT&lt;/p&gt;&lt;strong&gt;Postmortem&lt;/strong&gt;&lt;br&gt;Blameless analysis of why an incident was possible, and what change would prevent the class of it.&lt;/a&gt;" data-bs-toggle="tooltip" href="https://templates.metacog.co.kr/docs/operations-incident/postmortem/"&gt;Postmortem&lt;/a&gt;, which asks why. Keeping them apart lets the report be published within a day, while memories and logs are fresh, without waiting for analysis to conclude.&lt;/p&gt;
&lt;h2 id="when-to-use-it"&gt;When to use it &lt;a href="#when-to-use-it" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Any incident meeting the declaration threshold: customer impact, data risk, security event, or an SLO breach.&lt;/li&gt;
&lt;li&gt;Also for near misses where only luck prevented impact — those are the cheapest lessons available.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="what-it-must-answer"&gt;What it must answer &lt;a href="#what-it-must-answer" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;What was the impact, on whom, and for how long?&lt;/li&gt;
&lt;li&gt;What is the timeline, in UTC, with sources?&lt;/li&gt;
&lt;li&gt;What did we do, and what actually helped?&lt;/li&gt;
&lt;li&gt;What is still outstanding?&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="template"&gt;Template &lt;a href="#template" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock "&gt;
 &lt;pre id="e8d2106" class="language-markdown "&gt;
 &lt;code&gt;# Incident &amp;lt;ID&amp;gt;: &amp;lt;Short factual title&amp;gt;

| Field | Value |
|---|---|
| Severity | |
| Status | Active / Mitigated / Resolved |
| Detected | UTC, and by what |
| Mitigated | UTC |
| Resolved | UTC |
| Duration of impact | |
| Incident commander | |
| Services affected | |

## Impact
Who, how many, what they could not do, and any financial or regulatory effect.

## Timeline (UTC)
| Time | Event | Source |
|---|---|---|

Facts only. Analysis goes in the postmortem.

## Detection
How we found out, and whether monitoring or a human found it first.

## Actions taken
| Time | Action | By | Effect |
|---|---|---|---|

## Current state
What is fixed, what is on a workaround, what is still degraded.

## Follow-up items
| # | Item | Owner | Due | Tracker |
|---|---|---|---|---|

## Communications
| Time | Audience | Channel | Message summary |
|---|---|---|---|

## Data and security impact
Any data loss, exposure or integrity issue. State &amp;#34;none identified&amp;#34; explicitly.&lt;/code&gt;
 &lt;/pre&gt;
 &lt;/div&gt;
&lt;h2 id="worked-example"&gt;Worked example &lt;a href="#worked-example" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock "&gt;
 &lt;pre id="d74e634" class="language-markdown "&gt;
 &lt;code&gt;# Incident INC-2026-0207: Joiner provisioning stalled for 9 hours

| Field | Value |
|---|---|
| Severity | Sev-2 |
| Status | Resolved |
| Detected | 2026-12-03 07:12 UTC, by a People Ops report — not by monitoring |
| Mitigated | 2026-12-03 07:58 UTC |
| Resolved | 2026-12-03 11:40 UTC |
| Duration of impact | 2026-12-02 22:31 to 2026-12-03 07:58 UTC (9h 27m) |
| Incident commander | J. Marek |
| Services affected | Access Provisioning Service (scheduled actions only) |

## Impact
Fourteen joiners due to start on 2026-12-03 did not have access at 08:00 local
time. Eleven were provisioned by 08:30 after mitigation; three required manual
intervention because their start-date action had already been skipped. Six
approval escalations did not fire, delaying two additional joiners by one day.
No access was granted incorrectly. No data loss. Estimated cost: roughly 20
person-hours of lost productivity plus 3 hours of People Ops effort.

## Timeline (UTC)
| Time | Event | Source |
|---|---|---|
| 2026-12-02 22:29 | Routine node pool upgrade drains the node running the poller leader | Cluster audit log |
| 2026-12-02 22:31 | Poller leader lease expires; no new leader elected | Service logs |
| 2026-12-02 22:41 | `PROV_DUE_ACTIONS_OVERDUE` condition first true | Metrics (retrospective) |
| 2026-12-02 22:41 | Alert not delivered — routed to a Slack channel deleted on 2026-11-19 | PagerDuty routing config |
| 2026-12-03 07:12 | People Ops reports that four joiners have no access | #platform-support |
| 2026-12-03 07:19 | Incident declared, Sev-2, J. Marek commanding | Incident channel |
| 2026-12-03 07:31 | `due_action` backlog identified: 1,204 pending, oldest 8h51m | Investigation |
| 2026-12-03 07:44 | `provctl poller elect --force` executed | Command log |
| 2026-12-03 07:58 | Backlog drained to 0; provisioning resumed | Metrics |
| 2026-12-03 08:30 | 11 of 14 affected joiners confirmed provisioned | People Ops |
| 2026-12-03 09:50 | 3 remaining joiners provisioned manually via re-resolve | Audit log |
| 2026-12-03 11:40 | Alert routing corrected and verified with a test alert; resolved | PagerDuty |

## Detection
Monitoring detected the condition at 22:41 but the alert was never delivered:
its notification target was a Slack channel deleted two weeks earlier, and
PagerDuty had no fallback route. The incident was found by a human 8h31m later.
This detection gap is the most significant finding and is the primary subject
of the postmortem.

## Actions taken
| Time | Action | By | Effect |
|---|---|---|---|
| 07:44 | Forced leader election | J. Marek | Poller resumed; backlog drained in 14 min |
| 08:05 | Paused the node pool upgrade for the remaining nodes | J. Marek | Prevented recurrence during the incident |
| 09:50 | Manually re-resolved 3 requests whose start-date action was skipped | T. Blomqvist | Joiners provisioned; both actions audited |
| 11:20 | Added a fallback route on the PagerDuty service | J. Marek | Undelivered alerts now escalate to the primary |

## Current state
Resolved. Poller is running with a leader; backlog is zero. Alert routing has a
fallback and was verified with a test alert at 11:38. The underlying fragility —
a single-leader poller with no liveness alert of its own — is unchanged and is
the subject of follow-up item 2.

## Follow-up items
| # | Item | Owner | Due | Tracker |
|---|---|---|---|---|
| 1 | Audit every alert route for deleted or invalid targets | J. Marek | 2026-12-10 | OPS-881 |
| 2 | Poller emits a heartbeat; alert on heartbeat absence rather than only on backlog | A. Vogel | 2026-12-19 | OPS-882 |
| 3 | Node pool upgrades drain leader-holding pods gracefully with lease handover | Platform | 2027-01-16 | OPS-884 |
| 4 | Add a synthetic joiner every hour and alert if it is not provisioned | H. Ito | 2027-01-16 | OPS-885 |

## Communications
| Time | Audience | Channel | Message summary |
|---|---|---|---|
| 07:25 | People Ops, service desk | #platform-support | Incident declared, investigating, manual workaround available |
| 08:05 | Same | #platform-support | Mitigated; confirming affected joiners |
| 12:00 | Engineering leadership | Email | Summary, impact, follow-ups, postmortem scheduled 2026-12-05 |

## Data and security impact
None identified. No entitlement was granted without approval; the audit log
shows a complete record for all 14 affected requests, including the three
manual re-resolves. Delayed revocation was not in scope — no leaver event fell
in the affected window (verified against the HR feed).&lt;/code&gt;
 &lt;/pre&gt;
 &lt;/div&gt;
&lt;h2 id="common-mistakes"&gt;Common mistakes &lt;a href="#common-mistakes" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Analysis mixed into the timeline.&lt;/strong&gt; &amp;ldquo;The poller failed because leases are fragile&amp;rdquo; is a hypothesis. The timeline holds observations with sources; the reasoning belongs in the postmortem.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Impact described in system terms.&lt;/strong&gt; &amp;ldquo;The poller was down&amp;rdquo; is not impact. &amp;ldquo;Fourteen joiners had no access on their first morning&amp;rdquo; is.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Timeline without sources.&lt;/strong&gt; Six weeks later nobody can distinguish a logged fact from a recollection.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Follow-up items without owners and dates.&lt;/strong&gt; They will not happen, and the next incident will be the same one.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Omitting &amp;ldquo;no data impact identified&amp;rdquo;.&lt;/strong&gt; Saying nothing leaves the reader to assume the worst, and gives audit nothing to rely on.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="related-templates"&gt;Related templates &lt;a href="#related-templates" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a data-bs-delay="{&amp;#34;hide&amp;#34;:300,&amp;#34;show&amp;#34;:550}" data-bs-html="true" data-bs-title="&lt;a href='https://templates.metacog.co.kr/docs/operations-incident/postmortem/'&gt;&lt;p&gt;OPERATIONS &amp; INCIDENT&lt;/p&gt;</description></item><item><title>Postmortem</title><link>https://templates.metacog.co.kr/docs/operations-incident/postmortem/</link><pubDate>Sun, 23 Aug 2026 00:00:00 +0000</pubDate><guid>https://templates.metacog.co.kr/docs/operations-incident/postmortem/</guid><description>&lt;p&gt;A postmortem asks why the system allowed the incident, not who made a mistake. Blameless is not politeness — it is the only way to get the honest account of what people actually believed at the time, which is where the real causes live.&lt;/p&gt;
&lt;h2 id="when-to-use-it"&gt;When to use it &lt;a href="#when-to-use-it" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;After any Sev-1 or Sev-2 incident, and after significant near misses.&lt;/li&gt;
&lt;li&gt;After any incident where detection was slow, regardless of how small the impact was.&lt;/li&gt;
&lt;li&gt;Within a week of resolution — later than that, the reconstructed reasoning is less reliable than the logs.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="what-it-must-answer"&gt;What it must answer &lt;a href="#what-it-must-answer" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;What did people believe at each decision point, and why was that reasonable?&lt;/li&gt;
&lt;li&gt;Which contributing factors combined to make this possible?&lt;/li&gt;
&lt;li&gt;Why did detection take as long as it did?&lt;/li&gt;
&lt;li&gt;What change removes the whole class of problem, not just this instance?&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="template"&gt;Template &lt;a href="#template" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock "&gt;
 &lt;pre id="42cb24e" class="language-markdown "&gt;
 &lt;code&gt;# Postmortem: &amp;lt;Incident ID&amp;gt; — &amp;lt;title&amp;gt;

| Field | Value |
|---|---|
| Incident | link to the incident report |
| Severity / impact | |
| Facilitator | |
| Participants | |
| Date of review | |
| Status | Draft / Reviewed / Actions tracked |

## 1. Summary
Five sentences a newcomer can understand.

## 2. Contributing factors
Not &amp;#34;the root cause&amp;#34;. List the conditions that had to hold simultaneously.

| Factor | Why it existed | Why it was reasonable at the time |
|---|---|---|

## 3. What went well
Genuinely — the things worth keeping.

## 4. Detection analysis
Time to detect, why, and what would have detected it sooner.

## 5. Response analysis
Decision points, what was known at each, and what would have helped.

## 6. Where we got lucky
The things that could have made this much worse and did not.

## 7. Actions
| # | Action | Type (prevent/detect/mitigate) | Owner | Due | Tracker |
|---|---|---|---|---|---|

## 8. Actions we are deliberately not taking
With reasons.

## 9. Lessons for other teams&lt;/code&gt;
 &lt;/pre&gt;
 &lt;/div&gt;
&lt;h2 id="worked-example"&gt;Worked example &lt;a href="#worked-example" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock "&gt;
 &lt;pre id="f06889f" class="language-markdown "&gt;
 &lt;code&gt;# Postmortem: INC-2026-0207 — Joiner provisioning stalled for 9 hours

| Field | Value |
|---|---|
| Incident | INC-2026-0207 |
| Severity / impact | Sev-2; 14 joiners without access on their first morning |
| Facilitator | H. Ito (not on the responding team, by design) |
| Participants | J. Marek, A. Vogel, T. Blomqvist, platform on-call rotation |
| Date of review | 2026-12-05 |

## 1. Summary
A routine node pool upgrade drained the node holding the provisioning poller&amp;#39;s
leader lease. No new leader was elected because the lease-renewal path had no
handover on graceful shutdown, and the service had no liveness signal of its
own. Monitoring did notice within ten minutes, but the alert was routed to a
Slack channel that had been deleted two weeks earlier, and there was no
fallback route. The failure was therefore invisible for nine hours until a
human noticed missing access.

## 2. Contributing factors
| Factor | Why it existed | Why it was reasonable at the time |
|---|---|---|
| Single-leader poller with no heartbeat | The design (TDD, section 3) chose persisted timers over in-process ones, correctly, but only alerted on the *symptom* (backlog) rather than on leader liveness | Backlog was thought to be a sufficient proxy; in normal operation it is |
| Alert routed to a deleted Slack channel | The channel was deleted during a workspace tidy-up on 2026-11-19; nothing linked channels to alert routes | Nobody deleting a channel had any way to know an alert depended on it |
| No fallback route in PagerDuty | The service was configured with one notification target | Consistent with every other service we own — this was a fleet-wide gap, not a local oversight |
| Node pool upgrades do not consider leases | Cluster upgrades are automated and treat all pods as stateless | True for every other workload we run |
| Overnight window | The failure began at 22:31; nobody was looking | Expected — the service has no overnight SLO |

Note that four of these five had to hold at once. Fixing any single one would
have reduced impact from nine hours to under one.

## 3. What went well
- Once detected, mitigation took 46 minutes, most of it diagnosis; the actual
 fix was one documented command from the runbook.
- The runbook&amp;#39;s explicit &amp;#34;do not delete rows from due_action&amp;#34; warning stopped a
 responder from taking exactly the action that would have permanently dropped
 fourteen joiners&amp;#39; provisioning. This warning was added after a near miss in
 September and paid for itself here.
- The audit log was complete and made the impact assessment straightforward:
 we could state with confidence that no access was granted incorrectly.
- People Ops had a workable manual path and used it without waiting for us.

## 4. Detection analysis
Time to detect: 8h 31m (condition true 22:41, human report 07:12). Monitoring
evaluated correctly; delivery failed silently. PagerDuty does not alert on an
undeliverable notification target, and we had no test that alerts actually
arrive. A synthetic end-to-end check — provision a test joiner hourly and alert
on failure — would have detected this within an hour regardless of which
component broke, and independently of alert routing.

## 5. Response analysis
At 07:19 the responder&amp;#39;s first hypothesis was a database problem, because the
backlog query was slow. Three minutes were spent there. The dashboard shows
backlog size but not leader identity, so leadership was not the obvious first
check. Adding leader identity and lease age to the top of the pipeline
dashboard would have made the cause visible immediately.

## 6. Where we got lucky
- No leaver event fell in the window. A delayed revocation would have made this
 a security incident with an audit obligation, not a productivity one.
- 2026-12-03 was a Wednesday. The same failure on a Friday night would have run
 until Monday: roughly 60 hours, spanning weekend leaver events.
- The 500-joiner graduate intake was three months earlier. The same failure
 during intake would have affected hundreds of people.

## 7. Actions
| # | Action | Type | Owner | Due | Tracker |
|---|---|---|---|---|---|
| 1 | Audit all alert routes for invalid targets; add a CI check that every route resolves | Detect | J. Marek | 2026-12-10 | OPS-881 |
| 2 | Poller emits a heartbeat; alert on its absence within 5 minutes | Detect | A. Vogel | 2026-12-19 | OPS-882 |
| 3 | Hourly synthetic joiner, alerting on failure | Detect | H. Ito | 2027-01-16 | OPS-885 |
| 4 | Graceful lease handover on SIGTERM; verify with a chaos test | Prevent | J. Marek | 2027-01-16 | OPS-884 |
| 5 | Leader identity and lease age on the pipeline dashboard | Mitigate | J. Marek | 2026-12-12 | OPS-886 |
| 6 | Share the alert-route audit pattern at the platform guild — likely fleet-wide | Prevent | H. Ito | 2026-12-19 | OPS-887 |

## 8. Actions we are deliberately not taking
- **Running the poller in multiple instances.** Two leaders double-apply
 entitlements, which is a security-relevant failure far worse than a delay.
 The single-leader design stays; we improve handover and detection instead.
- **Overnight on-call for this service.** The business impact of an overnight
 outage is low provided it is fixed before 08:00. Actions 2 and 3 give us that
 without a rotation change; we will revisit if the synthetic check shows more
 than two overnight failures in a quarter.
- **Blocking node pool upgrades.** They are a security control. Action 4 makes
 the service tolerate them instead.

## 9. Lessons for other teams
Alert routes are configuration that can rot silently, and nothing tells you.
Every team should verify that its alerts are deliverable, and should have at
least one synthetic end-to-end check that does not depend on the same alerting
path as everything else.&lt;/code&gt;
 &lt;/pre&gt;
 &lt;/div&gt;
&lt;h2 id="common-mistakes"&gt;Common mistakes &lt;a href="#common-mistakes" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Hunting for &amp;ldquo;the root cause&amp;rdquo;.&lt;/strong&gt; Real incidents need several conditions to hold at once. Naming one cause guarantees you fix the least important of them.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Blame disguised as analysis.&lt;/strong&gt; &amp;ldquo;The engineer failed to check X&amp;rdquo; ends the inquiry. &amp;ldquo;Nothing in the tooling made X visible&amp;rdquo; continues it, and produces a fix.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No detection analysis.&lt;/strong&gt; Time to detect is usually the largest and cheapest lever on impact.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Only prevention actions.&lt;/strong&gt; You cannot prevent every failure. Detection and mitigation actions are often more valuable per hour spent.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No &amp;ldquo;not doing&amp;rdquo; section.&lt;/strong&gt; Every postmortem generates proposals that would cost more than the incident. Recording the rejection stops them being re-raised, and shows the analysis was a decision rather than a wish list.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Actions untracked.&lt;/strong&gt; If they are not in the same backlog as feature work, they will lose to feature work.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="related-templates"&gt;Related templates &lt;a href="#related-templates" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a data-bs-delay="{&amp;#34;hide&amp;#34;:300,&amp;#34;show&amp;#34;:550}" data-bs-html="true" data-bs-title="&lt;a href='https://templates.metacog.co.kr/docs/operations-incident/incident-report/'&gt;&lt;p&gt;OPERATIONS &amp; INCIDENT&lt;/p&gt;</description></item><item><title>Change Request</title><link>https://templates.metacog.co.kr/docs/operations-incident/change-request/</link><pubDate>Sun, 23 Aug 2026 00:00:00 +0000</pubDate><guid>https://templates.metacog.co.kr/docs/operations-incident/change-request/</guid><description>&lt;p&gt;A change request exists so that someone other than the implementer assesses risk before a production change, and so there is a record afterwards. It becomes bureaucracy when every change gets the same scrutiny — the useful version has clear categories with genuinely different paths.&lt;/p&gt;
&lt;h2 id="when-to-use-it"&gt;When to use it &lt;a href="#when-to-use-it" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Production changes affecting shared services, data, or anything under a regulatory or contractual obligation.&lt;/li&gt;
&lt;li&gt;Standard, pre-approved changes still need a record — but not a meeting.&lt;/li&gt;
&lt;li&gt;Emergency changes get retrospective approval, on a defined deadline.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="what-it-must-answer"&gt;What it must answer &lt;a href="#what-it-must-answer" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;What is changing, when, and who is doing it?&lt;/li&gt;
&lt;li&gt;What is the risk, and what happens if it goes wrong?&lt;/li&gt;
&lt;li&gt;How do we back it out, and how long does that take?&lt;/li&gt;
&lt;li&gt;Who approved it, and on what basis?&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="template"&gt;Template &lt;a href="#template" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock "&gt;
 &lt;pre id="ce0135c" class="language-markdown "&gt;
 &lt;code&gt;# Change Request CR-&amp;lt;id&amp;gt;

| Field | Value |
|---|---|
| Title | |
| Type | Standard (pre-approved) / Normal / Emergency |
| Risk | Low / Medium / High |
| Requested by / team | |
| Implementer | |
| Window | start–end, timezone |
| Services affected | |
| Customer impact | None / Degraded / Outage — with duration |
| Related | Release notes, runbook, incident |

## 1. Description
What changes, in one paragraph a non-specialist can follow.

## 2. Justification
Why now, and what happens if we do not.

## 3. Risk assessment
| Risk | Likelihood | Impact | Mitigation |
|---|---|---|---|

## 4. Implementation plan
Link the deployment runbook; do not duplicate it.

## 5. Verification
How we will know it worked.

## 6. Backout plan
Trigger, procedure, duration, and the point after which backout is not possible.

## 7. Communications
Who is told, when.

## 8. Approvals
| Role | Name | Decision | Date | Conditions |
|---|---|---|---|---|

## 9. Post-implementation review
Completed as planned? Issues? Actual duration?&lt;/code&gt;
 &lt;/pre&gt;
 &lt;/div&gt;
&lt;h2 id="worked-example"&gt;Worked example &lt;a href="#worked-example" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock "&gt;
 &lt;pre id="f069147" class="language-markdown "&gt;
 &lt;code&gt;# Change Request CR-2026-0884

| Field | Value |
|---|---|
| Title | Deploy Provisioning API v1.14.0 (bundle version pinning fix) |
| Type | Normal |
| Risk | Medium |
| Requested by | Platform Identity |
| Implementer | J. Marek |
| Window | 2026-11-12 07:00–08:00 UTC |
| Services affected | Access Provisioning Service; bulk import unavailable ~10 min |
| Customer impact | Degraded — bulk import paused; no impact on individual provisioning |
| Related | Release notes v1.14.0; deployment runbook; DEF-2026-0311 |

## 1. Description
Deploys the fix for DEF-2026-0311, where a provisioning request could apply a
different bundle version from the one recorded against it, producing a grant
that cannot be traced to a rule. The change makes that condition an error and
adds an alert. Also adds the re-resolve endpoint and rate-limit headers.

## 2. Justification
DEF-2026-0311 is a Sev-1 control failure already reported to Internal Audit.
The current mitigation (disabling the bundle clean-up action) is manual and
easily undone by anyone with admin access. Delay keeps an audit finding open.

## 3. Risk assessment
| Risk | Likelihood | Impact | Mitigation |
|---|---|---|---|
| Migration fails mid-deploy | Low | Requests cannot be created until rolled back | Additive nullable column; rehearsed in staging 2026-11-07; snapshot taken at step 4 |
| Old pods reject inserts during the rolling window | Low | Transient errors; events queue and retry | Column is nullable in this release; NOT NULL deferred to the next |
| New error path fires on legitimate requests | Medium | Requests fail instead of applying the wrong bundle | Intended behaviour — failing safe is preferred. Alert routes to the platform on-call; volume expected to be zero |
| Window overlaps the HR feed burst | Low | Backlog | Window is before the 09:00 burst; ingest paused during deploy |

## 4. Implementation plan
See the deployment runbook for v1.14.0. Eight steps, ~25 minutes, point of no
return at step 5.

## 5. Verification
Health checks on all pods, read-only contract tests against production, one
end-to-end test request for job code TEST-1 reaching COMPLETE with an audit
record, 5xx rate within baseline &amp;#43; 0.1pp over 15 minutes, and the new metric
present and reading zero.

## 6. Backout plan
Trigger: 5xx above baseline &amp;#43; 1pp for 5 minutes, contract test failure, or any
unexpected PARTIAL request. Procedure: pause ingest, deploy v1.13.4, resume;
approximately 12 minutes. The down-migration is only needed if v1.13.4 fails to
start, since it ignores the new column. Backout remains possible throughout;
after step 5 it requires the down-migration rather than a simple redeploy.

## 7. Communications
#platform-deploys at start and completion. Service desk lead notified 24h ahead
about the bulk import pause, and directly on any rollback.

## 8. Approvals
| Role | Name | Decision | Date | Conditions |
|---|---|---|---|---|
| Service owner | A. Vogel | Approved | 2026-11-10 | — |
| CAB chair | D. Achebe | Approved | 2026-11-10 | Approver present in the window |
| Security | A. Berg | Approved | 2026-11-10 | Internal Audit notified when the fix is live |

## 9. Post-implementation review
Completed 2026-11-12 07:52 UTC, 8 minutes ahead of the window. All verification
passed. One deviation: the ingest backlog took 7 minutes to drain rather than
the expected 5, because an overnight HR batch had queued more events than
usual. No impact. CR closed 2026-11-12 11:40 after the 09:00 burst processed
cleanly.&lt;/code&gt;
 &lt;/pre&gt;
 &lt;/div&gt;
&lt;h2 id="common-mistakes"&gt;Common mistakes &lt;a href="#common-mistakes" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;One process for every change.&lt;/strong&gt; If a config toggle needs the same paperwork as a database migration, people will route around the process entirely.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Backout plan as &amp;ldquo;roll back the deployment&amp;rdquo;.&lt;/strong&gt; For anything touching data that is a hypothesis, not a plan. Say what happens to records written under the new version.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Approvers who cannot assess the risk.&lt;/strong&gt; A signature from someone with no basis to judge adds delay and no safety. Pick approvers who can actually say no.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No post-implementation review.&lt;/strong&gt; Without it, the estimates in every future change request stay unexamined.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Emergency changes never regularised.&lt;/strong&gt; Define the retrospective approval deadline, and measure how many changes take the emergency path — a rising number means the normal path is broken.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="related-templates"&gt;Related templates &lt;a href="#related-templates" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a data-bs-delay="{&amp;#34;hide&amp;#34;:300,&amp;#34;show&amp;#34;:550}" data-bs-html="true" data-bs-title="&lt;a href='https://templates.metacog.co.kr/docs/development-release/deployment-runbook/'&gt;&lt;p&gt;DEVELOPMENT &amp; RELEASE&lt;/p&gt;</description></item><item><title>On-call Handover</title><link>https://templates.metacog.co.kr/docs/operations-incident/on-call-handover/</link><pubDate>Sun, 23 Aug 2026 00:00:00 +0000</pubDate><guid>https://templates.metacog.co.kr/docs/operations-incident/on-call-handover/</guid><description>&lt;p&gt;Everything a handover needs is already somewhere — in dashboards, tickets, incident channels. The point of writing it down is that the incoming engineer should not have to reconstruct it from six places at the start of a shift, and definitely not at 02:00.&lt;/p&gt;
&lt;h2 id="when-to-use-it"&gt;When to use it &lt;a href="#when-to-use-it" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Every rotation change, even a quiet one — &amp;ldquo;nothing outstanding&amp;rdquo; is useful information.&lt;/li&gt;
&lt;li&gt;At the start and end of a shift spanning an active incident.&lt;/li&gt;
&lt;li&gt;Before planned absence, when a service&amp;rsquo;s only informed person will be unavailable.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="what-it-must-answer"&gt;What it must answer &lt;a href="#what-it-must-answer" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;What is currently broken or degraded?&lt;/li&gt;
&lt;li&gt;What is expected to happen during your shift?&lt;/li&gt;
&lt;li&gt;What is fragile right now, and what do I do if it moves?&lt;/li&gt;
&lt;li&gt;What did I try that did not work, so you do not repeat it?&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="template"&gt;Template &lt;a href="#template" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock "&gt;
 &lt;pre id="a434da8" class="language-markdown "&gt;
 &lt;code&gt;# On-call handover: &amp;lt;rotation&amp;gt; — YYYY-MM-DD HH:MM UTC

**Outgoing:** name **Incoming:** name

## Active incidents
| ID | Sev | State | What is needed next | Channel |
|---|---|---|---|---|

## Degraded or on a workaround
| Service | State | Workaround in place | Expires / needs attention |
|---|---|---|---|

## Expected during your shift
| When | What | Whose | What to do if it goes wrong |
|---|---|---|---|

## Watch list
Things not yet broken but trending badly, with the threshold that matters.

## Known noise
Alerts that will fire and are expected — with the reason and the ticket.

## Tried and did not work
So the next person does not repeat it.

## Access and escalation notes
Anything unusual about who is reachable.&lt;/code&gt;
 &lt;/pre&gt;
 &lt;/div&gt;
&lt;h2 id="worked-example"&gt;Worked example &lt;a href="#worked-example" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock "&gt;
 &lt;pre id="ce024fc" class="language-markdown "&gt;
 &lt;code&gt;# On-call handover: platform-primary — 2026-12-03 18:00 UTC

**Outgoing:** J. Marek **Incoming:** P. Nowak

## Active incidents
| ID | Sev | State | What is needed next | Channel |
|---|---|---|---|---|
| INC-2026-0207 | Sev-2 | Resolved 11:40, monitoring | Nothing unless the poller backlog rises again. Postmortem is Friday; do not start analysis in the channel | #inc-2026-0207 |

## Degraded or on a workaround
| Service | State | Workaround | Expires / needs attention |
|---|---|---|---|
| Provisioning | Bundle clean-up admin action disabled since 2026-11-04 | Manual, by config flag | Stays until v1.14.0 ships (2026-11-12 — already shipped; flag can now be re-enabled, ticket OPS-878 open, not urgent) |
| Provisioning poller | Running normally, but no heartbeat alert yet (OPS-882 in progress) | Backlog alert only, now routed correctly | If the backlog alert fires, check leader identity first — it is on the pipeline dashboard as of today |
| Node pool upgrades | Paused on 3 remaining nodes since 08:05 | Manual pause | Security wants them completed by 2026-12-06. Do not resume during your shift; A. Vogel is coordinating with the lease handover fix |

## Expected during your shift
| When | What | Whose | What to do if it goes wrong |
|---|---|---|---|
| 22:00 UTC | HR nightly batch, ~40 events | HR platform | Expect a brief backlog; it should clear within 15 min. If not, check adapters before assuming the poller |
| 23:30 UTC | Legacy ERP nightly provisioning batch | ERP team | Failures show as PARTIAL requests plus tickets. Not a page — the daily exception report catches it. ERP on-call is #erp-oncall but they do not staff overnight |
| 02:00 UTC | Certificate renewal on the admin ingress (automated) | Platform | Runbook section 7. Manual renewal command is there; takes 4 minutes |

## Watch list
- Postgres primary disk at 71%, rising ~1.5pp/week. Alert threshold 85%. Not
 your problem this shift, but if it jumps more than 3pp overnight, something
 is writing more than it should — check the audit table partition size first.
- One adapter (the HR-adjacent directory) has been at a 3–4% error rate all
 week, well below the 20% alert. Retries absorb it. Ticket OPS-879.

## Known noise
- `PROV_ADAPTER_ERROR_RATE` for the ERP target will fire around 23:35 and clear
 by 23:50. Expected — the batch closes its connection abruptly. Ticket
 OPS-860, fix scheduled but not started. Do not escalate.

## Tried and did not work
- During INC-2026-0207 I tried `provctl poller restart` before forcing an
 election. It did not help, because the stale lease had not expired; the pod
 restarted and waited. `provctl poller elect --force` is the command that
 works. The runbook now says so.

## Access and escalation notes
A. Vogel is on a flight 20:00–23:30 UTC and unreachable. Secondary escalation
for anything provisioning-related is H. Ito, who ran the test cycle and knows
the system well. DBA on-call rotation changed on Monday: it is now
#dba-oncall-eu, not the old channel, which still exists and is unmonitored.&lt;/code&gt;
 &lt;/pre&gt;
 &lt;/div&gt;
&lt;h2 id="common-mistakes"&gt;Common mistakes &lt;a href="#common-mistakes" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&amp;ldquo;All quiet&amp;rdquo; when it is not.&lt;/strong&gt; The watch list is exactly what the incoming engineer cannot see for themselves.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Omitting known noise.&lt;/strong&gt; An engineer paged by an expected alert wastes twenty minutes and loses trust in the alert set.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No &amp;ldquo;tried and did not work&amp;rdquo;.&lt;/strong&gt; This is the highest-value section per line and is almost always left out.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Handover only in chat.&lt;/strong&gt; A written artefact survives the shift; a chat thread scrolls away and cannot be read at the start of the next handover.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Escalation contacts assumed current.&lt;/strong&gt; Rotations and channels change. The one time it matters is at 02:00.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="related-templates"&gt;Related templates &lt;a href="#related-templates" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a data-bs-delay="{&amp;#34;hide&amp;#34;:300,&amp;#34;show&amp;#34;:550}" data-bs-html="true" data-bs-title="&lt;a href='https://templates.metacog.co.kr/docs/operations-incident/operational-runbook/'&gt;&lt;p&gt;OPERATIONS &amp; INCIDENT&lt;/p&gt;</description></item><item><title>Information Security Policy</title><link>https://templates.metacog.co.kr/docs/security-compliance/information-security-policy/</link><pubDate>Sun, 23 Aug 2026 00:00:00 +0000</pubDate><guid>https://templates.metacog.co.kr/docs/security-compliance/information-security-policy/</guid><description>&lt;p&gt;A security policy states what must be true. It is not a standard (how), a procedure (steps), or a guideline (advice) — mixing those is why most policies are long, unread and unenforceable. Keep the policy short and put the detail in documents that can change without a board approval cycle.&lt;/p&gt;
&lt;h2 id="when-to-use-it"&gt;When to use it &lt;a href="#when-to-use-it" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;When certification (ISO 27001, SOC 2) or a customer contract requires documented policy.&lt;/li&gt;
&lt;li&gt;When a control needs to be mandatory and auditable rather than a team preference.&lt;/li&gt;
&lt;li&gt;Not for anything you are unwilling to enforce. An unenforced policy is worse than none: it is a documented control failure.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="what-it-must-answer"&gt;What it must answer &lt;a href="#what-it-must-answer" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Who does this apply to, and what must they do?&lt;/li&gt;
&lt;li&gt;Who owns each rule, and how is compliance measured?&lt;/li&gt;
&lt;li&gt;What happens when someone cannot comply?&lt;/li&gt;
&lt;li&gt;When is it reviewed, and by whom?&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="template"&gt;Template &lt;a href="#template" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock "&gt;
 &lt;pre id="4a7153b" class="language-markdown "&gt;
 &lt;code&gt;# &amp;lt;Organisation&amp;gt; Information Security Policy

| Field | Value |
|---|---|
| Version / effective date | |
| Owner | |
| Approved by | |
| Review cycle | |
| Applies to | |

## 1. Purpose and scope
Who and what is covered, including contractors and third parties.

## 2. Roles and responsibilities
| Role | Responsibility |
|---|---|

## 3. Policy statements
Each statement: mandatory, testable, owned.

### 3.1 &amp;lt;Domain&amp;gt;
| ID | Statement | Owner | Evidence of compliance |
|---|---|---|---|

Domains to cover: access control, authentication, data classification and
handling, cryptography, secure development, change management, logging and
monitoring, vulnerability management, third parties, incident response,
business continuity, physical, acceptable use.

## 4. Exceptions
Request, approve, time-limit, review.

## 5. Non-compliance
Consequences, stated plainly.

## 6. Related documents
Standards and procedures that implement this policy.

## 7. Review history
| Version | Date | Change | Approver |
|---|---|---|---|&lt;/code&gt;
 &lt;/pre&gt;
 &lt;/div&gt;
&lt;h2 id="worked-example"&gt;Worked example &lt;a href="#worked-example" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock "&gt;
 &lt;pre id="b241dae" class="language-markdown "&gt;
 &lt;code&gt;# Information Security Policy (extract)

| Field | Value |
|---|---|
| Version / effective date | 4.1 / 2026-07-01 |
| Owner | CISO |
| Approved by | Executive Committee, 2026-06-24 |
| Review cycle | Annual, or on material change |
| Applies to | All employees, contractors and third parties with access to company systems or data |

## 3.1 Access control
| ID | Statement | Owner | Evidence |
|---|---|---|---|
| AC-01 | Access is granted on the principle of least privilege, based on a documented role | Head of IT | Bundle definitions in the provisioning service; quarterly access review records |
| AC-02 | Access outside a documented role requires approval by the individual&amp;#39;s line manager before it is granted | Head of IT | Audit log entries showing approver, timestamp and justification |
| AC-03 | Access is revoked within 24 hours of an individual&amp;#39;s leave date | Head of IT | Daily exception report; quarterly sampling by Internal Audit |
| AC-04 | Privileged accounts are individually attributable; shared administrative credentials are prohibited | Head of IT | Account inventory; no accounts of type &amp;#34;shared&amp;#34; |
| AC-05 | Access rights are reviewed at least quarterly by the system owner | System owners | Signed review records retained 3 years |

## 3.2 Authentication
| ID | Statement | Owner | Evidence |
|---|---|---|---|
| AU-01 | Multi-factor authentication is required for all remote access and all administrative access | Head of IT | Identity platform configuration report |
| AU-02 | Service credentials are stored in the approved secrets manager and rotated at least every 90 days | Platform lead | Secrets manager age report; alert on any credential over 90 days |
| AU-03 | Credentials must not appear in source code, configuration files, logs, or ticketing systems | Engineering leads | Secret scanning in CI; findings tracked to closure |

## 3.6 Logging and monitoring
| ID | Statement | Owner | Evidence |
|---|---|---|---|
| LM-01 | Security-relevant events are logged with actor, timestamp, action and outcome | System owners | Log schema review per system |
| LM-02 | Security logs are retained for at least 12 months and are tamper-evident | Platform lead | Retention configuration; append-only storage settings |
| LM-03 | Personal data must not be written to operational logs | Engineering leads | Log sampling each quarter; findings tracked |

## 4. Exceptions
Exceptions are requested through the risk register, approved by the CISO for
Medium risk and by the Executive Committee for High. Every exception is
time-limited to a maximum of 12 months, names a compensating control, and is
reviewed at expiry. An expired exception is a policy violation.

Current example: legacy ERP cannot revoke access within 24 hours (AC-03) and
runs a nightly batch, giving a worst case of 26 hours. Exception EX-2026-014,
approved by the CISO 2026-10-30, expires 2027-06-30, compensating control is
a daily exception report reviewed by People Operations.

## 5. Non-compliance
Deliberate circumvention is a disciplinary matter. Inability to comply is not:
raise an exception. Teams that raise exceptions are not penalised — hidden
non-compliance is the failure mode this policy is designed to prevent.

## 6. Related documents
Access Control Standard; Secure Development Standard; Cryptographic Standard;
Incident Response Procedure; Data Classification Standard. Standards may be
updated by their owner without Executive Committee approval, provided they do
not weaken a policy statement.&lt;/code&gt;
 &lt;/pre&gt;
 &lt;/div&gt;
&lt;h2 id="common-mistakes"&gt;Common mistakes &lt;a href="#common-mistakes" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Policy, standard and procedure in one document.&lt;/strong&gt; Then every implementation detail needs executive re-approval, so nothing gets updated.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Statements nobody can test.&lt;/strong&gt; &amp;ldquo;Systems shall be appropriately secured&amp;rdquo; cannot be audited and cannot be complied with. Every statement needs an evidence column.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No exception process.&lt;/strong&gt; Teams that cannot comply and cannot get an exception will simply not comply, invisibly.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rules without owners.&lt;/strong&gt; An unowned control is an unimplemented control, and the auditor will find it before you do.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Copied from a template without adaptation.&lt;/strong&gt; A policy referencing systems you do not have signals to an auditor that nothing here reflects reality.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="related-templates"&gt;Related templates &lt;a href="#related-templates" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a data-bs-delay="{&amp;#34;hide&amp;#34;:300,&amp;#34;show&amp;#34;:550}" data-bs-html="true" data-bs-title="&lt;a href='https://templates.metacog.co.kr/docs/security-compliance/risk-register/'&gt;&lt;p&gt;SECURITY &amp; COMPLIANCE&lt;/p&gt;</description></item><item><title>Risk Register</title><link>https://templates.metacog.co.kr/docs/security-compliance/risk-register/</link><pubDate>Sun, 23 Aug 2026 00:00:00 +0000</pubDate><guid>https://templates.metacog.co.kr/docs/security-compliance/risk-register/</guid><description>&lt;p&gt;A risk register differs from a project &lt;a data-bs-delay="{&amp;#34;hide&amp;#34;:300,&amp;#34;show&amp;#34;:550}" data-bs-html="true" data-bs-title="&lt;a href='https://templates.metacog.co.kr/docs/project-management/raid-log/'&gt;&lt;p&gt;PROJECT MANAGEMENT&lt;/p&gt;&lt;strong&gt;RAID Log&lt;/strong&gt;&lt;br&gt;One table for Risks, Assumptions, Issues and Dependencies — the project's short-term memory.&lt;/a&gt;" data-bs-toggle="tooltip" href="https://templates.metacog.co.kr/docs/project-management/raid-log/"&gt;RAID Log&lt;/a&gt; in lifespan and audience: these risks outlive projects, and the entries are decisions by named accountable people, not a team&amp;rsquo;s working notes. The register&amp;rsquo;s value comes entirely from being reviewed — an unreviewed register is a list of old opinions.&lt;/p&gt;
&lt;h2 id="when-to-use-it"&gt;When to use it &lt;a href="#when-to-use-it" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;As the standing record for security, privacy, operational and compliance risk.&lt;/li&gt;
&lt;li&gt;As the home for policy exceptions and accepted risks, with expiry dates.&lt;/li&gt;
&lt;li&gt;Wherever an auditor will ask &amp;ldquo;who accepted this, when, and on what basis?&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="what-it-must-answer"&gt;What it must answer &lt;a href="#what-it-must-answer" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;What is the risk, in cause-and-effect terms?&lt;/li&gt;
&lt;li&gt;What is the current exposure, after existing controls?&lt;/li&gt;
&lt;li&gt;What are we doing about it, by when, and who owns that?&lt;/li&gt;
&lt;li&gt;Who accepted the residual risk, and when is it re-examined?&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="template"&gt;Template &lt;a href="#template" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock "&gt;
 &lt;pre id="5cfa0dd" class="language-markdown "&gt;
 &lt;code&gt;# Risk Register: &amp;lt;Organisation or domain&amp;gt;

| Field | Value |
|---|---|
| Owner | |
| Review cycle | |
| Last reviewed | |

## Scoring
State the likelihood and impact scales, and the tolerance thresholds. Do not
assume they are obvious.

## Register
| ID | Risk (cause -&amp;gt; event -&amp;gt; consequence) | Category | Inherent L/I | Existing controls | Residual L/I | Treatment | Owner | Action / due | Accepted by | Review date | Status |
|---|---|---|---|---|---|---|---|---|---|---|---|

Treatment: mitigate, transfer, avoid, accept.

## Accepted risks and policy exceptions
| ID | Exception to | Compensating control | Accepted by | Expires |
|---|---|---|---|---|

## Movement since last review
New, escalated, de-escalated, closed.&lt;/code&gt;
 &lt;/pre&gt;
 &lt;/div&gt;
&lt;h2 id="worked-example"&gt;Worked example &lt;a href="#worked-example" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock "&gt;
 &lt;pre id="15b2e08" class="language-markdown "&gt;
 &lt;code&gt;# Risk Register: Identity and Access (extract)

Owner: CISO. Review cycle: quarterly, next 2027-01-20. Last reviewed 2026-10-21.

## Scoring
Likelihood: 1 rare (&amp;lt; once in 5 years), 2 unlikely, 3 possible (once a year),
4 likely (quarterly), 5 almost certain (monthly).
Impact: 1 negligible, 2 minor, 3 moderate (reportable internally), 4 major
(regulatory notification or &amp;gt; EUR 250k), 5 severe (material to the business).
Score = L x I. Tolerance: score &amp;gt;= 12 requires Executive Committee acceptance;
9–11 requires CISO acceptance; &amp;lt;= 8 may be accepted by the system owner.

## Register
| ID | Risk | Category | Inherent | Controls | Residual | Treatment | Owner | Action / due | Accepted by | Review | Status |
|---|---|---|---|---|---|---|---|---|---|---|---|
| R-2026-011 | Legacy ERP revokes access only on a nightly batch, so a dismissed employee retains ERP access for up to 26 hours, during which they could export customer data | Access | 3 x 4 = 12 | Daily exception report; ERP access is read-only for 90% of roles; termination-day physical and VPN revocation is immediate | 2 x 4 = 8 | Mitigate, then avoid | Head of IT | ERP replacement in FY2027 (BUD-2027-04); until then the exception report is reviewed by 09:00 daily | CISO (EX-2026-014) | 2027-06-30 | Open |
| R-2026-018 | Alert routing configuration can reference deleted destinations, so a security-relevant alert may never be delivered | Detection | 4 x 3 = 12 | CI check that every alert route resolves (added 2026-12-10); fallback route on every PagerDuty service | 2 x 3 = 6 | Mitigate | Platform lead | Complete. Quarterly verification added to the ops calendar | CISO | 2027-01-20 | Closed 2026-12-19 |
| R-2026-022 | Free-text justification fields let a user enter personal or special-category data that then falls under a 7-year audit retention with no erasure path | Privacy | 3 x 3 = 9 | UI warning; field excluded from log export; DPIA documents the retention basis | 2 x 3 = 6 | Accept | DPO | Quarterly sampling of 50 justification entries for sensitive content | DPO | 2027-01-20 | Open |
| R-2026-027 | A single-leader poller with no liveness signal can stall silently, delaying provisioning and (in a leaver window) delaying revocation beyond policy | Availability / Access | 3 x 3 = 9 | Heartbeat alert (OPS-882); hourly synthetic provisioning check (OPS-885); backlog alert | 2 x 3 = 6 | Mitigate | Platform lead | OPS-885 due 2027-01-16 | CISO | 2027-01-20 | Open, on track |
| R-2026-031 | Growth in direct third-party dependencies raises the chance of a compromised package reaching production | Supply chain | 4 x 4 = 16 | Dependency scanning gating CI on High/Critical; new dependencies require maintainer approval; lockfiles pinned | 3 x 4 = 12 | Mitigate | Engineering director | Build provenance attestation and artefact signing, due 2027-03-31 | Executive Committee | 2027-01-20 | Open, above tolerance |

## Accepted risks and policy exceptions
| ID | Exception to | Compensating control | Accepted by | Expires |
|---|---|---|---|---|
| EX-2026-014 | AC-03 (revocation within 24h) for the legacy ERP | Daily exception report reviewed by People Ops by 09:00 | CISO | 2027-06-30 |
| EX-2026-019 | LM-03 (no personal data in operational logs) for the legacy ERP&amp;#39;s own logs, which we do not control | Log access restricted to 4 named administrators; 30-day retention | CISO | 2027-06-30 |

## Movement since last review
- New: R-2026-031 (supply chain) raised after an industry incident; above
 tolerance and therefore accepted at Executive Committee, not by the CISO.
- De-escalated: R-2026-018 residual from 12 to 6 after the CI check landed;
 closed on verification.
- Unchanged: R-2026-011. The FY2027 budget line is approved but the project has
 not started; if it slips past Q3 the exception must be re-approved rather
 than extended silently.&lt;/code&gt;
 &lt;/pre&gt;
 &lt;/div&gt;
&lt;h2 id="common-mistakes"&gt;Common mistakes &lt;a href="#common-mistakes" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;No scoring scale.&lt;/strong&gt; &amp;ldquo;High&amp;rdquo; means different things to different people, and scores stop being comparable across entries.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Risks as one-word topics.&lt;/strong&gt; &amp;ldquo;Supply chain&amp;rdquo; is a category. The cause-event-consequence sentence is what makes exposure assessable.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Inherent score only.&lt;/strong&gt; What matters for a decision is the residual risk after existing controls — and stating both shows what the controls are actually buying.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Acceptance by the wrong level.&lt;/strong&gt; A risk above tolerance accepted by a team lead is an audit finding waiting to happen. Match the acceptor to the score.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Exceptions that get extended rather than re-approved.&lt;/strong&gt; Silent extension is how a temporary compensating control becomes permanent and unexamined.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reviewed annually.&lt;/strong&gt; Anything reviewed less often than quarterly drifts out of date and stops informing decisions.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="related-templates"&gt;Related templates &lt;a href="#related-templates" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a data-bs-delay="{&amp;#34;hide&amp;#34;:300,&amp;#34;show&amp;#34;:550}" data-bs-html="true" data-bs-title="&lt;a href='https://templates.metacog.co.kr/docs/security-compliance/information-security-policy/'&gt;&lt;p&gt;SECURITY &amp; COMPLIANCE&lt;/p&gt;</description></item><item><title>Access Review</title><link>https://templates.metacog.co.kr/docs/security-compliance/access-review/</link><pubDate>Sun, 23 Aug 2026 00:00:00 +0000</pubDate><guid>https://templates.metacog.co.kr/docs/security-compliance/access-review/</guid><description>&lt;p&gt;An access review is a control that fails quietly. Reviewers approve everything to clear the queue, and the record looks identical to a review that found nothing. The template&amp;rsquo;s job is to make genuine review visible: exceptions found, revocations made, and how long they took.&lt;/p&gt;
&lt;h2 id="when-to-use-it"&gt;When to use it &lt;a href="#when-to-use-it" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Quarterly for privileged access and systems in scope for certification; annually for lower-risk systems.&lt;/li&gt;
&lt;li&gt;On organisational change — a reorganisation or an acquisition invalidates role assumptions wholesale.&lt;/li&gt;
&lt;li&gt;After any incident involving inappropriate access.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="what-it-must-answer"&gt;What it must answer &lt;a href="#what-it-must-answer" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;What was reviewed, over what population, as of what date?&lt;/li&gt;
&lt;li&gt;Who reviewed it, and were they the right person to judge?&lt;/li&gt;
&lt;li&gt;What was found, and what happened as a result?&lt;/li&gt;
&lt;li&gt;What could not be reviewed, and why?&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="template"&gt;Template &lt;a href="#template" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock "&gt;
 &lt;pre id="3864934" class="language-markdown "&gt;
 &lt;code&gt;# Access Review: &amp;lt;System or scope&amp;gt; — &amp;lt;period&amp;gt;

| Field | Value |
|---|---|
| Scope | |
| Population as at | date and how the snapshot was taken |
| Review period | |
| Coordinator | |
| Reviewers | |
| Policy reference | |

## 1. Population
| Category | Count |
|---|---|
| Total accounts | |
| Privileged | |
| Service accounts | |
| External / third party | |
| Dormant (&amp;gt; 90 days) | |

## 2. Method
How reviewers were given the data, what they were asked, and how long they had.

## 3. Results
| Reviewer | Accounts | Certified | Revoked | Modified | No response |
|---|---|---|---|---|---|

## 4. Findings
| # | Finding | Accounts affected | Action | Owner | Due | Status |
|---|---|---|---|---|---|---|

## 5. Revocations performed
| Account | Access removed | Reason | Date | Verified by |
|---|---|---|---|---|

## 6. Exclusions
What was not reviewed, and why.

## 7. Comparison with the previous review
Trend, and whether previous findings recurred.

## 8. Attestation
| Name | Role | Statement | Date |
|---|---|---|---|&lt;/code&gt;
 &lt;/pre&gt;
 &lt;/div&gt;
&lt;h2 id="worked-example"&gt;Worked example &lt;a href="#worked-example" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock "&gt;
 &lt;pre id="22e0d2d" class="language-markdown "&gt;
 &lt;code&gt;# Access Review: Provisioning-managed systems — Q4 2026

| Field | Value |
|---|---|
| Scope | 11 systems provisioned through the Access Provisioning Service |
| Population as at | 2026-12-01, exported by `provctl audit entitlements --as-of 2026-12-01` |
| Review period | 2026-12-01 to 2026-12-19 |
| Coordinator | T. Blomqvist (People Operations) |
| Policy reference | AC-05 |

## 1. Population
| Category | Count |
|---|---|
| Total accounts | 4,118 |
| Total entitlements | 37,402 |
| Privileged | 214 |
| Service accounts | 63 |
| External / third party | 89 |
| Dormant (&amp;gt; 90 days, no authentication) | 147 |

## 2. Method
Each system owner received a list of their system&amp;#39;s entitlement holders with
job title, department, manager, grant date, the bundle that granted it, and
last authentication date. Reviewers were asked to mark each as certify, revoke
or modify, with a reason required for anything other than certify. Ten working
days were allowed, with reminders on days 5 and 8. Privileged and dormant
accounts were listed first so that queue fatigue hit the lowest-risk entries.

## 3. Results
| Reviewer | Accounts | Certified | Revoked | Modified | No response |
|---|---|---|---|---|---|
| Platform (A. Vogel) | 640 | 601 | 31 | 8 | 0 |
| Finance systems (M. Duarte) | 812 | 780 | 22 | 10 | 0 |
| ERP (external supplier) | 1,204 | 1,204 | 0 | 0 | 0 |
| Collaboration (D. Achebe) | 1,462 | 1,401 | 54 | 7 | 0 |

The ERP result — 1,204 of 1,204 certified with zero exceptions in under two
hours — is not credible and is treated as a review failure, not a clean result.
See finding 3.

## 4. Findings
| # | Finding | Accounts | Action | Owner | Due | Status |
|---|---|---|---|---|---|---|
| 1 | 147 accounts had not authenticated in over 90 days, including 12 privileged | 147 | Disable after manager confirmation; delete after 30 days | T. Blomqvist | 2027-01-15 | 89 disabled, 58 confirmed still needed (seasonal roles) |
| 2 | 19 employees retained entitlements from a previous role after an internal move | 19 | Revoked; mover flow investigated | A. Vogel | 2026-12-19 | Closed — the mover flow only removes bundle entitlements, not manually added ones. Defect DEF-2026-0361 raised |
| 3 | ERP review completed in 1h 50m with no exceptions across 1,204 accounts | 1,204 | Review rejected; re-run with the supplier&amp;#39;s named security officer and a sampled verification by Internal Audit | L. Haddad | 2027-01-31 | Open |
| 4 | 8 service accounts had no named human owner | 8 | Owner assigned or account removed | A. Vogel | 2027-01-15 | 5 assigned, 3 removed |
| 5 | 4 third-party accounts belonged to individuals whose contract ended | 4 | Revoked same day; supplier notified | T. Blomqvist | 2026-12-08 | Closed |

## 6. Exclusions
Two systems (the archived reporting warehouse and the decommissioned intranet)
were excluded: both are read-only, offline, and scheduled for deletion in
Q1 2027. Excluded with CISO approval; if deletion slips past 2027-03-31 they
re-enter scope.

## 7. Comparison with the previous review
| Metric | Q3 2026 | Q4 2026 |
|---|---|---|
| Entitlements revoked | 78 | 107 |
| Dormant accounts | 203 | 147 |
| Findings repeated from the previous review | — | 1 (the ERP rubber-stamp, also seen in Q3) |

Dormant accounts are down 28% following the automated leaver flow. The residual
entitlements from internal moves (finding 2) are new — the mover flow was not
live during the Q3 review.

## 8. Attestation
| Name | Role | Statement | Date |
|---|---|---|---|
| A. Vogel | Platform system owner | I have reviewed all entitlements for my systems and certify the remaining access is appropriate | 2026-12-16 |
| M. Duarte | Finance system owner | As above | 2026-12-17 |
| D. Achebe | Collaboration system owner | As above | 2026-12-18 |
| L. Haddad | Internal Audit | The review was performed as documented, except for the ERP scope, which is rejected and being re-run | 2026-12-19 |&lt;/code&gt;
 &lt;/pre&gt;
 &lt;/div&gt;
&lt;h2 id="common-mistakes"&gt;Common mistakes &lt;a href="#common-mistakes" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;100% certification treated as a good result.&lt;/strong&gt; Across a large population it means nobody looked. Track review duration and exception rate as quality signals, and challenge outliers.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reviewers who cannot judge.&lt;/strong&gt; A manager three levels up does not know whether an engineer needs a specific database role. Route to whoever knows the work.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Access lists without context.&lt;/strong&gt; Certifying a list of usernames is impossible. Job title, department, grant reason and last-authentication date make it a real decision.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Findings without revocation evidence.&lt;/strong&gt; &amp;ldquo;Should be revoked&amp;rdquo; is not a control; the revocation date and who verified it is.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No comparison with the previous review.&lt;/strong&gt; Repeat findings are the strongest signal that the underlying process, not the access, is what needs fixing.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="related-templates"&gt;Related templates &lt;a href="#related-templates" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a data-bs-delay="{&amp;#34;hide&amp;#34;:300,&amp;#34;show&amp;#34;:550}" data-bs-html="true" data-bs-title="&lt;a href='https://templates.metacog.co.kr/docs/security-compliance/information-security-policy/'&gt;&lt;p&gt;SECURITY &amp; COMPLIANCE&lt;/p&gt;</description></item><item><title>Vendor Security Assessment</title><link>https://templates.metacog.co.kr/docs/security-compliance/vendor-security-assessment/</link><pubDate>Sun, 23 Aug 2026 00:00:00 +0000</pubDate><guid>https://templates.metacog.co.kr/docs/security-compliance/vendor-security-assessment/</guid><description>&lt;p&gt;Vendor assessment goes wrong in two directions: a 300-question form sent to a vendor selling a static website, or a rubber stamp for one processing customer records. Tier the assessment by data and access, and spend the effort where the exposure is.&lt;/p&gt;
&lt;h2 id="when-to-use-it"&gt;When to use it &lt;a href="#when-to-use-it" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Before contracting any supplier that will hold company or customer data, connect to internal systems, or provide a service whose failure would be an incident.&lt;/li&gt;
&lt;li&gt;On renewal, and whenever the vendor&amp;rsquo;s scope changes materially.&lt;/li&gt;
&lt;li&gt;After a publicly disclosed breach at the vendor.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="what-it-must-answer"&gt;What it must answer &lt;a href="#what-it-must-answer" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;What data and access will this vendor have, and what happens if they are breached?&lt;/li&gt;
&lt;li&gt;What assurance do they provide, and what did we actually verify rather than accept?&lt;/li&gt;
&lt;li&gt;What do we require contractually?&lt;/li&gt;
&lt;li&gt;What residual risk are we accepting, and who accepted it?&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="template"&gt;Template &lt;a href="#template" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock "&gt;
 &lt;pre id="080bf9c" class="language-markdown "&gt;
 &lt;code&gt;# Vendor Security Assessment: &amp;lt;Vendor&amp;gt; — &amp;lt;service&amp;gt;

| Field | Value |
|---|---|
| Assessment date | |
| Assessor | |
| Business owner | |
| Tier | 1 (critical) / 2 / 3 (low) |
| Decision | Approve / Approve with conditions / Reject |

## 1. Service description
What they do for us, and what we could not do without them.

## 2. Data and access scope
| Data category | Volume | Classification | Personal data? | Purpose |
|---|---|---|---|---|

| Access granted | Type | Justification |
|---|---|---|

## 3. Tiering
The criteria that put this vendor in its tier.

## 4. Assurance reviewed
| Evidence | Provided? | Date | Reviewed by | Notes |
|---|---|---|---|---|

## 5. Control assessment
| Domain | Finding | Rating | Evidence |
|---|---|---|---|

## 6. Concentration and exit
Dependency, lock-in, exit plan, data return and deletion.

## 7. Contractual requirements
| Requirement | In contract? | Clause |
|---|---|---|

## 8. Findings and conditions
| # | Finding | Severity | Required action | Owner | Due |
|---|---|---|---|---|---|

## 9. Residual risk and decision
| Risk | Rating | Accepted by | Date | Review date |
|---|---|---|---|---|&lt;/code&gt;
 &lt;/pre&gt;
 &lt;/div&gt;
&lt;h2 id="worked-example"&gt;Worked example &lt;a href="#worked-example" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock "&gt;
 &lt;pre id="98e98c7" class="language-markdown "&gt;
 &lt;code&gt;# Vendor Security Assessment: NorthPay — card payment processing

| Field | Value |
|---|---|
| Assessment date | 2026-04-28 |
| Assessor | A. Berg (Security) |
| Business owner | M. Duarte (Finance) |
| Tier | 1 — critical |
| Decision | Approve with conditions |

## 1. Service description
Processes all card payments for web and mobile. An outage stops revenue
immediately; a breach exposes cardholder data and triggers regulatory
notification. There is no manual fallback.

## 2. Data and access scope
| Data category | Volume | Classification | Personal data? | Purpose |
|---|---|---|---|---|
| Cardholder data (PAN, expiry) | ~2.1M transactions/yr | Restricted | Yes | Payment authorisation |
| Customer name and billing address | ~2.1M/yr | Confidential | Yes | Fraud screening, AVS |
| Transaction metadata | ~2.1M/yr | Internal | Indirectly | Reconciliation |

Access granted: outbound API calls from our systems to theirs; a webhook
endpoint they call, restricted by mutual TLS and IP allow-list; no access to
our internal networks or data stores.

## 3. Tiering
Tier 1 on three independent criteria: processes restricted data at scale,
outage is immediately revenue-affecting, and there is no rapid alternative
provider.

## 4. Assurance reviewed
| Evidence | Provided? | Date | Reviewed by | Notes |
|---|---|---|---|---|
| PCI DSS Attestation of Compliance (Level 1) | Yes | 2026-02-14 | A. Berg | Valid; scope covers the services we use. Verified against the card scheme&amp;#39;s public registry rather than accepting the PDF |
| SOC 2 Type II | Yes | 2026-01-31 | A. Berg | Two exceptions noted by the auditor: delayed access revocation and one incomplete change record. Both remediated per management response |
| Penetration test summary | Yes | 2025-11 | A. Berg | Summary only, no findings detail. Requested full report — refused; standard for this vendor |
| ISO 27001 certificate | Yes | 2026-03 | A. Berg | Verified with the certification body |
| Business continuity plan | Partial | 2026-04 | A. Berg | Summary only. RTO stated as 4 hours; last exercise date not disclosed |
| Sub-processor list | Yes | 2026-04 | DPO | 7 sub-processors, 2 outside the EEA with standard contractual clauses in place |

## 5. Control assessment
| Domain | Finding | Rating | Evidence |
|---|---|---|---|
| Access control | MFA enforced; privileged access reviewed quarterly | Satisfactory | SOC 2 |
| Encryption | TLS 1.2&amp;#43; in transit, AES-256 at rest, HSM-backed keys | Satisfactory | PCI AoC |
| Incident response | 24/7 team; contractual notification within 24h of confirmed breach | Satisfactory | Contract &amp;#43; SOC 2 |
| Change management | One incomplete change record in the SOC 2 period | Minor concern | SOC 2 exception 2 |
| Business continuity | RTO 4h claimed; no exercise evidence provided | Concern | Gap |
| Sub-processor management | Notification of new sub-processors, but only 30 days&amp;#39; notice with no right to object | Concern | Contract review |

## 6. Concentration and exit
Single provider for all card traffic. Exit would take an estimated 6–9 months
based on the incoming migration, which is itself a 9-month project. Contract
requires data return in a documented format within 30 days of termination and
deletion within 90, with certification of deletion. Mitigation: we retain our
own transaction ledger independently, so exit does not depend on their export.

## 7. Contractual requirements
| Requirement | In contract? | Clause |
|---|---|---|
| Breach notification within 24h | Yes | 11.3 |
| Right to audit or receive annual SOC 2 | Yes (report, not audit right) | 12.1 |
| Sub-processor notification | Yes, 30 days | 8.4 |
| Right to object to a sub-processor | No | — |
| Data return and certified deletion | Yes | 15.2 |
| Liability cap | 12 months&amp;#39; fees | 18.1 — below our EUR 5M standard for Tier 1 |

## 8. Findings and conditions
| # | Finding | Severity | Required action | Owner | Due |
|---|---|---|---|---|---|
| 1 | No right to object to new sub-processors | Medium | Negotiate an objection right with termination for cause | M. Duarte | Before signature |
| 2 | Liability cap below policy for Tier 1 | Medium | Escalate to Legal; accept or negotiate | M. Duarte | Before signature |
| 3 | No BCP exercise evidence | Medium | Request the most recent exercise report annually; treat non-provision as a finding at renewal | A. Berg | Annually |
| 4 | Pen test detail not disclosed | Low | Accept — consistent with the market; the PCI AoC provides independent coverage | A. Berg | — |

## 9. Residual risk and decision
| Risk | Rating | Accepted by | Date | Review date |
|---|---|---|---|---|
| Concentration: no rapid alternative provider | High | Executive Committee | 2026-05-06 | 2027-05 |
| Liability cap below policy | Medium | CFO | 2026-05-06 | At renewal |
| Unverified BCP capability | Medium | CISO | 2026-05-06 | 2027-04 |

Approved with conditions 1 and 2 resolved before signature. Condition 1 was
agreed by the vendor on 2026-05-02 (60 days&amp;#39; notice with an objection right);
condition 2 was accepted as-is by the CFO, with the concentration risk recorded
in the register as R-2026-008.&lt;/code&gt;
 &lt;/pre&gt;
 &lt;/div&gt;
&lt;h2 id="common-mistakes"&gt;Common mistakes &lt;a href="#common-mistakes" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;The same questionnaire for every vendor.&lt;/strong&gt; Tier by data and access. Effort spent on a low-tier vendor is effort not spent on the one holding cardholder data.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Accepting certificates without verification.&lt;/strong&gt; A PDF is not evidence. Check the certification body&amp;rsquo;s or scheme&amp;rsquo;s registry, and check that the scope covers the service you are buying.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ignoring the auditor&amp;rsquo;s exceptions in a SOC 2.&lt;/strong&gt; The exceptions section is the most informative part of the report and is routinely skipped.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No exit assessment.&lt;/strong&gt; Concentration risk is usually the largest exposure, and it is invisible if you only assess controls.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Findings without contract dates.&lt;/strong&gt; A finding that is not resolved before signature will not be resolved after it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Assessed once, never again.&lt;/strong&gt; Vendors change scope, get acquired and get breached. Reassess at renewal and on material change.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="related-templates"&gt;Related templates &lt;a href="#related-templates" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a data-bs-delay="{&amp;#34;hide&amp;#34;:300,&amp;#34;show&amp;#34;:550}" data-bs-html="true" data-bs-title="&lt;a href='https://templates.metacog.co.kr/docs/security-compliance/risk-register/'&gt;&lt;p&gt;SECURITY &amp; COMPLIANCE&lt;/p&gt;</description></item><item><title>Data Protection Impact Assessment</title><link>https://templates.metacog.co.kr/docs/security-compliance/data-protection-impact-assessment/</link><pubDate>Sun, 23 Aug 2026 00:00:00 +0000</pubDate><guid>https://templates.metacog.co.kr/docs/security-compliance/data-protection-impact-assessment/</guid><description>&lt;p&gt;A DPIA is required under the GDPR (Article 35) where processing is likely to result in a high risk to individuals, and equivalent obligations exist in other regimes. Done at the right time it is a design tool: it forces the necessity and proportionality questions while the design can still change.&lt;/p&gt;
&lt;h2 id="when-to-use-it"&gt;When to use it &lt;a href="#when-to-use-it" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Systematic and extensive automated evaluation of people, including profiling with legal or similarly significant effects.&lt;/li&gt;
&lt;li&gt;Large-scale processing of special-category data, or systematic monitoring of a publicly accessible area.&lt;/li&gt;
&lt;li&gt;New technologies, or any processing your supervisory authority lists as requiring one.&lt;/li&gt;
&lt;li&gt;When in doubt, do a short screening assessment and record why a full DPIA was or was not required.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="what-it-must-answer"&gt;What it must answer &lt;a href="#what-it-must-answer" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;What processing, of whose data, for what purpose, on what lawful basis?&lt;/li&gt;
&lt;li&gt;Is it necessary and proportionate — could the purpose be achieved with less data?&lt;/li&gt;
&lt;li&gt;What are the risks to individuals, not to the organisation?&lt;/li&gt;
&lt;li&gt;What measures reduce those risks, and what remains?&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="template"&gt;Template &lt;a href="#template" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock "&gt;
 &lt;pre id="4576bac" class="language-markdown "&gt;
 &lt;code&gt;# DPIA: &amp;lt;Processing activity&amp;gt;

| Field | Value |
|---|---|
| Version / date | |
| Controller | |
| DPO consulted | date |
| Status | Draft / Approved / Under review |
| Review date | |

## 1. Screening
Why a DPIA is required (or why not, if this is a screening record).

## 2. Description of processing
Nature, scope, context and purposes. Data flows, including transfers.

| Data category | Subjects | Volume | Source | Retention | Special category? |
|---|---|---|---|---|---|

Recipients, sub-processors, transfers outside the jurisdiction.

## 3. Lawful basis
Per purpose. For legitimate interests, include the balancing test.

## 4. Necessity and proportionality
Could the purpose be met with less data, less granularity, or shorter
retention? Answer honestly, per data category.

## 5. Consultation
Who was consulted — DPO, data subjects or their representatives, processors —
and what they said.

## 6. Risks to individuals
| # | Risk to the individual | Likelihood | Severity | Overall |
|---|---|---|---|---|

## 7. Measures
| Risk | Measure | Effect | Residual | Owner |
|---|---|---|---|---|

## 8. Data subject rights
How access, rectification, erasure, restriction, portability and objection are
handled — including where a right is limited and why.

## 9. Outcome
Sign-off, residual risk accepted, whether prior consultation with the
supervisory authority is required.&lt;/code&gt;
 &lt;/pre&gt;
 &lt;/div&gt;
&lt;h2 id="worked-example"&gt;Worked example &lt;a href="#worked-example" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock "&gt;
 &lt;pre id="95fd927" class="language-markdown "&gt;
 &lt;code&gt;# DPIA: Automated access provisioning and deprovisioning

| Field | Value |
|---|---|
| Version / date | 1.3 / 2026-09-22 |
| Controller | Example Group GmbH |
| DPO consulted | 2026-05-14, 2026-08-30 |
| Status | Approved |
| Review date | 2027-09-22, or on material change |

## 1. Screening
The processing concerns employees, is systematic, and determines access to
systems required to perform their job. It is not automated decision-making with
legal effect under Article 22 — no employment decision is made — but it is
systematic monitoring-adjacent processing of employee data at organisational
scale, and the works council requested a full assessment. A DPIA was therefore
completed.

## 2. Description of processing
Employee records flow from the HR system into a local projection, which drives
the creation and revocation of system access. Grants, revocations and approvals
are recorded in an append-only audit log.

| Data category | Subjects | Volume | Source | Retention | Special category? |
|---|---|---|---|---|---|
| Name, employee ID | Employees, ~4,100 | 4,100 | HR system | 90 days after leave date | No |
| Job code, department, manager ID | Employees | 4,100 | HR system | 90 days after leave date | No |
| Start and leave dates | Employees | 4,100 | HR system | 90 days after leave date | No |
| Entitlement grants and revocations | Employees | ~9,000/yr | Generated | 7 years | No |
| Approval justification (free text) | Employees &amp;#43; approving managers | ~800/yr | Manager input | 7 years | Potentially — free text |
| Last authentication timestamp | Employees | 4,100 | Target systems | 12 months | No |

Recipients: eleven internal target systems; Internal Audit (read-only export).
No transfers outside the EEA. One processor: the cloud infrastructure provider,
under an existing data processing agreement.

## 3. Lawful basis
- Provisioning and revocation: legitimate interests (Art. 6(1)(f)) — securing
 systems and enabling employees to work. Balancing test in section 4.
- Audit log retention for 7 years: legal obligation (Art. 6(1)(c)) under
 financial-reporting record-keeping requirements, and legitimate interests for
 the remainder.
- Last authentication timestamp: legitimate interests, for detecting dormant
 accounts. Explicitly *not* used for performance management, and this
 limitation is stated in the works council agreement and enforced by
 restricting the field to the access review export.

## 4. Necessity and proportionality
- **Could we use less data?** The projection holds only fields needed to resolve
 a bundle and route an approval. Salary, contract type, absence and
 performance data were available in the HR feed and are deliberately not
 ingested. The feed is filtered at the source, not after ingestion.
- **Could retention be shorter?** The 90-day operational retention is set by the
 need to investigate provisioning disputes. The 7-year audit retention follows
 the statutory record-keeping period; shorter would not satisfy the audit
 finding that prompted the system.
- **Is the free-text justification necessary?** Yes — an approval without a
 reason does not satisfy the control. But it is the highest-risk field, since
 a manager could type anything. Mitigated in section 7.
- **Is the last-authentication timestamp proportionate?** It is the only
 practical way to find dormant accounts. Its use is contractually and
 technically limited to that purpose.

## 5. Consultation
DPO consulted twice; requested the free-text mitigation and the explicit
purpose limitation on the authentication timestamp, both adopted. The works
council was consulted over six weeks (2026-05-20 to 2026-07-01) and agreed,
conditional on the timestamp not being available to line managers and on
employees receiving a written explanation of the processing. Both conditions
are implemented.

## 6. Risks to individuals
| # | Risk to the individual | Likelihood | Severity | Overall |
|---|---|---|---|---|
| 1 | A manager records sensitive information (health, union membership) in a justification field, which is then retained 7 years with no erasure path | Possible | High | High |
| 2 | An employee is denied access they need because of an HR data error, and cannot get it corrected quickly | Possible | Medium | Medium |
| 3 | The authentication timestamp is repurposed for performance monitoring | Unlikely | High | Medium |
| 4 | Excess personal data reaches lower environments through a test data copy | Unlikely | High | Medium |
| 5 | An individual cannot find out what access they hold or why | Possible | Low | Low |

## 7. Measures
| Risk | Measure | Effect | Residual | Owner |
|---|---|---|---|---|
| 1 | Field labelled with a warning; guidance in manager training; excluded from operational logs and from the audit export sent to third parties; quarterly sampling of 50 entries by the DPO with deletion of any sensitive content found | Reduced, not eliminated — the field is free text by necessity | Low–Medium, accepted, reviewed quarterly | DPO |
| 2 | Errors are corrected in the HR system, which propagates within 5 minutes; People Ops can apply access immediately while the correction flows through; the process is documented in the employee-facing explanation | Reduced | Low | People Ops |
| 3 | Field exposed only in the access review export; not in any manager-facing view; works council agreement records the purpose limitation; access to the export is logged | Reduced | Low | Platform |
| 4 | Only anonymised copies reach lower environments; the anonymisation script is itself tested (TC-240) and a refresh is blocked if that test fails | Reduced | Low | QA |
| 5 | Self-service page showing an employee their current entitlements, the bundle that granted each, and the date | Reduced | Low | Platform |

## 8. Data subject rights
- **Access:** the self-service page covers current entitlements; a full audit
 history is available on request through the DPO.
- **Rectification:** flows from the HR system; the provisioning service is never
 edited directly, so there is one place to correct.
- **Erasure:** operational data is deleted 90 days after the leave date. Audit
 records are retained for 7 years on a legal-obligation basis, and erasure is
 refused for that period — this refusal is explained in the employee-facing
 notice rather than left to be discovered on request.
- **Objection:** legitimate-interests processing carries a right to object; an
 objection would in practice mean no system access, so it is handled as an
 HR conversation, not a technical setting.

## 9. Outcome
Residual risk is Low, except risk 1 at Low–Medium, accepted by the DPO on
2026-09-22 with quarterly sampling. Prior consultation with the supervisory
authority is not required, as no high residual risk remains after measures.
Review on material change or by 2027-09-22.&lt;/code&gt;
 &lt;/pre&gt;
 &lt;/div&gt;
&lt;h2 id="common-mistakes"&gt;Common mistakes &lt;a href="#common-mistakes" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Written after the system is built.&lt;/strong&gt; A DPIA is a design input. Afterwards it can only document risk, not reduce it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Risks to the organisation instead of to individuals.&lt;/strong&gt; &amp;ldquo;Reputational damage&amp;rdquo; is not the subject of a DPIA. What happens to the person is.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Necessity treated as a formality.&lt;/strong&gt; The question &amp;ldquo;could we do this with less data?&amp;rdquo; is the one that most often improves the design — the filtered HR feed above is a direct result of asking it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Free-text fields not analysed.&lt;/strong&gt; They are the most common route for special-category data to enter a system that was designed not to hold any.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No review date.&lt;/strong&gt; Processing evolves; a DPIA describing a system from two years ago provides no protection.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Measures without owners.&lt;/strong&gt; An unowned measure is not implemented, and the assessment overstates how safe the processing is.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="related-templates"&gt;Related templates &lt;a href="#related-templates" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a data-bs-delay="{&amp;#34;hide&amp;#34;:300,&amp;#34;show&amp;#34;:550}" data-bs-html="true" data-bs-title="&lt;a href='https://templates.metacog.co.kr/docs/architecture-design/data-model-document/'&gt;&lt;p&gt;ARCHITECTURE &amp; DESIGN&lt;/p&gt;</description></item></channel></rss>