2026-07-26 19:58:18 +02:00
|
|
|
# retoor <retoor@molodetz.nl>
|
|
|
|
|
|
|
|
|
|
def test_primary_admin_ignores_accounts_without_a_signup_time(local_db):
|
|
|
|
|
from devplacepy.database import get_primary_admin_uid, invalidate_admins_cache
|
|
|
|
|
|
|
|
|
|
users = local_db["users"]
|
|
|
|
|
users.insert(
|
|
|
|
|
{
|
|
|
|
|
"uid": "pa-real",
|
|
|
|
|
"username": "pa-real",
|
|
|
|
|
"role": "Admin",
|
Fix circular import, primary-admin NULL trap, and add gateway quota reset
Restores a working import graph and closes two data-correctness bugs, plus
adds a reset for the AI gateway's rolling 24h spend.
Circular import: database/__init__ -> engagement -> content -> utils ->
database made the package unimportable. get_project_devlog moves out of
database/engagement.py into content.py, where enrich_items already lives.
Primary administrator: _can_hold_primary_admin read is_active with
bool(row.get("is_active")), so an admin row whose is_active column is SQL
NULL (any row predating the column) was treated as deactivated and skipped.
Every other site defaults an unknown is_active to active; this one now does
too.
Profile JSON: xp_next_level and xp_progress_pct were computed but only put on
the top-level context, never on profile_user, so they serialised as null even
though UserOut declares them and the API docs document them as embedded there.
Gateway quota reset: a cap previously lifted only with the passage of time.
quota.reset upserts a watermark row into gateway_quota_resets, scoped by the
same three nullable dimensions as a quota rule, and spent_24h sums from
max(24h cutoff, watermark). No ledger row is deleted, so the cost analytics on
/admin/ai-usage stay intact. Reaches every surface: POST
/admin/gateway/quota-resets, a per-rule Reset spend button, the Devii tool
gateway_quota_reset (confirm-gated), devplace gateway quota reset, and the API
docs. Admin's Reset all quotas now stamps a global gateway watermark too,
which is what a caller stuck on "AI gateway daily quota exceeded" needed.
Startup: _backfill_gamification swept every xp=0 user on every boot in every
worker and could never converge, since a user with no content earns no XP.
It now intersects pending users with _milestone_candidates(). db.tables is a
live reflection, so it is hoisted out of the loops that probed it per row.
Docker: the dependency layer now depends on pyproject.toml only, so a source
edit no longer reinstalls every dependency and re-downloads Chromium.
Adds start_interval so the healthcheck probes during the start period, and a
docker-reload target, since docker-up does not restart an unchanged container.
Adds events.md, the audit event catalogue that README, CLAUDE.md, the quiz
docs and the tooling all referenced but which never existed: 288 keys across
28 categories, including the families built from a variable at the call site.
Test fixes: both devlog helpers dated post 0 as the newest while the tests
assumed post 2 was; a profile login posted username= to a form that takes
email=; a devlog assertion matched six buttons under strict mode; and the
primary-admin tests seeded founders newer than the back-dated fixture admin,
so they only passed without the api tier.
Full suite: 2989 passed, 1 skipped.
2026-07-27 11:17:48 +02:00
|
|
|
"created_at": "1990-01-01T00:00:00",
|
2026-07-26 19:58:18 +02:00
|
|
|
"deleted_at": None,
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
users.insert(
|
|
|
|
|
{
|
|
|
|
|
"uid": "pa-null",
|
|
|
|
|
"username": "pa-null",
|
|
|
|
|
"role": "Admin",
|
|
|
|
|
"created_at": None,
|
|
|
|
|
"deleted_at": None,
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
users.insert(
|
|
|
|
|
{
|
|
|
|
|
"uid": "pa-blank",
|
|
|
|
|
"username": "pa-blank",
|
|
|
|
|
"role": "Admin",
|
|
|
|
|
"created_at": "",
|
|
|
|
|
"deleted_at": None,
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
invalidate_admins_cache()
|
|
|
|
|
try:
|
|
|
|
|
assert get_primary_admin_uid() == "pa-real"
|
|
|
|
|
finally:
|
|
|
|
|
for uid in ("pa-real", "pa-null", "pa-blank"):
|
|
|
|
|
users.delete(uid=uid)
|
|
|
|
|
invalidate_admins_cache()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_primary_admin_skips_deactivated_and_deleted_founders(local_db):
|
|
|
|
|
from devplacepy.database import get_primary_admin_uid, invalidate_admins_cache
|
|
|
|
|
|
|
|
|
|
users = local_db["users"]
|
|
|
|
|
seeded = [
|
Fix circular import, primary-admin NULL trap, and add gateway quota reset
Restores a working import graph and closes two data-correctness bugs, plus
adds a reset for the AI gateway's rolling 24h spend.
Circular import: database/__init__ -> engagement -> content -> utils ->
database made the package unimportable. get_project_devlog moves out of
database/engagement.py into content.py, where enrich_items already lives.
Primary administrator: _can_hold_primary_admin read is_active with
bool(row.get("is_active")), so an admin row whose is_active column is SQL
NULL (any row predating the column) was treated as deactivated and skipped.
Every other site defaults an unknown is_active to active; this one now does
too.
Profile JSON: xp_next_level and xp_progress_pct were computed but only put on
the top-level context, never on profile_user, so they serialised as null even
though UserOut declares them and the API docs document them as embedded there.
Gateway quota reset: a cap previously lifted only with the passage of time.
quota.reset upserts a watermark row into gateway_quota_resets, scoped by the
same three nullable dimensions as a quota rule, and spent_24h sums from
max(24h cutoff, watermark). No ledger row is deleted, so the cost analytics on
/admin/ai-usage stay intact. Reaches every surface: POST
/admin/gateway/quota-resets, a per-rule Reset spend button, the Devii tool
gateway_quota_reset (confirm-gated), devplace gateway quota reset, and the API
docs. Admin's Reset all quotas now stamps a global gateway watermark too,
which is what a caller stuck on "AI gateway daily quota exceeded" needed.
Startup: _backfill_gamification swept every xp=0 user on every boot in every
worker and could never converge, since a user with no content earns no XP.
It now intersects pending users with _milestone_candidates(). db.tables is a
live reflection, so it is hoisted out of the loops that probed it per row.
Docker: the dependency layer now depends on pyproject.toml only, so a source
edit no longer reinstalls every dependency and re-downloads Chromium.
Adds start_interval so the healthcheck probes during the start period, and a
docker-reload target, since docker-up does not restart an unchanged container.
Adds events.md, the audit event catalogue that README, CLAUDE.md, the quiz
docs and the tooling all referenced but which never existed: 288 keys across
28 categories, including the families built from a variable at the call site.
Test fixes: both devlog helpers dated post 0 as the newest while the tests
assumed post 2 was; a profile login posted username= to a form that takes
email=; a devlog assertion matched six buttons under strict mode; and the
primary-admin tests seeded founders newer than the back-dated fixture admin,
so they only passed without the api tier.
Full suite: 2989 passed, 1 skipped.
2026-07-27 11:17:48 +02:00
|
|
|
("pa-deleted", "1991-01-01T00:00:00", True, "2020-01-01T00:00:00"),
|
|
|
|
|
("pa-inactive", "1992-01-01T00:00:00", False, None),
|
|
|
|
|
("pa-usable", "1993-01-01T00:00:00", True, None),
|
2026-07-26 19:58:18 +02:00
|
|
|
]
|
|
|
|
|
for uid, created_at, active, deleted_at in seeded:
|
|
|
|
|
users.insert(
|
|
|
|
|
{
|
|
|
|
|
"uid": uid,
|
|
|
|
|
"username": uid,
|
|
|
|
|
"role": "Admin",
|
|
|
|
|
"created_at": created_at,
|
|
|
|
|
"is_active": active,
|
|
|
|
|
"deleted_at": deleted_at,
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
invalidate_admins_cache()
|
|
|
|
|
try:
|
|
|
|
|
assert get_primary_admin_uid() == "pa-usable"
|
|
|
|
|
finally:
|
|
|
|
|
for uid, _, _, _ in seeded:
|
|
|
|
|
users.delete(uid=uid)
|
|
|
|
|
invalidate_admins_cache()
|