Skip to content

docs(admin): fix the 3× stale-age rules — wrong threshold, wrong timeline - #8

Merged
MrAlders0n merged 2 commits into
mainfrom
docs/fix-stale-age-3x-rules
Aug 2, 2026
Merged

docs(admin): fix the 3× stale-age rules — wrong threshold, wrong timeline#8
MrAlders0n merged 2 commits into
mainfrom
docs/fix-stale-age-3x-rules

Conversation

@MrAlders0n

Copy link
Copy Markdown
Contributor

Follow-up to #7. This correction was pushed to that branch a few minutes after it was merged, so it missed the merge and the incorrect text is currently live on the site.

What's wrong on main right now

| 72 hours (3×) | If it has a colliding ID, it becomes eligible for automatic deletion. If it is Pending, it is auto-approved (if still being heard) or deleted (if not). |

Three problems, all from treating the two 3× routines as one rule.

1. Wrong threshold. The approve/delete branch tests last_heard against the stale age, not 3× (repeaters_cleanup.php:249):

UPDATE repeaters SET enabled = 1 WHERE enabled = 4
  AND created_at  < :pendCutoff   -- 3× stale: has it existed long enough to judge?
  AND last_heard >= :staleCutoff  -- 1× stale: is it alive right now?

3× (on created_at) decides when a pending record is judged; 1× (on last_heard) decides which way. The docs collapsed both into "3×".

2. Wrong timeline. That table's premise is "a repeater that stops adverting at day 0." Under that premise a pending repeater can only ever be deleted — approval requires having been heard within the last 24h. So the row offered a branch with one unreachable side, which is what made it read as nonsense. Pending resolution keys off the record's creation date, not off silence, so it now lives in its own section outside that table.

3. Overstated the duplicate rule. "Becomes eligible for automatic deletion" implies silence alone is enough. It isn't — the delete only fires when another repeater still shares the ID prefix. A silent repeater with a unique ID is untouched and just continues toward Inactive.

Also adds

The survivor repair, which was missing from the docs entirely (repeaters_cleanup.php:224-238): when the stale twin is deleted and exactly one other repeater shared that ID, the survivor is restored from Excluded to Active and given the clean ID back. Worth documenting, since it means some Excluded repeaters recover with no admin action.

Cross-references in the Repeaters tab status list and the New Repeaters Enter Pending State setting updated to match.

🤖 Generated with Claude Code

https://claude.ai/code/session_01KojjSrgSQQJW7Z8b3eakEA

MrAlders0n and others added 2 commits August 2, 2026 08:10
…line

Review caught the lifecycle table putting pending-repeater resolution in a
row it can't belong to. Two errors, both from treating the two 3x routines
as one rule.

Threshold: the approve/delete branch tests last_heard against 1x the stale
age, not 3x (repeaters_cleanup.php:249). The 3x check is on created_at and
only decides WHEN a pending record is judged; 1x decides which way it goes.
The docs collapsed both into "3x".

Timeline: the table's premise is "a repeater that stops adverting at day 0",
under which a pending repeater can only ever be deleted — approval requires
being heard within the last 24h. So the row offered a branch with one
unreachable side. Pending runs on the record's creation date, not on
silence, so it now sits in its own section outside that table.

Also corrects the duplicate row, which implied silence alone makes a
repeater "eligible for deletion". It doesn't — the delete only fires when
another repeater still shares the ID prefix; a unique ID is untouched. And
documents the survivor repair that was missing entirely: the surviving
repeater is restored from Excluded to Active with the clean ID, so a
collision blocking a legitimate repeater resolves itself.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KojjSrgSQQJW7Z8b3eakEA
…mers

Review caught the Repeater Inactive After example claiming a repeater
"only heard when someone drives past every few weeks" stays on the map
longer with a raised timer. Wardriving has no such effect.

repeaters.last_heard has exactly one writer: api.php:1152, the MQTT
ingestion path, from repeater adverts. wardrive-api.php never touches it —
its only writes to the repeaters table are multibyte_capable flags
(:2493, :2510), which touch neither last_heard nor enabled. So a wardriver
hearing a repeater records and associates the pings but leaves the
lifecycle clock untouched: it still goes stale, still goes Inactive, still
gets purged on the schedule it was already on. Return-to-Active is
advert-only too, via the enabled CASE in the same UPSERT.

The old example had it backwards on the one axis an admin would act on,
and would have sent someone raising a timer when their actual problem is
observer coverage. Adds an explicit definition of "heard" up front, fixes
the example, and flags the failure mode the distinction creates: a
repeater transmitting fine but out of observer range ages out regardless,
and enabling auto-delete in a region with patchy observer coverage will
permanently delete live repeaters.

Ghost Retention is unaffected — ghosts genuinely are wardrive-discovery
driven, on a separate table. Noted as the exception.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KojjSrgSQQJW7Z8b3eakEA
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant