Founding as a Developer — Validate Before You Build
Pin Definitions Down in Code and Recount the Metrics
Goal
From 16 weeks of "Moanote" product records, build functions that calculate DAU, WAU, MAU, stickiness, weekly sharing users, and the 7-day activation rate exactly as defined, and measure how much the numbers swing when the definition changes.
Why it matters
A metric is a number only when its definition is written down. If just one of internal accounts, time zone, duplicates, or the criterion for active differs, the same records produce an entirely different trend. In the early days of a startup you decide investment and hiring with these numbers, so the habit of pinning the definition down in code and recomputing to get the same value is the foundation of product judgment.
Materials and definitions
/opt/fixtures/founder/product/users.csv—user_id,signup_at,is_internal(times are UTC, ending in Z)/opt/fixtures/founder/product/events.csv—user_id,ts,event(event: session_start · create_doc · share_doc · invite_sent · upgrade)- The business time zone is Asia/Seoul (UTC+9). Dates are Seoul dates, weeks start at Monday 00:00 Seoul time, and week 0 is 2026-03-02 (weeks 0–15).
- Internal accounts (is_internal=1) are excluded from every metric. Active =
session_startat least once in that period. Count by number of people. - Every function takes the materials directory path as its first argument (the grader calls it with other materials too). A date argument is a string like
"2026-06-14".
Steps
- In
/root/founder/metrics/summary.json, write an overview of the materials:users(the total number of users),internal_users,events(the total number of event lines), andevent_counts(an object of line counts by event type). - In
/root/founder/metrics/metrics.py, createdau(fix, day)— the number of external users (an integer) with a session_start on the Seoul dateday. - In
/root/founder/metrics/internal.json, write for 2026-06-14dau_all(including internal accounts),dau_external(excluding them), andinflation_pct(= (dau_all − dau_external) / dau_external × 100, rounded to two decimal places). - In
metrics.py, addwau(fix, day)andmau(fix, day)— the number of active external users within the past 7 and 28 days, includingday. - In
metrics.py, addstickiness(fix, day)— the average DAU over the 28 days up today÷mau(fix, day), rounded to four decimal places. - In
/root/founder/metrics/definitions.json, write the WAU as of 2026-06-14 under three definitions:session(session_start),any_event(regardless of event type), andcore(share_doc). All are external users, counted by number of people. - In
metrics.py, addweekly_sharers(fix)— return, for each of weeks 0–15, "the number of external users who did share_doc that week" as a dictionary with string week keys, like{"0": n, "1": n, ...}. - In
metrics.py, addactivation(fix)(among external users who signed up in weeks 0–11, the share who did create_doc within 7×24 hours of the signup time →{"signups": n, "activated": m, "rate": 0.0000}), and in/root/founder/metrics/report.jsongather and write for 2026-06-14dau,wau,mau,stickiness, plusactivation_rate,north_star_peak_week(the week with the most weekly sharing users, an integer), andnorth_star_week15(the value for week 15).
Notes
- Seoul date:
datetime.strptime(ts, "%Y-%m-%dT%H:%M:%SZ").replace(tzinfo=timezone.utc).astimezone(ZoneInfo("Asia/Seoul")).date() - Week number:
(서울시각 - datetime(2026, 3, 2, tzinfo=서울)).days // 7(the Korean placeholders are the Seoul time and the Seoul time zone) - Common mistakes: grouping by UTC date, writing the event count as the number of people, not excluding internal accounts, counting MAU with 30 days or a calendar month, and dividing stickiness by a single day's DAU.
- The standard library alone (csv, datetime, zoneinfo, collections) is enough. It is also fine to check with the sqlite3 CLI.
Count the materials first
In /root/founder/metrics/summary.json, write users, internal_users, events, and event_counts.
Read the two files with csv.DictReader and count the event types with collections.Counter. is_internal is the string "1".
DAU — Seoul date, external users, number of people
In /root/founder/metrics/metrics.py, create dau(fix, day). It returns the number of external users with a session_start on the Seoul date day.
Convert the UTC time to Asia/Seoul, group by .date(), gather the user ids into a set, and count its size. Filter out internal accounts with is_internal in users.csv.
How much do internal accounts inflate the metric
In /root/founder/metrics/internal.json, write dau_all, dau_external, and inflation_pct for 2026-06-14.
On the same day and with the same definition (session_start), change only whether internal accounts are included and count twice. The denominator of the ratio is the DAU of external users.
WAU and MAU — 7 and 28 days including the reference day
Add wau(fix, day) and mau(fix, day) to metrics.py. They return the number of active external users within the past 7 and 28 days, including day.
Build the active set for each date and count the size of the union of day, day-1, …, day-6 (or -27). It is not a calendar month or 30 days.
Stickiness — 28-day average DAU ÷ MAU
Add stickiness(fix, day) to metrics.py. Divide the average DAU over the 28 days up to day by mau(fix, day) and round to four decimal places.
If you divide by that single day's DAU, it swings with the weekday. Use the average you get by adding up the DAU of each of the 28 days and dividing by 28.
Change only the definition of active and count the same window
In /root/founder/metrics/definitions.json, write the number of external users in the 7-day window as of 2026-06-14 under three definitions: session, any_event, and core (share_doc).
Leave the window and the user filter as they are and change only the event type you count. any_event does not discriminate by event type.
A North Star candidate — weekly sharing users
Add weekly_sharers(fix) to metrics.py. For each of weeks 0–15, return the number of external users who did share_doc as a dictionary with string week keys.
The week number is (Seoul time − 2026-03-02 00:00 Seoul).days // 7. Fill in all 16 keys, using 0 for weeks with no events.
The activation rate and a one-page report
Add activation(fix) to metrics.py, and gather dau, wau, mau, stickiness, activation_rate, north_star_peak_week, and north_star_week15 into /root/founder/metrics/report.json.
Activation is the first create_doc within 7×24 hours (timedelta(days=7)) of the signup time, not by calendar date. The population is external users who signed up in weeks 0–11. If several weeks tie for the most, pick the earlier week.