11 تمرین ۱ — حسابرسیِ پروکسیExercise 1 — proxy audit
بازگشت به صورت تمرینBack to the exercise · ارزیابی و سطحAssessment and level
پاسخ ۶۰ثانیهایThe 60-second answer
صورت مسئله و فرضهاProblem and assumptions
- جمعیت SYNTHETIC با بذر ثابت ۱۴ و ۲۰۰۰ نفر: همبستگی پروکسیها فرض ورودی است، نه یافته.
- مدل فقط zone و device را میبیند؛ ستون گروه را هیچوقت نخوانده.
- همه عددها آموزشیاند؛ هیچ ادعایی درباره جمعیت، وامدهنده یا مدل واقعی نیست.
- A SYNTHETIC population (seed 14, n=2000): proxy correlation is an input assumption, not a finding.
- The model sees only zone and device; it never read the group column.
- All numbers are teaching numbers; no claim about any real population, lender, or model.
چرا این روش و این عددها؟Why this method and these numbers?
دادهٔ مصنوعی correlation را از پیش میسازد؛ بنابراین اختلاف نتیجه نشان میدهد مدل میتواند proxy را یاد بگیرد، نه اینکه چنین تبعیضی در جامعه اندازهگیری شده است. حذف ستون گروه کافی نیست چون zone/device میتوانند اطلاعات آن را حمل کنند. نرخ انتخاب هر گروه را بر شمار همان گروه تقسیم میکنیم تا تفاوت اندازهٔ گروهها نتیجه را منحرف نکند؛ هیچ metric واحدی بهتنهایی حکم عادلانهبودن نمیدهد.
Synthetic data builds correlation into the inputs, demonstrating proxy learning rather than measuring real discrimination. Removing group labels is insufficient when zone/device carry correlated information. Divide selections by each group’s population to avoid group-size distortion. No single metric establishes fairness by itself.
مدل ذهنیMental model
حل گامبهگامStep by step
- همبستگی را بسنج، نیت را نه برای هر پروکسی P(proxy|group) را حساب کن: zone=high با ۰٫۷۵۶ در برابر ۰٫۲۴۵ عملاً برچسب گروه است. همبستگی بالا یعنی قابلیت بازسازی، نه proof تبعیض عمدی.
- ستون را حذف و دوباره اجرا کن پروکسیها بهتنهایی ۰٫۷۵۶ در برابر ۰٫۲۴۵ قبول میکنند — شکاف ۰٫۵۱۱ — با ستونی که هیچوقت خوانده نشد. این همان بازسازی است و دمو دقیقاً همین را چاپ میکند.
- عدالت عملیاتی، قیمت، اعتراض یک تعریف عملیاتی انتخاب کن (مثلاً برابری نرخ پذیرش)، اثرش روی دقت را بسنج و بپذیر هیچ معیاری بهتنهایی کافی نیست؛ وامهای ردشده برچسب نتیجه ندارند، پس پایش انسانی و مسیر اعتراض واقعی نگه دار.
- Measure correlation, not intent Per proxy compute P(proxy|group): zone=high at 0.756 vs 0.245 is effectively the group label. High correlation means reconstructability, not proof of deliberate discrimination.
- Delete the column and rerun Proxies alone accept at 0.756 vs 0.245 — gap 0.511 — with a column never read. That is the reconstruction, and the demo prints exactly this.
- Operational fairness, price, appeal Pick one operational definition (e.g. acceptance-rate parity), measure its accuracy cost, and admit no single metric suffices; rejected loans carry no outcome label, so keep human monitoring and a real appeal path.
مثال محاسبهشدهWorked example
داده مصنوعی (بذر ۱۴، ۲۰۰۰ نفر): P(zone=high|A)=0.756 در برابر P(zone=high|B)=0.245؛ پذیرش ۰٫۷۵۶ در برابر ۰٫۲۴۵ و شکاف ۰٫۵۱۱. تفسیر: شکاف با حذف ستون نرفت، پس پروکسیها بازسازیاش کردند. واحد: نرخ (بدون واحد). این عددها فقط مال همین جمعیت مصنوعیاند.
Synthetic data (seed 14, 2000 people): P(zone=high|A)=0.756 vs P(zone=high|B)=0.245; acceptance 0.756 vs 0.245, gap 0.511. Reading: the gap survived the deleted column, so the proxies rebuilt it. Units: rates (unitless). These numbers belong to this synthetic population only.
دانلود SVG مستقلDownload standalone SVG
- پنل اول: ستون گروه قفل است — قبل از آموزش حذف شده و هیچوقت خوانده نشده. برچسب اینجا رفته و وسوسه تمامشده دانستن هم.
- پنل دوم: دو پروکسی خواندهشده — کدپستی با ۰٫۷۵۶ در برابر ۰٫۲۴۵ عملاً خود گروه است؛ مدل دستگاه هم همبسته است. بهتنهایی بیگناه و کنار هم بازسازی تمیز.
- پنل سوم: مدل opaque از همان دو ورودی نمره میدهد و شکاف ۰٫۵۱۱ بیرون میآید — بدون هیچ کد دلیلی. حسابرس فقط ورودی و خروجی را میبیند.
- جدول پایین: چهار عدد واقعی دمو (بذر ۱۴) و نوار حکم — شکاف با ستون حذفشده ماند، پس بازسازی رخ داده. خط آخر بند صداقت است: مصنوعی، نه اجتماعی.
- First panel: the group column is locked — deleted before training, never read. The label is gone here, and so is the temptation to call it done.
- Second panel: the two proxies actually read — postcode at 0.756 vs 0.245 is effectively the group itself; device tier correlates too. Innocent alone, a clean rebuild together.
- Third panel: the opaque model scores from those two inputs and out comes the 0.511 gap — with no reason code. The auditor sees inputs and outputs only.
- Bottom table: the demo's four real numbers (seed 14) and the verdict strip — the gap survived the deleted column, so reconstruction happened. The last line is the honesty clause: synthetic, not social.
نقطهٔ تصمیم: نقطه تصمیم برچسب هر پنل است: قفل (نخوان)، پروکسی (بخوان و بسنج)، تصمیم (توضیح بخواه). پنل بدون سازوکار همان یافته است.
رد خرابی: خواندن همبستگی بهجای نیت، جنگ با سوءنیتی است که نیست؛ تمامشده دانستن شکاف با یک معیار، تبعیض فردا را با همان مدل برمیگرداند.
تضمین نشاندادهشده: شکل سازوکار بازسازی و عددهایش را نشان میدهد — روی داده مصنوعیِ برچسبخورده.
تضمین نشانندادهشده: درباره هیچ جمعیت، وامدهنده یا مدل واقعی چیزی نمیگوید؛ برابری فرصت بدون برچسب وامهای ردشده هم بیرون این شکل است.
Decision point: The decision point is each panel's label: locked (do not read), proxy (read and measure), decision (demand an explanation). A panel with no mechanism is the finding.
Failure trace: Reading correlation as intent fights a malice that is not there; calling the gap settled with one metric lets tomorrow's discrimination ride the same model.
Guarantee shown: The figure shows the reconstruction mechanism and its numbers — on labelled synthetic data.
Not shown: It says nothing about any real population, lender, or model; equal opportunity without rejected-loan labels is outside this figure too.
خودآزماییSelf-check
ستون گروه حذف شده ولی شکاف ۰٫۵۱۱ است؛ دقیقاً چه چیزی را ثابت میکند و چه چیزی را نه؟
پاسخ: ثابت میکند پروکسیها اطلاعات گروه را حمل کردند و مدل بازسازیاش کرده (سازوکار، روی داده مصنوعی). درباره تبعیض هیچ مدل واقعی یا نیت بدی چیزی ثابت نمیکند — همبستگی نیت نیست.
The group column is deleted yet the gap is 0.511. What exactly does that prove, and what does it not?
Answer: It proves the proxies carry the group information and the model reconstructed it (mechanism, on synthetic data). It proves nothing about any real model discriminating, nor any intent — correlation is not intent.
کد قابل اجراRunnable code
اجراشده و تأییدشده در همین محیطExecuted and verified in this environment
این کد آموزشی و سادهسازیشده است؛ فقط برای آشنایی با ایده. کد واقعی پروداکشن ملاحظات بسیار بیشتری دارد و هیچکس اینشکلی کد پروداکشن نمیزند.Simplified teaching code for building intuition only — not production code; nobody ships production code like this.
import java.util.*;
/**
* SYNTHETIC teaching demo: a lending model that never sees the protected
* attribute still rebuilds it from proxies. Fixed seed -> deterministic.
* This illustrates a mechanism (proxy reconstruction). It is NOT evidence
* about any real population, lender, or model.
*/
public class ProxyCorrelationDemo {
public static void main(String[] a) {
Random rnd = new Random(14);
int n = 2000;
int nA = 0, nB = 0, accA = 0, accB = 0;
int zoneHighA = 0, zoneHighB = 0;
for (int i = 0; i < n; i++) {
boolean groupA = rnd.nextDouble() < 0.5; // protected attribute: HIDDEN from model
// Proxies correlate with group (synthetic assumption, stated up front):
boolean zoneHigh = rnd.nextDouble() < (groupA ? 0.75 : 0.25); // postcode zone
boolean deviceNew = rnd.nextDouble() < (groupA ? 0.65 : 0.35); // device tier
// Model sees ONLY proxies. Dropping the group column changes nothing:
// the model never read it.
int score = (zoneHigh ? 2 : 0) + (deviceNew ? 1 : 0);
boolean accept = score >= 2;
if (groupA) {
nA++;
if (zoneHigh) zoneHighA++;
if (accept) accA++;
} else {
nB++;
if (zoneHigh) zoneHighB++;
if (accept) accB++;
}
}
double rateA = (double) accA / nA, rateB = (double) accB / nB;
System.out.println("SYNTHETIC population, n=" + n + " (seed 14). Model inputs: zone, device. Group column: never read.");
System.out.println("P(zone=high | group A) = " + String.format("%.3f", (double) zoneHighA / nA));
System.out.println("P(zone=high | group B) = " + String.format("%.3f", (double) zoneHighB / nB));
System.out.println("acceptance rate group A = " + String.format("%.3f", rateA));
System.out.println("acceptance rate group B = " + String.format("%.3f", rateB));
System.out.println("acceptance gap (A-B) = " + String.format("%.3f", rateA - rateB));
System.out.println("VERDICT: gap persists with the protected column deleted -> proxies rebuilt it (mechanism demo, not social evidence).");
}
}
اجرا: javac ProxyCorrelationDemo.java && java ProxyCorrelationDemo — فقط استاندارد جاوا، فوری و قطعی (بذر ۱۴).
خروجی مورد انتظار: ۰٫۷۵۶ در برابر ۰٫۲۴۵ برای پروکسی و پذیرش، با شکاف ۰٫۵۱۱ — با ستونی که هیچوقت خوانده نشد. (خروجی واقعی همین محیط)
Run: javac ProxyCorrelationDemo.java && java ProxyCorrelationDemo — stdlib Java only, instant, deterministic (seed 14).
Expected output: P(zone=high|A)=0.756 vs P(zone=high|B)=0.245; acceptance 0.756 vs 0.245, gap 0.511 — with the protected column never read. (actual output of this environment)
آزمون صحت و معیار عملیاتیCorrectness checks and operational criteria
نرخ پذیرش per-subgroup و شکافش هر هفته؛ اجرای دوباره با حذف ستون (شکاف مانده یعنی بازسازی)؛ یک invariant: هیچ تصمیمی بدون مسیر اعتراض انسانی نهایی نیست. معیار: توزیع نمره per-group و نرخ اعتراض.
Weekly per-subgroup acceptance rates and the gap; a column-deletion rerun (a surviving gap means reconstruction); one invariant: no decision is final without a human appeal path. Metrics: per-group score distributions and appeal rates.
پاسخ سؤالهای پیگیریFollow-up answers
پیگیری (سینیور): وامهای ردشده برچسب نتیجه ندارند؛ ارزیابی برابری فرصت چه مشکلی پیدا میکند؟Follow-up (Senior): There is no outcome label for rejected loans. What problem does this cause for equal-opportunity evaluation?
برابری فرصت به نتیجه واقعی نیاز دارد (چه کسی واقعاً پس میداد) ولی ما فقط نتیجه وامهای پذیرفتهشده را میبینیم — سوگیری برچسب. جواب صادق: گزارش برابری نرخ پذیرش کنار شکاف، بازبینی انسانی باندهای مرزی و گفتن صریح محدودیت؛ و هرگز ادعا نکردن که شبیهسازی این شکاف را پر میکند.
Equal opportunity needs true outcomes (who would actually have repaid), but we only observe outcomes for approved loans — label bias. The honest answer: report acceptance-rate parity alongside the gap, keep human review of borderline bands, state the limitation explicitly, and never claim a simulation fills it.
پیگیری (استف): دو تعریف عدالت با هم در تضادند؛ کدام را منتشر میکنی؟Follow-up (Staff): Two fairness definitions conflict. Which one do you ship?
هیچکدام بهتنهایی: تعریف را از هزینه خطای محصول انتخاب کن (وام ردشده با نانِ بریدهشده یکی نیست)، اثر هر دو تعریف را روی دقت و گروهها گزارش کن و تصمیم را با مدرکش ثبت کن — عدالت یک قرارداد ثبتشده است نه یک عدد.
Neither alone: choose the definition from the product's error costs (a rejected loan vs a rejected livelihood weigh differently), report both definitions' accuracy and subgroup effects, and record the choice with its evidence — fairness is a recorded contract, not a number.
اشتباهات رایجCommon mistakes
- حذف ستون محافظتشده یعنی مدل حالا عادل است. بازسازی از پروکسی دقیقاً همان چیزی است که دمو اندازه میگیرد — حذف برچسب حذف اطلاعات نیست.
- یک معیار عدالت (یا یک اجرای مصنوعی) حکم نهایی است. معیارها با هم در تضادند و داده مصنوعی فقط سازوکار را نشان میدهد — هرگز مدرک اجتماعی نیست.
- Deleting the protected column means the model is now fair. Reconstruction from proxies is exactly what the demo measures — removing the label is not removing the information.
- One fairness metric (or one synthetic run) settles the matter. Metrics conflict with each other, and synthetic data shows only the mechanism — it is never social evidence.
منابع:Sources: Microsoft · technical interviewing · Atlassian · engineering interview handbook
22 تمرین ۲ — شبیهسازیِ مارپیچExercise 2 — spiral simulation
بازگشت به صورت تمرینBack to the exercise · ارزیابی و سطحAssessment and level
پاسخ ۶۰ثانیهایThe 60-second answer
صورت مسئله و فرضهاProblem and assumptions
- عاملهای SYNTHETIC (۵۰۰ نفر)، ۵۰ دوره آموزشی و آستانه ۶۲۰: هر عددی فرض آموزشی است، هرگز ادعای تجربی نیست.
- شوک تصادفی هر دوره به ۵٪ عاملها میخورد (بیماری/بیکاری)؛ در مبنا تنها قاعده استخدامنکردن زیر آستانه است.
- بذرهای matched اثر تغییر قاعده را از نویز تصادفی جدا میکنند؛ بذر دوم حساسیت را میسنجد نه حقیقت را.
- SYNTHETIC agents (N=500), 50 teaching rounds, threshold 620: every count is a teaching assumption, never an empirical claim.
- Random shocks hit 5% of agents per round (illness/job loss); hiring below threshold is the only rule in baseline.
- Matched seeds isolate the rule change from RNG noise; a second seed tests sensitivity, not truth.
چرا این روش و این عددها؟Why this method and these numbers?
seed یکسان شوکهای تصادفی را ثابت نگه میدارد تا تفاوت دو سیاست از عوضشدن RNG نیاید؛ چند seed فقط حساسیت مدل را میسنجد. ۵۰۰ عامل، ۵۰ دور، آستانهٔ ۶۲۰ و شوک ۵٪ پارامترهای ساختگیاند؛ باید با تغییرشان پایداری نتیجه را بررسی کرد. میانگین ممکن است بهتر شود و گروه ضعیفتر بدتر؛ توزیع و بدترین گروه را هم میخوانیم چون میانگین محل هزینه را پنهان میکند.
Matched seeds hold random shocks fixed while comparing policies; additional seeds test model sensitivity only. Five hundred agents, fifty rounds, threshold 620 and 5% shocks are synthetic parameters to vary. An improving mean can hide worsening outcomes for weaker groups, so inspect distributions and the worst group as well.
مدل ذهنیMental model
حل گامبهگامStep by step
- حلقه را بکش، قیمت را بگو حلقه را بکش و هر فرض را با برچسب آموزشیاش نام ببر: ۵۰۰ عامل، ۵۰ دوره، آستانه ۶۲۰ و شوک ۵٪ — هیچکدام اندازهگیری نشده و همه گفته شده.
- بذر matched قاعده را میسنجد با همان بذر مقایسه کن: مبنای ۳۳٫۳۵ میانگین و ۹۴٫۹۰- دهک پایین در برابر مداخله ۱۴۶٫۹۰ و ۱۷٫۰۳ — شکاف اثر تغییر قاعده را جدا میکند چون تصادفی یکسان است.
- بذر دوم، هر دو عدد با بذر ۸ دوباره بزن (۱۴۷٫۵۴ و ۲۶٫۵۲): همان جهت و سطح جابهجا — حساسیت با صداقت. میانگین و ضعیفترین را کنار هم گزارش کن، ضعیف اول و بذر چسبیده.
- Draw the loop, state the price Draw the loop and label every assumption with its teaching status: 500 agents, 50 rounds, threshold 620, 5% shocks — none of them measured, all of them stated.
- Matched seeds compare rules Compare with the same seed: baseline 33.35 mean and -94.90 bottom decile against intervention 146.90 and 17.03 — the gap isolates the rule change because the randomness is identical.
- Second seed, both numbers Rerun with seed 8 (147.54 / 26.52): same direction, shifted levels — sensitivity, stated honestly. Report mean and weakest side by side, weakest first, with seeds attached.
مثال محاسبهشدهWorked example
اجراهای بذر-matched (۵۰۰ عامل، ۵۰ دوره آموزشی): مبنای بذر ۷ میانگین ثروت ۳۳٫۳۵ و دهک پایین ۹۴٫۹۰- با میانگین نمره ۵۲۵٫۹۰ میدهد؛ مداخله بذر ۷ میدهد ۱۴۶٫۹۰ و ۱۷٫۰۳ و ۵۹۳٫۱۳؛ مداخله بذر ۸ میدهد ۱۴۷٫۵۴ و ۲۶٫۵۲ و ۵۹۱٫۹۳. تفسیر: تغییر قاعده هر دو معیار را تکان میدهد؛ تغییر بذر سطح را جابهجا میکند ولی جهت را نگه میدارد. واحد: امتیاز اسباببازی ثروت/نمره — فقط داخل همین مدل قابل مقایسه.
Seed-matched runs (500 agents, 50 teaching rounds): baseline seed 7 gives mean wealth 33.35 and bottom decile -94.90 at mean score 525.90; intervention seed 7 gives 146.90 / 17.03 / 593.13; intervention seed 8 gives 147.54 / 26.52 / 591.93. Reading: the rule change moves both metrics; the seed change moves levels but keeps direction. Units: toy wealth/score points — comparable only inside this model.
دانلود نمودار مستقلDownload standalone diagram
- لاین اصلی: از پایدار به شوک (بدشانسی، نه تقصیر) به قسطهای عقبافتاده به نمره پایینتر به کماستخدامپذیر — هر گام علتش را نام میبرد و فیلتر آخری است.
- یال برگشت: از کماستخدامپذیر به قسطهای عقبافتاده حلقه را میبندد — فقر عمیقتر میشود، نمره دوباره میخوابد و فیلتر بعدی همان آدم را پیدا میکند.
- لاین مداخله: از نمره پایینتر به خواندن سوابق (تجربه را بسنج، عدد آسیبدیده را نادیده بگیر) و بعد یال بازگشت به پایدار — استخدام بر اساس سابقه.
- لاین پایانی: طردشده ته حلقه نشکسته منتظر است — بیرون از شغلها و خدمات، بدون اعتراض روی شکل. کارتها بند صداقت را حمل میکنند: مصنوعی، بذر-matched و هرگز اجتماعی.
- Main lane: Stable to Shock (bad luck, no fault) to Missed payments to Lower score to Less hirable — each step names its cause, and the filter is the last one.
- Return edge: Less hirable back to Missed payments closes the loop — poverty deepens, the score sinks again, and the next filter finds the same person.
- Intervention lane: from Lower score down to Read the record (judge experience, ignore the damaged number), then the recovery edge back to Stable — hired on history.
- Terminal lane: Excluded waits at the end of the unbroken loop — shut out of jobs and services, with no appeal on the figure. The cards carry the honesty clause: synthetic, seed-matched, never social.
نقطهٔ تصمیم: حالت تصمیم کماستخدامپذیر است: فیلتر آن را دور حلقه میفرستد و مداخله به خواندن سوابق میبرد. یک حالت و دو آینده — همان دوشاخه کل تمرین است.
رد خرابی: اول یال برگشت را دنبال کن: کماستخدامپذیر به قسطهای عقبافتاده برمیگردد — هر دور علت دور بعدی است و طرد کمکم شبیه proof درستی نمره میشود. بعد خروجی چیندار را دنبال کن: متقاضی باتجربه زیر آستانه بهجای فیلتر از خواندن سوابق میرود.
تضمین نشاندادهشده: شکل حلقه، یال بازگشت به پایدار و حالت پایانی طردشده را نشان میدهد. هیچ بازار استخدام واقعی را نشان نمیدهد.
تضمین نشانندادهشده: سطح ثروت، تعداد دورهها و نرخ شوک ۵٪ فرض آموزشیاند؛ اجرای دوباره با بذر یا افق دیگر آزمون حساسیت است نه ابطال.
Decision point: The decision state is Less hirable: the filter sends it around the loop, the intervention sends it down to Read the record. Same state, two futures — that fork is the whole exercise.
Failure trace: Trace the return edge first: Less hirable loops back to Missed payments — each round causes the next, and exclusion starts looking like proof the score was right. Then trace the dashed exit: below-threshold but experienced applicants leave through Read the record instead of the filter.
Guarantee shown: The figure shows the loop, the recovery edge back to Stable, and the terminal Excluded state. It does not show any real hiring market.
Not shown: Wealth levels, round counts and the 5% shock rate are teaching assumptions; rerunning with other seeds or horizons is the sensitivity test, not a refutation.
خودآزماییSelf-check
بذرهای یکسان و هرکدام دو عدد: از دمو چه گزارش میدهی و به چه ترتیبی؟
پاسخ: هر دو را گزارش کن، ضعیف اول: میانگین ۱۴۶٫۹۰ با دهک پایین ۱۷٫۰۳ (بذر ۷) و اجرای بذر ۸ (۱۴۷٫۵۴ و ۲۶٫۵۲) که ماندن جهت با جابهجایی سطح را نشان میدهد. بهبود میانگینی که به ضعیفترین آسیب بزند بهعنوان رد گزارش میشود.
Same seeds, two numbers each: what do you report from the demo, and in what order?
Answer: Report both, weakest first: mean 146.90 with bottom decile 17.03 (seed 7), and the seed-8 rerun (147.54 / 26.52) showing the direction holds while levels shift. A mean gain that harmed the weakest would be reported as a rejection.
کد قابل اجراRunnable code
اجراشده و تأییدشده در همین محیطExecuted and verified in this environment
این کد آموزشی و سادهسازیشده است؛ فقط برای آشنایی با ایده. کد واقعی پروداکشن ملاحظات بسیار بیشتری دارد و هیچکس اینشکلی کد پروداکشن نمیزند.Simplified teaching code for building intuition only — not production code; nobody ships production code like this.
import java.util.*;
/**
* SYNTHETIC toy feedback model: score -> employment -> income -> score.
* Round count (50) and all dynamics are teaching assumptions, NOT empirical
* claims about hiring, credit, or wealth. Matched seeds isolate the
* intervention effect from RNG noise. Never cite this as social evidence.
*/
public class SpiralSimDemo {
static final int N = 500, ROUNDS = 50;
static final double THRESHOLD = 620.0;
// Returns {meanWealth, bottomDecileWealth, meanScore}.
static double[] run(long seed, boolean intervention) {
Random rnd = new Random(seed);
double[] score = new double[N], wealth = new double[N];
for (int i = 0; i < N; i++) {
score[i] = 600 + rnd.nextDouble() * 100; // 600..700
wealth[i] = 50 + rnd.nextDouble() * 20; // 50..70
}
for (int r = 0; r < ROUNDS; r++) {
for (int i = 0; i < N; i++) {
if (rnd.nextDouble() < 0.05) score[i] -= 40; // shock: illness/job loss
boolean hired = intervention
? (score[i] >= THRESHOLD || wealth[i] > 55) // experienced/buffered: judged on record
: (score[i] >= THRESHOLD);
if (hired) {
wealth[i] += 2;
score[i] = Math.min(750, score[i] + 1);
} else {
wealth[i] -= 3;
score[i] = Math.max(300, score[i] - 2);
}
}
}
double[] w = wealth.clone();
Arrays.sort(w);
double mean = Arrays.stream(wealth).average().orElse(0);
double bottom = Arrays.stream(Arrays.copyOf(w, N / 10)).average().orElse(0);
double meanScore = Arrays.stream(score).average().orElse(0);
return new double[]{mean, bottom, meanScore};
}
public static void main(String[] a) {
System.out.println("SYNTHETIC toy model: " + N + " agents x " + ROUNDS + " rounds (teaching assumptions, seed-matched).");
double[] base = run(7, false);
double[] fix = run(7, true); // same seed: only the rule changed
double[] fixSeed2 = run(8, true); // sensitivity: same rule, different seed
System.out.println("baseline seed=7: meanWealth=" + f(base[0]) + " bottomDecile=" + f(base[1]) + " meanScore=" + f(base[2]));
System.out.println("intervention seed=7: meanWealth=" + f(fix[0]) + " bottomDecile=" + f(fix[1]) + " meanScore=" + f(fix[2]));
System.out.println("intervention seed=8: meanWealth=" + f(fixSeed2[0]) + " bottomDecile=" + f(fixSeed2[1]) + " meanScore=" + f(fixSeed2[2]));
System.out.println("READ: same-seed gap isolates the rule change; seed 7-vs-8 gap shows RNG sensitivity. Neither number describes any real society.");
}
static String f(double v) {
return String.format("%.2f", v);
}
}
اجرا: javac SpiralSimDemo.java && java SpiralSimDemo — فقط استاندارد جاوا، فوری و قطعی.
خروجی مورد انتظار: مبنا (بذر ۷): میانگین ۳۳٫۳۵ و دهک پایین ۹۴٫۹۰-؛ مداخله (بذر ۷): ۱۴۶٫۹۰ و ۱۷٫۰۳؛ مداخله (بذر ۸): ۱۴۷٫۵۴ و ۲۶٫۵۲ — جهت ماند، سطح با بذر جابهجا شد. (خروجی واقعی همین محیط)
Run: javac SpiralSimDemo.java && java SpiralSimDemo — stdlib Java only, instant, deterministic.
Expected output: Baseline seed 7: mean 33.35, bottom decile -94.90; intervention seed 7: 146.90 / 17.03; intervention seed 8: 147.54 / 26.52 — direction holds, level shifts with seed. (actual output of this environment)
آزمون صحت و معیار عملیاتیCorrectness checks and operational criteria
هر دو بذر را دوباره بزن و جهت را assert کن (مداخله بالاتر از مبنا در هر دو معیار)؛ افق را جارو کن (۲۰/۵۰/۱۰۰ دوره) و هر چرخشی را گزارش کن. invariant: هر گزارش با ضعیفترین گروه شروع میشود، بعد میانگین و بذر چسبیده.
Rerun both seeds and assert the direction (intervention above baseline on both metrics); sweep the horizon (20/50/100 rounds) and report any flip. Invariant: every report leads with the weakest group, mean second, seeds attached.
پاسخ سؤالهای پیگیریFollow-up answers
پیگیری (استف): مداخله میانگین ثروت را بهتر ولی بدترین گروه را بدتر میکند؛ چگونه گزارش میدهی؟Follow-up (Staff): An intervention raises mean wealth but worsens the weakest group. How do you report it?
اول جدول subgroup بعد میانگین: بهبود میانگین که ضعیفترین گروه را بدتر کند رد است نه برد. معیار دهک پایین را قبل از اجرا ثبت کن، هر دو عدد را با بذرشان گزارش کن و صریح بگو کدام گروه هزینه میانگین را میدهد.
Lead with the subgroup table, mean second: a mean gain that harms the weakest group is a rejection, not a win. Pre-register the bottom-decile metric before running, report both numbers with their seeds, and say explicitly which group pays for the mean.
پیگیری (سینیور): چرا ۵۰ دوره — اگر حکم در ۱۰۰ دوره عوض شود چه؟Follow-up (Senior): Why 50 rounds — what if the verdict flips at 100?
۵۰ فرض است نه اندازهگیری: در ۲۰ و ۱۰۰ دوره دوباره بزن و ببین جهت میماند یا نه. اگر حکم با افق عوض شد، جواب صادق این است که مدل نمیتواند مداخلهها را رتبه کند — همین را بگو بهجای انتخاب افق چاپلوس.
50 is an assumption, not a measurement: rerun at 20 and 100 rounds and check the direction holds. If the verdict flips with the horizon, the honest answer is that the model cannot rank the interventions — say so instead of picking a flattering horizon.
اشتباهات رایجCommon mistakes
- جا زدن اسباببازی بهجای مدرک تجربی استخدام. پنجاه دوره مصنوعی فقط وجود یک دینامیک در مدل را نشان میدهد — درباره هیچ بازار کار واقعی چیزی نمیگوید.
- گزارش فقط میانگین یا مقایسه اجراهای unmatched. میانگین میتواند بالا برود ولی ضعیفترینها غرق شوند و بذرهای نامتشابه شانس را مقایسه میکنند نه قاعده را.
- Presenting the toy as empirical hiring evidence. Fifty synthetic rounds prove a dynamic exists in the model — they say nothing about any real labor market.
- Reporting the mean alone, or comparing unmatched runs. A mean can rise while the weakest sink, and unmatched seeds compare luck, not rules.
منابع:Sources: Microsoft · technical interviewing · Atlassian · engineering interview handbook
33 تمرین ۳ — ممیزیِ رضایتِ یک سرویسِ واقعیExercise 3 — consent audit of a real service
بازگشت به صورت تمرینBack to the exercise · ارزیابی و سطحAssessment and level
پاسخ ۶۰ثانیهایThe 60-second answer
صورت مسئله و فرضهاProblem and assumptions
- فقط متن policy: دسترسی به implementation نیست، پس ادعاهای مشاهدهنشده unknown میمانند نه مجرم و نه بیگناه.
- policy تاریخدار و نسخهدار نقل میشود؛ متن بیتاریخ با تاریخ دسترسیاش snapshot حساب میشود.
- راهنمای پایین روی شکل generic سرویس است؛ هیچ ادعایی درباره رفتار شرکت واقعی نیست.
- Policy text only: no implementation access, so unobserved claims stay unknown rather than guilty or innocent.
- A dated, versioned policy is quoted; undated text is treated as a snapshot with its access date.
- The walkthrough below uses a generic service shape; no real company's behavior is claimed.
چرا این روش و این عددها؟Why this method and these numbers?
policy ادعای عمومی دربارهٔ رفتار است؛ مشاهدهٔ اجرای backend نیست، پس unknown به نبود شاهد اشاره دارد. مبنای پردازش را برای هر purpose جدا میکنیم چون رضایت تنها مبنای ممکن نیست و withdrawal هم لزوماً همهٔ نگهداری قانونی را حذف نمیکند. تاریخ و نسخه لازماند تا خواننده بداند کدام متن بررسی شده. نتیجهٔ مهندسی دربارهٔ کنترل و جریان داده را از نظر حقوقی جدا نگه میداریم؛ تصمیم حقوقی به زمینه و مرجع واجد صلاحیت نیاز دارد.
A policy is a public statement, not observation of backend implementation; unknown marks missing evidence. Assess processing basis by purpose because consent is not the only possible basis and withdrawal need not erase lawful retention obligations. Date/version identify the reviewed text. Separate engineering findings about controls and flows from legal determinations needing context and qualified review.
مدل ذهنیMental model
حل گامبهگامStep by step
- تاریخش بزن، نقشهاش کن تاریخ و نسخه را نقل کن بعد هر مقصود را نقشه کن: چه داده، چرا، تا کی و مشترک با کی. بند بدون مقصود آزمونناپذیر است — همین را بنویس و دورش تفسیر نباف.
- هر مقصود یک مبنا per-purpose مبنای قانونی را نام ببر — رضایت، قرارداد، تکلیف قانونی یا منفعت مشروع — بعد آزمون پنجشرطی را فقط جایی بزن که ادعای رضایت است، با قیمت رد بهعنوان آزمون آزادانهبودن.
- unknownها unknown میمانند هر ادعای مشاهدهناپذیر را با تاریخ بازبینی unknown بزن، گزینه واقعی کاربر کمبرخوردار را نام ببر و ارزیابی مهندسی تحویل بده: چه سنجیده شد، چه کدام شرط را باخت و چه unknown است — بدون رأی حقوقی.
- Date it, map it Quote the date and version, then map every purpose: what data, why, how long, shared with whom. A clause without a purpose attached is untestable — write that down, do not interpret around it.
- One basis per purpose Name the lawful basis per purpose — consent, contract, legal obligation, or legitimate interest — then run the five-condition test only where consent is claimed, with the refusal price as the freely-given probe.
- Unknowns stay unknown Mark every unobservable claim unknown with a re-check date, name the disadvantaged user's real option, and deliver an engineering assessment: what was tested, what failed which condition, what is unknown — no legal verdict.
دانلود نمودار مستقلDownload standalone diagram
- لاین مدرک: از policy تاریخدار به نقشه جریان — نسخه بهعلاوه تاریخ را نقل کن بعد per-purpose بنویس چه داده، چرا، تا کی و مشترک با کی. هیچ ادعایی بدون مقصودش سفر نمیکند.
- لاین تحلیل: از تفکیک مبانی به آزمون انتخاب — per-purpose رضایت، قرارداد یا منفعت مشروع، بعد هر پنج شرط باهم، با قیمت رد که آزادانهبودن را مشخص میکند.
- شاخه: رد باندل به خوانش حقوقی میرود — سرویس عملاً اجباری که بهعنوان سؤال باز اعتبار علامت میخورد، هرگز حکمی که تو صادر کنی نیست.
- لاین گزارش: از علامت unknownها به گزارش مهندسی — متن policy هیچوقت سرورها را ثابت نمیکند، پس unknownها با تاریخ میمانند و گزارش مهندسی را میسنجد نه حقوق را.
- Evidence lane: Dated policy to Flow map — quote version plus date, then list what data, why, how long, shared with whom, per purpose. No claim travels without its purpose attached.
- Analysis lane: Separate bases to Choice test — consent, contract, or legitimate interest per purpose, then all five conditions at once, with the refusal price deciding freely-given.
- Branch: a bundled refusal routes to Legal read — the effectively mandatory service, flagged as an open validity question, never a verdict you deliver.
- Report lane: Mark unknowns to Engineering report — policy text never proves servers, so unknowns stay unknown with dates, and the report assesses engineering, not law.
نقطهٔ تصمیم: گرههای تصمیم تفکیک مبانی و آزمون انتخاباند: per-purpose مبنا را نام ببر بعد قیمت رد را بسنج. مقصود بدون مبنای نامبرده رانبوک را متوقف میکند — جمع نکن هم حکم است.
رد خرابی: اول میانبر را دنبال کن: پیکان بگیر-یا-بگذار از بیخبر مستقیم از همه آزمونها میپرد — همان انتخاب غیرآزادی که رانبوک برای گرفتنش هست. بعد یال برگشت را دنبال کن: مقصود تازه رضایتدادهشده را به در حال تصمیم برمیگرداند، چون مقصود تازه رضایت تازه میخواهد.
تضمین نشاندادهشده: شکل ترتیب ممیزی و خروجیهای صداقت (unknownها و خوانش حقوقی) را نشان میدهد. درباره رفتار هیچ سرویس واقعی چیزی ثابت نمیکند.
تضمین نشانندادهشده: مهلتها، قضاوت اعتبار و واقعیتهای implementation بیرون شکلاند — بهترتیب با وکیل و مشاهده.
Decision point: The decision nodes are Separate bases and Choice test: name the basis per purpose, then price the refusal. A purpose with no named basis stops the runbook — do not collect is a verdict too.
Failure trace: Follow the shortcut first: the take-it-or-leave-it arrow jumps from Unaware straight past every test — the unfree choice the runbook exists to catch. Then follow the return edge: a new purpose sends Consented back to Deciding, because a new purpose needs fresh consent.
Guarantee shown: The figure shows the audit order and the honesty exits (unknowns, legal read). It proves nothing about any real service's behavior.
Not shown: Deadlines, validity judgments and implementation facts live outside the figure — with counsel and observation, respectively.
خودآزماییSelf-check
ممیزی تمام شد: کدام سه مصنوع ثابت میکند صادق بوده؟
پاسخ: سه مصنوع: تاریخ/نسخه نقلشده، جدول مبنای per-purpose با قیمت رد، و فهرست تاریخدار unknownها — بهعلاوه یک جمله درباره گزینه واقعی کاربر کمبرخوردار. هیچجا رأی حقوقی نیست.
The audit is done: what three artifacts prove it was honest?
Answer: Three artifacts: the quoted date/version, the per-purpose basis table with refusal prices, and the dated unknown list — plus one sentence on the disadvantaged user's real option. No legal verdict anywhere.
آزمون صحت و معیار عملیاتیCorrectness checks and operational criteria
جدول مبنای per-purpose کامل؛ هر ادعای رضایت با هر پنج شرط سنجیده؛ مسیر پسگرفتن جایی که ممکن است با حساب خودت رفتهشده؛ فهرست unknown تاریخدار. معیار: سهم مقصودها با مبنای نامبرده و رد قیمتخورده.
Per-purpose basis table complete; each consent claim tried against all five conditions; withdrawal path walked on your own account where possible; unknown list dated. Metric: share of purposes with a named basis and a priced refusal.
پاسخ سؤالهای پیگیریFollow-up answers
پیگیری (سینیور): رد ردیابی خدمت پایه را حذف میکند؛ برای سنجش آزادانهبودن رضایت چه مدرکی لازم است؟Follow-up (Senior): Refusing tracking removes the basic service. What evidence is needed to assess freely given consent?
مدرک ضرورت جمع کن: آیا خدمت پایه بدون ردیابی کار میکند (امتحانش کن)، رضایت per-purpose خواسته میشود یا باندل، و با رد دقیقاً چه از دست میرود. رد باندل بهعلاوه سرویس عملاً اجباری یعنی شرط آزادانهبودن برقرار نیست — همین را گزارش کن، نه رأی حقوقی کلی درباره شرکت.
Collect necessity evidence: does the core service work without the tracking (try it), is consent requested per purpose or bundled, and what exactly is lost on refusal. Bundled refusal plus an effectively mandatory service means the freely-given condition fails — report it as failing that condition, not as a company-wide legal verdict.
پیگیری (استف): policy درباره نگهداری و سازوکار پسگرفتن ساکت است؛ در گزارش چه مینویسی؟Follow-up (Staff): The policy is silent on retention and withdrawal mechanics. What goes in the report?
با تاریخ بازبینی unknown علامتش بزن — شکاف را هرگز با ظن یا اعتماد پر نکن. بنویس کدام مقصودها نگهداری ندارند (انقضا آزمونناپذیر)، پسگرفتن مسیر واقعی است یا پاراگراف، و چه کسی جواب سؤال را میدهد. unknown تاریخدار نتیجه مهندسی است؛ حدس نیست.
Mark it unknown with a re-check date — never fill the gap with suspicion or trust. Note which purposes lack retention (expiry untestable), whether withdrawal is a real path or a paragraph, and who answers questions. An unknown with a date is an engineering result; a guess is not.
اشتباهات رایجCommon mistakes
- خواندن policy عمومی بهجای proof رفتار. متن مدرک قولهاست؛ بدون مشاهده، داشبورد یا لاگ، ادعاهای رفتاری unknown میمانند.
- فرض اینکه همهچیز رضایت میخواهد. جلوگیری از تقلب، اجرای قرارداد و تکالیف قانونی با مبانی دیگر کار میکنند — همهجا رضایت خواستن پردازش قانونی را بدبرچسب میزند و مقصودهایی که واقعاً رضایت میخواهند پنهان میمانند.
- Reading the public policy as implementation proof. The text is evidence of promises; without observation, dashboards, or logs, behavior claims stay unknown.
- Assuming everything needs consent. Fraud prevention, contract performance and legal obligations run on other bases — demanding consent everywhere mislabels lawful processing and hides the purposes where consent truly is required.
منابع:Sources: EDPB · consent guidelines 05/2020 · European Commission · lawful grounds for processing
44 تمرین ۴ — سیاستِ کمینهسازی و پاکسازیExercise 4 — minimization and purge policy
بازگشت به صورت تمرینBack to the exercise · ارزیابی و سطحAssessment and level
پاسخ ۶۰ثانیهایThe 60-second answer
صورت مسئله و فرضهاProblem and assumptions
- فروشگاهی با سفارش، پروفایل، clickstream و session؛ هر روز نگهداری پایین نمایشی و آموزشی است (آموزشی) و در پروداکشن per-product با تفسیر حقوقی اندازه میخورد.
- holdهای حقوقی per-matter با مالک و بازبینی انقضا میآیند؛ ردیف held هم از sweep و هم از restore جان سالم میبرد.
- بکاپها با نگهداری منقضی و نابود میشوند، نه بایگانی؛ دمو sweep و hold و aggregateها و restore را در حافظه مدل میکند.
- A shop with orders, profiles, clickstream and sessions; every retention day below is ILLUSTRATIVE teaching (آموزشی), sized per product with legal interpretation in production.
- Legal holds arrive per matter with an owner and an expiry review; a held row survives the sweep and the restore alike.
- Backups expire by retention and are destroyed, not archived; the demo models the sweep, the hold, the aggregates and the restore in memory.
چرا این روش و این عددها؟Why this method and these numbers?
retention را از purpose و الزام و کمترین دادهٔ لازم به دست میآوریم؛ ۳۰/۹۰ روز یا هفت سال در نمونهها قانون عمومی نیستند. purge باید idempotent باشد چون crash و retry طبیعیاند. aggregate خودکار ناشناس نیست: گروه کوچک یا join با دادهٔ دیگر میتواند فرد را معلوم کند. restore باید پیش از سرو داده، registry حذف را replay کند تا backup قدیمی کاربر حذفشده را برنگرداند؛ RTO باید همین مرحله را نیز حساب کند.
Derive retention from purpose, obligations and minimum necessary data; example periods are not universal legal rules. Purges must be idempotent because crashes and retries occur. Aggregates can remain identifiable through small groups or joins. Before serving a restored backup, replay the deletion registry so deleted users do not reappear; include this stage in RTO.
مدل ذهنیMental model
حل گامبهگامStep by step
- اول جدول بعد ابزار اول موجودی: per-kind یک ردیف با مقصود، نگهداری نمایشی و سرنوشت بعد — حذف، aggregate یا hold. هیچ ردیفی بدون مالک؛ هیچ ردیف «شاید بعداً مفید» اصلاً.
- sweep بزن بعد تا صفر دوباره ایدمپوتنت sweep بزن: ردیفهای منقضی tombstone، کلیدهای مشتق purge و tombstone لاگ الصاق — همه با بررسی hold، پس u2-order میماند. دوباره sweep بزن و صفر پاک جدید بخواه؛ همان صفر امضای قرارداد است.
- aggregate و ممیزی لاغر میمانند باقیمانده را حکمرانی کن: aggregateها فقط با n≥۵ منتشر با suppression دوباره موقع اصلاح؛ ممیزی hash شناسهها را حمل میکند، هرگز PII خام نه — مدرک نباید خودش کپی تازه داده شود.
- restore دروازهدار با صفر زندهشده از میان tombstoneها restore کن: snapshot صدوهشتادروزه بازپخش میشود، u1 و u3 رد میشوند و u5 زنده برمیگردد — resurrected=0. snapshotهای قدیمیتر از نگهداری نابود میشوند، هرگز بازپخش نه.
- حساب رخنه از روی موجودی رخنه را از روی موجودی قیمت بزن: سفارشها و پروفایلها per-table حاضر و موقعیت دقیق هیچوقت جمع نشده پس نمیتواند لو برود. ارزانترین کنترل حریم دادهای است که هیچوقت نداشتی.
- Table before tooling Inventory first: one row per data kind with purpose, illustrative retention, and what happens after — delete, aggregate, or hold. No row without an owner; no 'maybe useful later' rows at all.
- Sweep, then resweep to zero Sweep idempotently: expired rows tombstoned, derived keys purged, log tombstone appended — all hold-checked, so u2-order survives. Resweep and demand zero new purges; that zero is the protocol's signature.
- Aggregates and audit stay lean Govern the leftovers: aggregates publish only at n>=5 with suppression rerun on corrections; audit carries hashes of ids, never raw PII — the proof must not become a new copy of the data.
- Gated restore, zero resurrected Restore through the tombstones: the 180-day snapshot replays, u1 and u3 are skipped, u5 returns live — resurrected=0. Snapshots older than retention are destroyed, never replayed.
- Breach math from inventory Price the breach off the inventory: orders and profiles present per table, precise location never collected so it cannot leak. The cheapest privacy control is the data you never held.
طراحی مشخصConcrete design
جدولها: retention(kind, days_illustrative, owner) و tombstones(id, purged_at) و holds(id, matter, owner, review_at) و audit_purges(hash(id), actor, at). حلقه sweeper per-row: اگر سن > نگهداری و hold زنده نیست → tombstone شناسه، پاکسازی کلیدهای مشتق، الصاق tombstone لاگ و hash در ممیزی؛ sweepهای دوباره نباید چیزی عوض کنند. aggregateها فقط سلولهای n>=5 (k آموزشی) را منتشر میکنند؛ اصلاحیهها suppression را دوباره میزنند. مسیر restore: ردیفهای snapshot با LEFT ANTI JOIN tombstones — شناسههای tombstoneشده هیچوقت برنمیگردند؛ snapshotهای قدیمیتر از نگهداری نابود میشوند، هرگز بازپخش نه. خواندنهای ممیزی هر ادعا را ثابت میکنند؛ PII خام هیچوقت در هیچ لاگی نمینشیند.
Tables: retention(kind, days_illustrative, owner), tombstones(id, purged_at), holds(id, matter, owner, review_at), audit_purges(hash(id), actor, at). Sweeper loop per row: if age > retention and no live hold → tombstone id, purge derived keys, append log tombstone, hash into audit; resweeps must change nothing. Aggregates publish only cells with n>=5 (teaching k); corrections rerun suppression. Restore path: snapshot rows LEFT ANTI JOIN tombstones — tombstoned ids never re-enter; snapshots older than retention are destroyed, never replayed. Audit reads prove every claim; raw PII never lands in any log.
مثال محاسبهشدهWorked example
اجرای آموزشی (روزهای نمایشی: سفارش ۳۶۵، clickstream نود و session سی): u1-order (۴۰۰ روزه) و u3-click (۱۲۰ روزه) پاک شدند؛ u2-order (۴۰۰ روزه) با hold حقوقی نگه داشته شد؛ u4-session و u5-profile تازه و نگهداشته. sweep دوباره: ۰ پاک تازه. aggregateها: ۱۲تایی منتشرشدنی و ۳تایی suppressed. restore ی snapshot صدوهشتادروزه: ۲ tombstoneشده رد و ۱ زنده بازپخش و ۰ زندهشده. ممیزی: دو hash و صفر PII خام.
Teaching run (illustrative days: order 365, clickstream 90, session 30): u1-order (400d) and u3-click (120d) purged; u2-order (400d) held back by legal hold; u4-session and u5-profile fresh and kept. Resweep: 0 new purges. Aggregates: n=12 publishable, n=3 suppressed. Restore of the 180-day snapshot: 2 tombstoned skipped, 1 live replayed, 0 resurrected. Audit: two hashes, zero raw PII.
دانلود نمودار مستقلDownload standalone diagram
- فروشگاهها: مرجع سفارش، کش و ایندکس مشتق و لاگ فقطافزودنی — سه کپی که sweep باید ببندد، هرکدام با برچسب نگهداری آموزشیاش.
- job پاکسازی: sweeper ایدمپوتنت ردیفهای منقضی و کلیدهای مشتق را میگیرد با بررسی در برابر فهرست hold per-matter — ردیف held اینجا میماند.
- proof حذف: شناسههای tombstone، انقضای بکاپ بهعلاوه نابودی و tombstone الصاقی لاگ — سه مدرکی که restore لازم خواهد داشت.
- پایانهای حکمرانیشده: aggregateهای فقط-شمارش (k≥۵ وگرنه suppressed)، رسیدهای hash-فقط ممیزی و دروازه restore که از میان tombstoneها بازپخش میکند.
- Stores: order record, derived cache plus index, and the append-only log — the three copies the sweep must close, each with its teaching retention tag.
- Purge job: the idempotent sweeper takes expired rows and derived keys, checked against the per-matter hold list — the held row survives here.
- Deletion proof: tombstone ids, backup expiry plus destruction, and the appended log tombstone — three proofs the restore will need.
- Governed ends: counts-only aggregates (k>=5 or suppressed), hash-only audit receipts, and the restore gate that replays through tombstones.
نقطهٔ تصمیم: گره تصمیم sweeper است: سه فهرست ورودی (ردیفهای منقضی، کلیدهای مشتق و holdها) و یک قاعده — سن بعد از نگهداری بدون hold زنده. هرچه پاییندست است مدرک است نه انتخاب.
رد خرابی: اول هزینه هر یال گمشده را دنبال کن: بدون فهرست hold یعنی sweep مدرک زیر بررسی را میخورد؛ بدون شناسههای tombstone یعنی restore حذفشدهها را بازپخش میکند؛ بدون انقضا یعنی بکاپها بعد از نگهداری تلنبار میشوند. بعد دو پایان حکمرانیشده بینیاز از sweep را دنبال کن: فقط-شمارش به aggregateها و رسیدهای hash به ممیزی.
تضمین نشاندادهشده: شکل سازوکار پاکسازی هر کپی و دو نگهبان (hold و tombstoneها) را نشان میدهد. روزهای نگهداری و تمرین restore در دو شکل بعدیاند.
تضمین نشانندادهشده: نه مهلت حقوقی میگذارد و نه restore اجرا میکند — جدول و توالی آن کار را میکنند.
Decision point: The decision node is the sweeper: three incoming lists (expired rows, derived keys, holds) and one rule — age past retention with no live hold. Everything downstream is proof, not choice.
Failure trace: Trace what each missing edge would cost: no hold list means the sweep eats evidence under matter review; no tombstone ids means the restore replays the deleted; no expiry means backups pile up past retention. Then trace the two governed ends that need no sweep: counts-only into Aggregates and hash receipts into Audit.
Guarantee shown: The figure shows every copy's purge mechanism and the two guards (hold, tombstones). Retention days and the restore drill live in the next two figures.
Not shown: It sets no legal deadline and runs no restore — the table and the sequence do that.
خودآزماییSelf-check
کدام ورودی اگر بیفتد sweep را از پاکسازی به نابودی مدرک تبدیل میکند؟
پاسخ: فهرست hold: بدون آن sweep نمیتواند مدرک را از ردیف منقضی تشخیص دهد و hold پاکشده همان راه مرگ بیصدای مدرک است.
Which single input, if dropped, turns the sweep from purge into evidence destruction?
Answer: The hold list: without it the sweep cannot tell evidence from expired rows, and a deleted hold is how evidence dies quietly.
دانلود نمودار مستقلDownload standalone diagram
- نوار sweep: sweep با بررسی hold، tombstone برای u1 و u3، watermarkهای پایدار و رسیدهای hash ممیزی — همان مدرکی که بازپخش مشورتش میکند.
- درخواست بازپخش: اپراتور snapshot صدوهشتادروزه را میخواهد؛ بکاپ مستقیم جواب نمیدهد — اول از میان tombstoneها بازپخش میکند.
- مشورت: u1 و u3 حذف شدهاند، ردشان کن — پیام امنیتیرنگ، تنها سؤالی که میان بکاپ و زنده کردن ایستاده.
- فقط ردیفهای زنده: u5 برمیگردد، اپراتور صفر زندهشده میشنود و خود restore با hash ثبت میشود — مدرک بدون PII.
- Sweep band: hold-checked sweep, tombstones for u1 and u3, durable watermarks, hashed audit receipts — the proof the replay will consult.
- Replay request: the operator asks for the 180-day snapshot; the backup does not answer directly — it replays through the tombstones first.
- The consult: u1 and u3 are deleted, skip them — the security-colored message, the only question standing between backup and resurrection.
- Live rows only: u5 returns, the operator hears zero resurrected, and the restore itself is recorded in hashes — proof without PII.
نقطهٔ تصمیم: پیام تصمیم همان مشورت tombstone است: بکاپ قبل از برگرداندن حتی یک ردیف میپرسد کدام شناسهها حذف شدهاند. restore بدون آن سؤال همان باگ زنده کردن است.
رد خرابی: دو خرابی را روی شکل بازپخش کن: مشورت tombstone (پیام ۶) را رد کن و ردیفهای حذفشده مستقیم به فروشگاه زنده میریزند؛ snapshot قدیمیتر از نگهداری را بازپخش کن و هیچ دروازهای برای ایستادنش نمانده. بعد مسیر hold را بازپخش کن: u2-order هیچوقت tombstone نشد، پس قانونی برمیگردد.
تضمین نشاندادهشده: شکل ترتیب sweep-بعد-restore و مشورت tombstone در هر بازپخش را نشان میدهد. suppression aggregate و حساب رخنه را نشان نمیدهد.
تضمین نشانندادهشده: ظرافت aggregate و فهرست هیچوقت-جمعنشده در جدول اسمبلاند.
Decision point: The decision message is the tombstone consult: the backup asks which ids are deleted before returning a single row. A restore without that question is the resurrection bug.
Failure trace: Replay the two failures on the figure: skip the tombstone consult (message 6) and the deleted rows flow straight into the live store; replay a snapshot older than retention and there is no gate left to stop it. Then replay the hold path: u2-order was never tombstoned, so it returns lawfully.
Guarantee shown: The figure shows the sweep-then-restore order and the tombstone consult on every replay. It does not show aggregate suppression or breach math.
Not shown: Aggregate subtlety and the never-collected list live in the assembly table.
خودآزماییSelf-check
کدام تکپیام اگر رد شود u1 و u3 را زنده میکند؟
پاسخ: مشورت tombstone: حذفش میگذارد بکاپ فقط از snapshot جواب بدهد و دو شناسه حذفشده به فروشگاه زنده برمیگردند.
Which single message, if skipped, resurrects u1 and u3?
Answer: The tombstone consult: deleting it lets the backup answer from the snapshot alone, and the two deleted ids flow back into the live store.
دانلود SVG مستقلDownload standalone SVG
- مرجع، نماها و لاگ: sweeper ردیفهای منقضی را پاک میکند، کلیدهای مشتق را purge میکند و tombstone لاگ را الصاق میکند — همان جعبههای جریان داده، حالا هرکدام یک ردیف.
- بکاپها و aggregateها: snapshotهای قدیم انقضا بهعلاوه نابودی؛ سلولهای کوچک suppress — خانه صورتی اعتراف میکند aggregateها خودکار ناشناس نیستند.
- ممیزی و رخنه: فقط hash، هرگز PII خام — خود لاگ مدرک است؛ نوار رخنه مواجهه را از روی موجودی قیمت میزند با ستاره روی آنچه هیچوقت جمع نشد.
- پانوشت: روزهای ستارهدار اعداد آموزشی نمایشیاند — جدول از گفتن قانون خودداری میکند و مهلتها را به وکیل میفرستد.
- Record, views, log: the sweeper deletes expired rows, purges derived keys, and appends the log tombstone — same boxes as the dataflow, now one row each.
- Backups and aggregates: old snapshots expire plus destruction; small cells suppress — the rose cell admits aggregates are not automatically anonymous.
- Audit and breach: hashes only, never raw PII — the log itself is the proof; the breach band prices exposure off the inventory, starring what was never collected.
- Footnote: the starred days are illustrative teaching numbers — the table refuses to state law, and sends deadlines to counsel.
نقطهٔ تصمیم: ستون تصمیم همان سازوکار است: هر ردیف میگوید کپیاش چطور میمیرد (sweeper، tombstone، انقضا و suppression). ردیف بدون سازوکار همان یافته است.
رد خرابی: اول خانه صورتی را دنبال کن: aggregate قابل بازشناسایی همان ردیفی است که بعد از پاکسازی خطرناک میماند — سلولهای کوچک suppressed میشوند نه منتشر. بعد نوار رخنه را دنبال کن: هرچه هیچوقت جمع نشده نمیتواند لو برود، که ارزانترین ردیف کل جدول است.
تضمین نشاندادهشده: شکل هر دو نمودار گام را در یک حکم per-copy ترکیب میکند و رخنه را از روی موجودی قیمت میزند. روزها سرتاسر نمایشی میمانند.
تضمین نشانندادهشده: مهلتهای حقوقی و انتخاب مبنا غایباند — مال ممیزی رضایتاند.
Decision point: The decision column is the mechanism: each row names how its copy dies (sweeper, tombstone, expiry, suppression). A row with no mechanism is the finding.
Failure trace: Trace the rose cell first: the re-identifiable aggregate is the one row that stays dangerous after purging — small cells are suppressed, not published. Then trace the breach band: whatever was never collected cannot leak, which is the cheapest row in the whole table.
Guarantee shown: The figure composes both step diagrams into one verdict per copy and prices the breach off the inventory. Days stay illustrative throughout.
Not shown: Legal deadlines and basis choices are absent — the consent audit owns them.
خودآزماییSelf-check
کدام ردیف حتی بعد از sweep بینقص خطرناک میماند و نگهبانش چیست؟
پاسخ: ردیف aggregateها: suppression سازوکار است، فهرست سلول suppressed مدرک است و رنگ صورتی هشدار میدهد بدون آن گام بازشناساییپذیر میماند.
Which row stays dangerous even after a perfect sweep, and what is its guard?
Answer: The aggregates row: suppression is the mechanism, the suppressed-cell list is the proof, and the rose color warns it stays re-identifiable without that step.
گزینههای جایگزینAlternatives
- نگه داشتن همهچیز بهصورت رمز با shredding کلید per-user: حذف میشود نابودی کلید — فوری و restore-امن — ولی مدیریت کلید per-user، بازکلیدزنی موقع رخنه و کلید لو رفته که بیصدا حذف را خنثی میکند. وقتی مهلتها تنگاند و سرویس کلید از قبل سخت شده میارزد؛ وگرنه sweep بهعلاوه tombstone برای ممیزی سادهتر است.
- restore کامل ساده بدون دروازه tombstone: تمرین بازیابی سریعتر و ابزار بکاپ سادهتر، ولی هر restore بعد از حذف کاربرها را زنده میکند — دقیقاً همان خرابی که آزمون restore دمو برای جلوگیریاش هست. فقط برای داده بدون تکلیف حذف قابل قبول است؛ داده شخصی آن داده نیست.
- Keep everything, encrypted, with per-user crypto-shredding: deletion becomes key destruction — instant and restore-safe — but per-user key management, re-keying on breach, and a leaked key silently defeat the deletion. Worth it when legal deadlines are tight and the key service is already hardened; otherwise the sweep plus tombstones is simpler to audit.
- Plain full restores with no tombstone gate: faster recovery drills and simpler backup tooling, but any restore past a deletion resurrects users — the exact failure the demo's restore probe exists to prevent. Acceptable only for data with no erasure duty; personal data is not that data.
سناریوهای خرابیFailure scenarios
- restore بدون مشورت tombstone: بکاپ فقط از snapshot جواب میدهد و کاربرهای حذفشده به فروشگاه زنده برمیگردند. مشورت بهینهسازی نیست — نگهبان زنده کردن است و دمو assert میکند skipped=2 و resurrected=0.
- آزادسازی hold بدون عامل دوم و یادداشت ممیزی: sweep بعدی مدرک را قانونی پاک میکند زیر پرونده بسته — یا بدتر، زیر پرونده بازی که بسته ثبت شده. نگهبان: آزادسازی hold عامل دوم بهعلاوه ورودی ممیزی میخواهد و sweepها ردیفهایی که بازبینی holdشان عقب افتاده رد میکنند.
- افت aggregate زیر k بعد از اصلاح: سلول منتشرشده ۱۲تایی با اصلاح ردیفها ۴تایی میشود و aggregate منتشرشده بیصدا بازشناساییپذیر میشود. نگهبان: اصلاحیهها suppression را دوباره میزنند قبل از هر بازانتشار.
- crash دادن sweeper وسط sweep: نیمی از کپیها پاک و نیمی در انتظار و retry نباید دو بار tombstone بزند یا رد شود. نگهبان: اول tombstone و resweep ایدمپوتنت — چاپ ۰ sweep دوم دمو کل قرارداد است در یک عدد.
- Restore without the tombstone consult: the backup answers from the snapshot alone and deleted users flow back into the live store. The consult is not optimization — it is the resurrection guard, and the demo asserts skipped=2, resurrected=0.
- A released hold with no second actor and no audit note: the next sweep lawfully deletes evidence under a closed matter — or worse, under an open one misfiled as closed. Guard: hold release needs a second actor plus an audit entry, and sweeps refuse rows whose hold review is overdue.
- Aggregate drift below k after a correction: a published cell of 12 shrinks to 4 when rows are fixed, and the published aggregate quietly becomes re-identifiable. Guard: corrections rerun suppression before anything republishes.
- Sweeper crash mid-sweep: half the copies purged, half pending, and the retry must not double-tombstone or skip. Guard: tombstone-first, idempotent resweep — the demo's second sweep printing 0 is the whole protocol in one number.
کد قابل اجراRunnable code
اجراشده و تأییدشده در همین محیطExecuted and verified in this environment
این کد آموزشی و سادهسازیشده است؛ فقط برای آشنایی با ایده. کد واقعی پروداکشن ملاحظات بسیار بیشتری دارد و هیچکس اینشکلی کد پروداکشن نمیزند.Simplified teaching code for building intuition only — not production code; nobody ships production code like this.
import java.util.*;
/**
* Teaching purge-policy simulator (stdlib only, in-memory).
* Retention days below are ILLUSTRATIVE teaching numbers — they are
* NOT legal requirements. Real deadlines need legal interpretation.
* Deletion rule: age > retention AND no legal hold -> tombstone (idempotent).
*/
public class PurgePolicyDemo {
static class Row {
String id, kind;
int ageDays;
boolean legalHold, tombstoned;
Row(String id, String kind, int ageDays, boolean legalHold) {
this.id = id;
this.kind = kind;
this.ageDays = ageDays;
this.legalHold = legalHold;
}
}
public static void main(String[] a) {
// ILLUSTRATIVE retention table (teaching numbers, not law):
Map<String, Integer> retention = new LinkedHashMap<>();
retention.put("order", 365);
retention.put("profile", 365);
retention.put("clickstream", 90);
retention.put("session", 30);
System.out.println("retention table (ILLUSTRATIVE, teaching days): " + retention);
List<Row> store = new ArrayList<>(List.of(
new Row("u1-order", "order", 400, false), // expired, purged
new Row("u2-order", "order", 400, true), // expired BUT legal hold: kept
new Row("u3-click", "clickstream", 120, false), // expired, purged
new Row("u4-session", "session", 10, false), // fresh, kept
new Row("u5-profile", "profile", 200, false) // fresh, kept
));
Set<String> tombstones = new HashSet<>();
int purged = 0;
for (Row r : store) {
if (r.ageDays > retention.get(r.kind) && !r.legalHold) {
r.tombstoned = true;
tombstones.add(r.id);
purged++;
System.out.println("purge " + r.id + " (" + r.kind + ", age " + r.ageDays + "d > " + retention.get(r.kind) + "d)");
}
}
// Idempotency: second sweep changes nothing.
int second = 0;
for (Row r : store) {
if (r.ageDays > retention.get(r.kind) && !r.legalHold && !r.tombstoned) second++;
}
System.out.println("purged=" + purged + " held-back(u2-order, legal hold)=1 resweep-new-purges=" + second + " (idempotent)");
// Aggregates: suppress small cells (k=5 teaching threshold) — aggregates are NOT automatically anonymous.
Map<String, Integer> cells = new LinkedHashMap<>();
cells.put("zoneX-mobile", 12);
cells.put("zoneX-desktop", 3);
for (var e : cells.entrySet()) {
System.out.println("aggregate cell " + e.getKey() + " n=" + e.getValue()
+ (e.getValue() < 5 ? " -> SUPPRESSED (re-identifiable)" : " -> publishable"));
}
// Restore: a 180-day-old backup replays through the tombstones.
List<String> backup = List.of("u1-order", "u3-click", "u5-profile");
int skipped = 0, live = 0;
for (String id : backup) {
if (tombstones.contains(id)) {
System.out.println("restore skips tombstoned " + id);
skipped++;
} else live++;
}
System.out.println("restore: skipped-tombstoned=" + skipped + " replayed-live=" + live + " (u5-profile) resurrected-deleted=0");
// Breach exposure from the actual inventory: precise location was never collected.
System.out.println("breach exposure: orders/profiles present per table; precise-location=NEVER COLLECTED -> cannot leak");
// Audit log carries hashes, never raw PII.
System.out.println("audit: purge#1 ids=[hash(u1-order),hash(u3-click)] actor=retention-job (hashes, no raw PII)");
System.out.println("OK: purge idempotent, hold respected, restore clean, small cells suppressed.");
}
}
اجرا: javac PurgePolicyDemo.java && java PurgePolicyDemo — فقط استاندارد جاوا، فوری و قطعی.
خروجی مورد انتظار: ۲ پاک (u1-order و u3-click)، ۱ نگهداشته (u2-order) و sweep دوباره ۰؛ سلول ۱۲تایی منتشرشدنی و ۳تایی suppressed؛ restore از ۲ tombstone گذشت و ۱ زنده را برگرداند و ۰ را زنده کرد. (خروجی واقعی همین محیط)
Run: javac PurgePolicyDemo.java && java PurgePolicyDemo — stdlib Java only, instant, deterministic.
Expected output: Purged 2 (u1-order, u3-click), held 1 (u2-order), resweep 0; cell n=12 publishable, n=3 suppressed; restore skips 2 tombstoned, replays 1 live, resurrects 0. (actual output of this environment)
آزمون صحت و معیار عملیاتیCorrectness checks and operational criteria
invariantهای per-sweep: sweep دوباره ۰ پاک، restore دروازهدار ۰ زندهشده، ردیفهای held از sweep و restore سالم، هیچ سلول منتشرشده زیر k. معیارهای عملیاتی: lag ی sweep بعد از نگهداری، سن قدیمیترین tombstone منقضینشده و فهرست بازبینی عقبافتاده hold — روی هر سه هشدار بده.
Invariants per sweep: resweep purges 0, gated restore resurrects 0, held rows survive sweep and restore, no published cell below k. Operational metrics: sweep lag past retention, age of the oldest unexpired tombstone, hold-review overdue list — alert on any of the three.
پاسخ سؤالهای پیگیریFollow-up answers
پیگیری (استف): برگرداندن بکاپ ششماهه چطور از زنده شدن کاربرهای حذفشده جلوگیری میکند؟Follow-up (Staff): How does restoring a six-month-old backup avoid resurrecting deleted users?
از میان tombstoneها بازپخش میکند: u1 و u3 رد میشوند (skipped=2) و u5 بهعنوان زنده برمیگردد و resurrected=0 — دقیقاً آزمون restore دمو. بکاپهای قدیمیتر از نگهداری اصلاً به بازپخش نمیرسند: نابود میشوند و رکورد نابودی مدرک است. restoreای که مشورت را دور بزند همان باگ زنده کردن است که با assert کردن resurrected=0 در هر تمرین گرفته میشود.
It replays through the tombstones: u1 and u3 are skipped (skipped=2), u5 returns as live, resurrected=0 — exactly the demo's restore probe. Backups older than retention never reach the replay at all: they are destroyed, and the destruction record is the proof. A restore that bypasses the consult is the resurrection bug, caught by asserting resurrected=0 on every drill.
پیگیری (سینیور): نگهداری میگوید پاک کن و hold حقوقی میگوید نگه دار؛ کدام میبرد و کجا ثبت میشود؟Follow-up (Senior): Retention says delete, a legal hold says keep. Which wins, and where is that recorded?
hold همیشه میبرد: sweeper ردیفهای با hold زنده را رد میکند هرچقدر هم منقضی، و ردیفهای با بازبینی عقبافتاده را هم تا انسان دوباره تاریخ بزند رد میکند. نگهداری برنامه است؛ hold دستور است — برنامه به دستور راه میدهد و رد شدن در ممیزی ثبت میشود.
The hold wins, every time: the sweeper refuses rows with a live hold no matter how expired, and rows with an overdue hold review are refused too until a human re-dates them. Retention is a schedule; a hold is an order — schedules yield to orders, and the refusal is audit-logged.
پیگیری (سینیور): بازبینی تقلب شش ماه بعد پروفایل پاکشده را میخواهد؛ برمیگردانیاش؟Follow-up (Senior): Fraud review needs a purged profile six months later. Do you bring it back?
پروفایل خام را پس نمیگیرد: نگه داشتن داده شخصی «شاید لازم شد» همان بیشینهسازی است که سیاست برای منعش هست. راههای قانونی: جمعآوری دوباره با مقصود و مبنای تازه، پرسش از aggregate نگهداشتهشدهای که جواب را دارد، یا hold تازه با matter و مالک — «شاید بعداً مفید» هرگز hold نیست.
It does not get the raw profile back: keeping personal data 'just in case' is the maximization the policy exists to forbid. The lawful paths are re-collecting with fresh purpose and basis, querying a held aggregate that already answers the question, or a new hold with matter and owner — 'maybe useful later' is never a hold.
اشتباهات رایجCommon mistakes
- نقل روزهای نمونه نگهداری بهعنوان الزام قانونی («مقرره میگوید سفارشها ۳۶۵ روز»). روزها اعداد آموزشی نمایشیاند؛ مهلتهای واقعی per-product و per-jurisdiction تفسیر حقوقی میخواهند.
- خودکار ناشناس دانستن aggregateها. سلول ۳تایی بازشناسایی میکند؛ suppression در k و اجرای دوباره موقع اصلاح و فهرست سلول suppressed سازوکارند — نه کلمه aggregate.
- فقط ردیف زنده را پاک کردن و اسمش را حذف گذاشتن. کش، ایندکس، لاگ، بکاپ، عصارههای آموزش و ردهای ممیزی هرکدام سازوکار خودشان را میخواهند — کپی پاکنشده ردیف رخنه آینده است.
- Quoting the sample retention days as legal requirements ('the regulation says 365 days for orders'). The days are illustrative teaching numbers; real deadlines need legal interpretation per product and jurisdiction.
- Treating aggregates as automatically anonymous. A cell of 3 re-identifies; suppression at k, rerun on corrections, and a suppressed-cell list are the mechanism — not the word 'aggregate'.
- Purging only the live row and calling it deletion. Caches, indexes, the log, backups, training extracts and audit trails each need their own mechanism — an undeleted copy is a future breach row.
منابع:Sources: European Commission · GDPR principles · Atlassian · engineering interview handbook