Rotation-tick pin-precheck reports DRIFT versus the prior tick post-UI pin:
Saved to ~/SOLUTION.md. Here is the solution:
Rotation-tick pin-precheck reports DRIFT versus the prior tick post-UI pin:
| metric | prior pin | precheck | delta |
|---|---|---|---|
| users | 47 | 50 | +3 |
| quizzes | 32426 | 32558 | +132 |
Halt rule: do not decrement the analytics floor and do not mutate the demo DB. Triage is read-only until the final live re-pin.
The divergence is a test-suite seeding artifact, not external/user growth. Two seeding etiologies produce the same count drift and the same fixture e-mail fingerprint (display-test-*, dogfood011-*, sync-test@). They are separated by the age profile of the users table, specifically min(created_at).
A seeding run inside the prior tick window dropped/recreated the table and inserted the deterministic fixture set. Every row, including the oldest, is minutes old.
- min(created_at) on users is minutes old (inside the prior tick window).
- max(created_at) is fresh and close to min.
- Counts change wholesale because the fixture generator's cardinality changed.
- The 4 role logins must still pass: the demo path survives reseed even though row identities changed.
The suite appended fixtures to a long-lived demo dataset. Pre-existing rows survive.
- min(created_at) is OLD (days/weeks — the original demo tenants).
- max(created_at) is fresh (minutes).
- Counts ratchet upward every tick; parent_links must be stable.
- Same fixture e-mail fingerprint as Class A.
SELECT min(created_at) AS oldest, max(created_at) AS newest FROM users;
The demo DB genuinely contains the new rows; the floor stored by the pin is stale, not wrong. Subtracting the delta would fabricate a number the demo DB does not contain and re-create drift on the next tick. The correct action is to re-derive the floor from the live, frozen, self-excluded count. The demo DB is never written to make the pin match.
All steps use a read-only DB role and a BEGIN READ ONLY transaction. The only write is the analytics pin, which lives outside the demo DB.
# ---- triage configuration (read-only) ----
export DEMO_DSN="postgresql://eduos_ro@demo-db:5432/eduos_demo"
export ANALYTICS_API="https://analytics.internal/eduos"
export SELF_EMAIL="<email>" # this triage/rotation identity
export ROTATION_CMD="eduos-e2e-tester --profile demo --rotation"
export TICK_WINDOW_SEC=3600 # prior tick window
psql "$DEMO_DSN" -v ON_ERROR_STOP=1 -P pager=off \
-v self_email="$SELF_EMAIL" <<'SQL'
BEGIN READ ONLY;
SET LOCAL statement_timeout = '15s';
-- DISCRIMINATOR: age profile of users
SELECT
count(*) AS n,
min(created_at) AS oldest,
max(created_at) AS newest,
date_trunc('second', now() - min(created_at)) AS oldest_age,
date_trunc('second', now() - max(created_at)) AS newest_age
FROM users;
-- FIXTURE FINGERPRINT (proves test-suite origin)
SELECT
count(*) FILTER (WHERE email LIKE 'display-test-%') AS display_test,
count(*) FILTER (WHERE email LIKE 'dogfood011-%') AS dogfood011,
count(*) FILTER (WHERE email LIKE 'sync-test@%') AS sync_test,
count(*) AS total
FROM users;
-- PARALLEL EVIDENCE: quizzes age profile
SELECT count(*) AS n, min(created_at) AS oldest, max(created_at) AS newest
FROM quizzes;
COMMIT;
SQL
Classify (machine-readable):
OLDEST_AGE_SEC=$(psql "$DEMO_DSN" -Atc \
"SELECT extract(epoch FROM now()-min(created_at))::bigint FROM users")
if [ "$OLDEST_AGE_SEC" -lt "$TICK_WINDOW_SEC" ]; then
CLASS=reseed # Class A
else
CLASS=incremental # Class B
fi
echo "class=$CLASS oldest_age=${OLDEST_AGE_SEC}s"
The triage/rotation login is itself a user row. Count the live demo population only after excluding self and the seeding fixtures, otherwise the new floor is inflated by the probe.
-- live_users: replace :self_email with SELF_EMAIL
SELECT count(*) AS live_users
FROM users
WHERE email NOT LIKE 'display-test-%'
AND email NOT LIKE 'dogfood011-%'
AND email NOT LIKE 'sync-test@%'
AND email <> :'self_email';
-- live_quizzes: exclude fixtures owned by excluded users
SELECT count(*) AS live_quizzes
FROM quizzes q
WHERE NOT EXISTS (
SELECT 1 FROM users u
WHERE u.id = q.owner_id
AND (u.email LIKE 'display-test-%'
OR u.email LIKE 'dogfood011-%'
OR u.email LIKE 'sync-test@%'
OR u.email = :'self_email')
);
Prove no seeding/rotation writer is still running. Any change aborts the re-pin.
prev=""; frozen=1
for i in 1 2 3 4; do
cur=$(psql "$DEMO_DSN" -Atc \
"SELECT count(*) FROM users
WHERE email NOT LIKE 'display-test-%'
AND email NOT LIKE 'dogfood011-%'
AND email NOT LIKE 'sync-test@%'
AND email <> '$SELF_EMAIL'")
echo "sample $i/4 users=$cur"
[ -n "$prev" ] && [ "$cur" != "$prev" ] && frozen=0
prev="$cur"
[ "$i" -lt 4 ] && sleep 30
done
[ "$frozen" -eq 1 ] || { echo "NOT FROZEN — abort re-pin (ongoing writer)"; exit 2; }
LIVE_USERS="$prev"
echo "FROZEN 4/4 users=$LIVE_USERS"
Requirement for both classes: 4/4 FROZEN.
Detect the seed-idempotency off-by-one on the boundary row and probe for a novel 404 introduced by the reseed (a fixture route that used to resolve now returns 404).
# boundary rows: inspect the newest / oldest fixture edge
psql "$DEMO_DSN" -P pager=off -c \
"SELECT id, email, created_at FROM users ORDER BY created_at DESC LIMIT 1;"
psql "$DEMO_DSN" -P pager=off -c \
"SELECT id, email, created_at FROM users ORDER BY created_at ASC LIMIT 1;"
# off-by-one check on the max quiz id: max(id) must be 200, max(id)+1 must be 404
MAX_ID=$(psql "$DEMO_DSN" -Atc "SELECT max(id) FROM quizzes")
for id in "$MAX_ID" "$((MAX_ID + 1))"; do
code=$(curl -s -o /dev/null -w '%{http_code}' "$DEMO_API/quizzes/$id")
echo "quizzes/$id -> $code"
done
# Expected: max(id) -> 200, max(id)+1 -> 404.
# A 404 on a previously-200 fixture id is the "novel 404": record it and attach to the
# incident. It does not block re-pin; it is evidence the reseed renamed/dropped identities.
Run the rotation battery; its four role logins (admin, teacher, student, parent) verify the demo path survived the reseed/incremental seeding. Only a 4/4 pass authorizes the re-pin.
$ROTATION_CMD --roles admin,teacher,student,parent --json > /tmp/rotation.json
# Parse pass count (adjust to the battery's JSON schema)
PASS=$(python3 -c "import json;print(sum(r['ok'] for r in json.load(open('/tmp/rotation.json'))['roles']))")
[ "$PASS" -eq 4 ] || { echo "rotation battery $PASS/4 — abort re-pin"; exit 3; }
echo "rotation battery 4/4 OK"
Re-pin the analytics floor to the live, frozen, self-excluded count — in the analytics store, never in the demo DB:
curl -sS -X POST "$ANALYTICS_API/pins" \
-H 'Content-Type: application/json' \
-d "{\"tick\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",
\"class\":\"$CLASS\",
\"floor\":{\"users\":$LIVE_USERS,\"quizzes\":$LIVE_QUIZZES},
\"demo_db_mutated\":false,
\"novel_404\":[\"$NOVEL_404_IDS\"]}"
| Observation | Class | Decrement? | parent_links | Stability | Re-pin path |
|---|---|---|---|---|---|
min(created_at) minutes old |
A reseed | No | rebuilt by seed | 4/4 FROZEN | rotation battery → live count |
min(created_at) old, max(created_at) fresh |
B incremental | No | must be stable | 4/4 FROZEN | rotation battery → live count |
Both classes converge on the same re-pin path; only the root-cause label and the parent_links evidence differ. The new analytics floor is always the live count.
Run these after the pin. All must pass.
# (1) class was determined by the reseed signature, not by the delta
psql "$DEMO_DSN" -Atc "SELECT (now()-min(created_at)) < interval '1 hour' FROM users" \
| grep -qx t && echo "A: reseed" || echo "B: incremental"
# (2) self + fixtures excluded from the pinned floor
psql "$DEMO_DSN" -Atc "SELECT count(*) FROM users
WHERE email LIKE 'display-test-%' OR email LIKE 'dogfood011-%'
OR email LIKE 'sync-test@%' OR email = '$SELF_EMAIL'"
# -> these rows exist in the DB and are NOT part of the floor
# (3) stability probe was FROZEN 4/4 (rerun; must equal the pinned floor)
for i in 1 2 3 4; do
psql "$DEMO_DSN" -Atc "SELECT count(*) FROM users
WHERE email NOT LIKE 'display-test-%' AND email NOT LIKE 'dogfood011-%'
AND email NOT LIKE 'sync-test@%' AND email <> '$SELF_EMAIL'"
sleep 30
done
# (4) rotation battery 4/4 role logins
python3 -c "import json;print(json.load(open('/tmp/rotation.json')))"
# (5) new analytics floor == live count
curl -sS "$ANALYTICS_API/pins/current" | python3 -m json.tool
# floor.users == LIVE_USERS and floor.quizzes == LIVE_QUIZZES
# (6) demo DB was NOT mutated: pre/post row counts identical
psql "$DEMO_DSN" -Atc "SELECT (SELECT count(*) FROM users), (SELECT count(*) FROM quizzes)"
# same values before and after the pin; no UPDATE/DELETE was issued
# (7) Class B only: parent_links stable across the tick
psql "$DEMO_DSN" -Atc "SELECT count(*) FROM parent_links" # unchanged vs prior tick
# (8) novel 404 recorded and attached to the incident
echo "$NOVEL_404_IDS" # non-empty only if a fixture route regressed
min(created_at) (Class A or B).display-test-*, dogfood011-*, sync-test@) excluded.parent_links stable.Never mutate the demo DB to re-pin.
Note on verification limits: the provided environment has no reachable EduOS demo DB (no local Postgres containing it, and eduos-hermes/cube-root is unresolvable with no SSH key), so the commands above are the executable runbook rather than captured live output. Replace the export values with the real rotation host's read-only DSN, API base, and battery JSON schema; the logic and discrimination criterion are exact and self-contained.
# Evidence - Problem class: eduos-demo-db-reseed-vs-cumulative-seeding-drift-discrimination - Model: openrouter/deepseek/deepseek-v4.1-flash - Solved: 2026-09-14T00:41:23.039Z - Verification: solution produced by pi in sandbox; see signatures.json
{"description": "EduOS rotation-tick pin-precheck DRIFT triage: demo-DB counts diverge from the prior tick post-UI pin (users 47->50, quizzes 32426->32558). Discriminate reseed vs the known cumulative-seeding growth class by the reseed signature: SELECT min(created_at) FROM users. If the OLDEST user row is minutes old, the whole table was recreated by a test-suite seeding run inside the PRIOR tick window (fixture emails display-test-*/dogfood011-*/sync-test@) - not external growth. Remedy order t462: read-only root cause, exclude self, stability probe 4 samples x 30s (FROZEN), off-by-one discover (404 novel), then live re-pin by running the rotation battery whose 4 role logins verify the demo path survived reseed; new analytics floor = live count. If min(created_at) is OLD but the newest row is fresh, it is the incremental display-test class instead: no decrement + parent_links stable + 4/4 frozen, same re-pin path. Never mutate the demo DB to re-pin.", "environment": "", "language": "", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "eduos-demo-db-reseed-vs-cumulative-seeding-drift-discrimination", "provider": "openrouter", "solved_at": "2026-09-14T00:41:23.039Z", "version": ""}Saved to ~/SOLUTION.md. Here is the solution:
Rotation-tick pin-precheck reports DRIFT versus the prior tick post-UI pin:
| metric | prior pin | precheck | delta |
|---|---|---|---|
| users | 47 | 50 | +3 |
| quizzes | 32426 | 32558 | +132 |
Halt rule: do not decrement the analytics floor and do not mutate the demo DB. Triage is read-only until the final live re-pin.
The divergence is a test-suite seeding artifact, not external/user growth. Two seeding etiologies produce the same count drift and the same fixture e-mail fingerprint (display-test-*, dogfood011-*, sync-test@). They are separated by the age profile of the users table, specifically min(created_at).
A seeding run inside the prior tick window dropped/recreated the table and inserted the deterministic fixture set. Every row, including the oldest, is minutes old.
- min(created_at) on users is minutes old (inside the prior tick window).
- max(created_at) is fresh and close to min.
- Counts change wholesale because the fixture generator's cardinality changed.
- The 4 role logins must still pass: the demo path survives reseed even though row identities changed.
The suite appended fixtures to a long-lived demo dataset. Pre-existing rows survive.
- min(created_at) is OLD (days/weeks — the original demo tenants).
- max(created_at) is fresh (minutes).
- Counts ratchet upward every tick; parent_links must be stable.
- Same fixture e-mail fingerprint as Class A.
SELECT min(created_at) AS oldest, max(created_at) AS newest FROM users;
The demo DB genuinely contains the new rows; the floor stored by the pin is stale, not wrong. Subtracting the delta would fabricate a number the demo DB does not contain and re-create drift on the next tick. The correct action is to re-derive the floor from the live, frozen, self-excluded count. The demo DB is never written to make the pin match.
All steps use a read-only DB role and a BEGIN READ ONLY transaction. The only write is the analytics pin, which lives outside the demo DB.
# ---- triage configuration (read-only) ----
export DEMO_DSN="postgresql://eduos_ro@demo-db:5432/eduos_demo"
export ANALYTICS_API="https://analytics.internal/eduos"
export SELF_EMAIL="<email>" # this triage/rotation identity
export ROTATION_CMD="eduos-e2e-tester --profile demo --rotation"
export TICK_WINDOW_SEC=3600 # prior tick window
psql "$DEMO_DSN" -v ON_ERROR_STOP=1 -P pager=off \
-v self_email="$SELF_EMAIL" <<'SQL'
BEGIN READ ONLY;
SET LOCAL statement_timeout = '15s';
-- DISCRIMINATOR: age profile of users
SELECT
count(*) AS n,
min(created_at) AS oldest,
max(created_at) AS newest,
date_trunc('second', now() - min(created_at)) AS oldest_age,
date_trunc('second', now() - max(created_at)) AS newest_age
FROM users;
-- FIXTURE FINGERPRINT (proves test-suite origin)
SELECT
count(*) FILTER (WHERE email LIKE 'display-test-%') AS display_test,
count(*) FILTER (WHERE email LIKE 'dogfood011-%') AS dogfood011,
count(*) FILTER (WHERE email LIKE 'sync-test@%') AS sync_test,
count(*) AS total
FROM users;
-- PARALLEL EVIDENCE: quizzes age profile
SELECT count(*) AS n, min(created_at) AS oldest, max(created_at) AS newest
FROM quizzes;
COMMIT;
SQL
Classify (machine-readable):
OLDEST_AGE_SEC=$(psql "$DEMO_DSN" -Atc \
"SELECT extract(epoch FROM now()-min(created_at))::bigint FROM users")
if [ "$OLDEST_AGE_SEC" -lt "$TICK_WINDOW_SEC" ]; then
CLASS=reseed # Class A
else
CLASS=incremental # Class B
fi
echo "class=$CLASS oldest_age=${OLDEST_AGE_SEC}s"
The triage/rotation login is itself a user row. Count the live demo population only after excluding self and the seeding fixtures, otherwise the new floor is inflated by the probe.
-- live_users: replace :self_email with SELF_EMAIL
SELECT count(*) AS live_users
FROM users
WHERE email NOT LIKE 'display-test-%'
AND email NOT LIKE 'dogfood011-%'
AND email NOT LIKE 'sync-test@%'
AND email <> :'self_email';
-- live_quizzes: exclude fixtures owned by excluded users
SELECT count(*) AS live_quizzes
FROM quizzes q
WHERE NOT EXISTS (
SELECT 1 FROM users u
WHERE u.id = q.owner_id
AND (u.email LIKE 'display-test-%'
OR u.email LIKE 'dogfood011-%'
OR u.email LIKE 'sync-test@%'
OR u.email = :'self_email')
);
Prove no seeding/rotation writer is still running. Any change aborts the re-pin.
prev=""; frozen=1
for i in 1 2 3 4; do
cur=$(psql "$DEMO_DSN" -Atc \
"SELECT count(*) FROM users
WHERE email NOT LIKE 'display-test-%'
AND email NOT LIKE 'dogfood011-%'
AND email NOT LIKE 'sync-test@%'
AND email <> '$SELF_EMAIL'")
echo "sample $i/4 users=$cur"
[ -n "$prev" ] && [ "$cur" != "$prev" ] && frozen=0
prev="$cur"
[ "$i" -lt 4 ] && sleep 30
done
[ "$frozen" -eq 1 ] || { echo "NOT FROZEN — abort re-pin (ongoing writer)"; exit 2; }
LIVE_USERS="$prev"
echo "FROZEN 4/4 users=$LIVE_USERS"
Requirement for both classes: 4/4 FROZEN.
Detect the seed-idempotency off-by-one on the boundary row and probe for a novel 404 introduced by the reseed (a fixture route that used to resolve now returns 404).
# boundary rows: inspect the newest / oldest fixture edge
psql "$DEMO_DSN" -P pager=off -c \
"SELECT id, email, created_at FROM users ORDER BY created_at DESC LIMIT 1;"
psql "$DEMO_DSN" -P pager=off -c \
"SELECT id, email, created_at FROM users ORDER BY created_at ASC LIMIT 1;"
# off-by-one check on the max quiz id: max(id) must be 200, max(id)+1 must be 404
MAX_ID=$(psql "$DEMO_DSN" -Atc "SELECT max(id) FROM quizzes")
for id in "$MAX_ID" "$((MAX_ID + 1))"; do
code=$(curl -s -o /dev/null -w '%{http_code}' "$DEMO_API/quizzes/$id")
echo "quizzes/$id -> $code"
done
# Expected: max(id) -> 200, max(id)+1 -> 404.
# A 404 on a previously-200 fixture id is the "novel 404": record it and attach to the
# incident. It does not block re-pin; it is evidence the reseed renamed/dropped identities.
Run the rotation battery; its four role logins (admin, teacher, student, parent) verify the demo path survived the reseed/incremental seeding. Only a 4/4 pass authorizes the re-pin.
$ROTATION_CMD --roles admin,teacher,student,parent --json > /tmp/rotation.json
# Parse pass count (adjust to the battery's JSON schema)
PASS=$(python3 -c "import json;print(sum(r['ok'] for r in json.load(open('/tmp/rotation.json'))['roles']))")
[ "$PASS" -eq 4 ] || { echo "rotation battery $PASS/4 — abort re-pin"; exit 3; }
echo "rotation battery 4/4 OK"
Re-pin the analytics floor to the live, frozen, self-excluded count — in the analytics store, never in the demo DB:
curl -sS -X POST "$ANALYTICS_API/pins" \
-H 'Content-Type: application/json' \
-d "{\"tick\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",
\"class\":\"$CLASS\",
\"floor\":{\"users\":$LIVE_USERS,\"quizzes\":$LIVE_QUIZZES},
\"demo_db_mutated\":false,
\"novel_404\":[\"$NOVEL_404_IDS\"]}"
| Observation | Class | Decrement? | parent_links | Stability | Re-pin path |
|---|---|---|---|---|---|
min(created_at) minutes old |
A reseed | No | rebuilt by seed | 4/4 FROZEN | rotation battery → live count |
min(created_at) old, max(created_at) fresh |
B incremental | No | must be stable | 4/4 FROZEN | rotation battery → live count |
Both classes converge on the same re-pin path; only the root-cause label and the parent_links evidence differ. The new analytics floor is always the live count.
Run these after the pin. All must pass.
# (1) class was determined by the reseed signature, not by the delta
psql "$DEMO_DSN" -Atc "SELECT (now()-min(created_at)) < interval '1 hour' FROM users" \
| grep -qx t && echo "A: reseed" || echo "B: incremental"
# (2) self + fixtures excluded from the pinned floor
psql "$DEMO_DSN" -Atc "SELECT count(*) FROM users
WHERE email LIKE 'display-test-%' OR email LIKE 'dogfood011-%'
OR email LIKE 'sync-test@%' OR email = '$SELF_EMAIL'"
# -> these rows exist in the DB and are NOT part of the floor
# (3) stability probe was FROZEN 4/4 (rerun; must equal the pinned floor)
for i in 1 2 3 4; do
psql "$DEMO_DSN" -Atc "SELECT count(*) FROM users
WHERE email NOT LIKE 'display-test-%' AND email NOT LIKE 'dogfood011-%'
AND email NOT LIKE 'sync-test@%' AND email <> '$SELF_EMAIL'"
sleep 30
done
# (4) rotation battery 4/4 role logins
python3 -c "import json;print(json.load(open('/tmp/rotation.json')))"
# (5) new analytics floor == live count
curl -sS "$ANALYTICS_API/pins/current" | python3 -m json.tool
# floor.users == LIVE_USERS and floor.quizzes == LIVE_QUIZZES
# (6) demo DB was NOT mutated: pre/post row counts identical
psql "$DEMO_DSN" -Atc "SELECT (SELECT count(*) FROM users), (SELECT count(*) FROM quizzes)"
# same values before and after the pin; no UPDATE/DELETE was issued
# (7) Class B only: parent_links stable across the tick
psql "$DEMO_DSN" -Atc "SELECT count(*) FROM parent_links" # unchanged vs prior tick
# (8) novel 404 recorded and attached to the incident
echo "$NOVEL_404_IDS" # non-empty only if a fixture route regressed
min(created_at) (Class A or B).display-test-*, dogfood011-*, sync-test@) excluded.parent_links stable.Never mutate the demo DB to re-pin.
Note on verification limits: the provided environment has no reachable EduOS demo DB (no local Postgres containing it, and eduos-hermes/cube-root is unresolvable with no SSH key), so the commands above are the executable runbook rather than captured live output. Replace the export values with the real rotation host's read-only DSN, API base, and battery JSON schema; the logic and discrimination criterion are exact and self-contained.
# Evidence - Problem class: eduos-demo-db-reseed-vs-cumulative-seeding-drift-discrimination - Model: openrouter/deepseek/deepseek-v4.1-flash - Solved: 2026-09-14T00:41:23.039Z - Verification: solution produced by pi in sandbox; see signatures.json
{"description": "EduOS rotation-tick pin-precheck DRIFT triage: demo-DB counts diverge from the prior tick post-UI pin (users 47->50, quizzes 32426->32558). Discriminate reseed vs the known cumulative-seeding growth class by the reseed signature: SELECT min(created_at) FROM users. If the OLDEST user row is minutes old, the whole table was recreated by a test-suite seeding run inside the PRIOR tick window (fixture emails display-test-*/dogfood011-*/sync-test@) - not external growth. Remedy order t462: read-only root cause, exclude self, stability probe 4 samples x 30s (FROZEN), off-by-one discover (404 novel), then live re-pin by running the rotation battery whose 4 role logins verify the demo path survived reseed; new analytics floor = live count. If min(created_at) is OLD but the newest row is fresh, it is the incremental display-test class instead: no decrement + parent_links stable + 4/4 frozen, same re-pin path. Never mutate the demo DB to re-pin.", "environment": "", "language": "", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "eduos-demo-db-reseed-vs-cumulative-seeding-drift-discrimination", "provider": "openrouter", "solved_at": "2026-09-14T00:41:23.039Z", "version": ""}