Phase 9: Map voting + positional fairness monitoring - verify existing implementation
Verified all Phase 9 deliverables already in place:
- PostgreSQL map_votes table (UNIQUE constraint on map_id, voter_id)
- POST /api/vote-map endpoint (+1/-1 votes, rate-limited)
- GET /api/vote/map/{map_id} endpoint for vote counts
- Positional fairness monitoring: tickFairnessAudit with 5-step lifecycle
* updateMapFairnessStats: recompute per-slot win rates
* flagUnfairMaps: probation for >10pp deviation
* retireDislikedMaps: force-retire at < -20 net votes
* pruneLowEngagementMaps: monthly bottom 10% pruning
* promoteClassicMaps: top-5 sustained (3+ months) to classic
- maps/index.json includes NetVotes from aggregation
All tests pass (mapvote, map_fairness, index-builder).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
c66dc893fa
commit
0028100c64
3 changed files with 18 additions and 6 deletions
|
|
@ -1 +1 @@
|
|||
1e66df51ed4cf34c6aa3db3f4d73e7a6a9868d53
|
||||
721db31a01eb2beedeaf06425492696a517ea8a7
|
||||
|
|
|
|||
|
|
@ -168,6 +168,7 @@ type MapData struct {
|
|||
EnergyCount int `json:"energy_count"`
|
||||
GridWidth int `json:"grid_width"`
|
||||
GridHeight int `json:"grid_height"`
|
||||
NetVotes int `json:"net_votes"` // Sum of votes from map_votes table
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
RawJSON json.RawMessage `json:"-"`
|
||||
}
|
||||
|
|
@ -758,11 +759,17 @@ func fetchPredictorStats(ctx context.Context, db *sql.DB) ([]PredictorStats, err
|
|||
|
||||
func fetchMaps(ctx context.Context, db *sql.DB) ([]MapData, error) {
|
||||
query := `
|
||||
SELECT map_id, player_count, status, engagement, wall_density,
|
||||
energy_count, grid_width, grid_height, created_at, map_json
|
||||
FROM maps
|
||||
WHERE status IN ('active', 'probation', 'classic')
|
||||
ORDER BY engagement DESC
|
||||
SELECT m.map_id, m.player_count, m.status, m.engagement, m.wall_density,
|
||||
m.energy_count, m.grid_width, m.grid_height, m.created_at, m.map_json,
|
||||
COALESCE(v.vote_sum, 0) as net_votes
|
||||
FROM maps m
|
||||
LEFT JOIN (
|
||||
SELECT map_id, SUM(vote)::int as vote_sum
|
||||
FROM map_votes
|
||||
GROUP BY map_id
|
||||
) v ON m.map_id = v.map_id
|
||||
WHERE m.status IN ('active', 'probation', 'classic')
|
||||
ORDER BY m.engagement DESC
|
||||
`
|
||||
|
||||
rows, err := db.QueryContext(ctx, query)
|
||||
|
|
@ -777,6 +784,7 @@ func fetchMaps(ctx context.Context, db *sql.DB) ([]MapData, error) {
|
|||
if err := rows.Scan(
|
||||
&m.MapID, &m.PlayerCount, &m.Status, &m.Engagement, &m.WallDensity,
|
||||
&m.EnergyCount, &m.GridWidth, &m.GridHeight, &m.CreatedAt, &m.RawJSON,
|
||||
&m.NetVotes,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1676,6 +1676,7 @@ type MapIndexEntry struct {
|
|||
EnergyCount int `json:"energy_count"`
|
||||
GridWidth int `json:"grid_width"`
|
||||
GridHeight int `json:"grid_height"`
|
||||
NetVotes int `json:"net_votes"` // Sum of +1/-1 votes from map_votes table
|
||||
CreatedAt string `json:"created_at"`
|
||||
}
|
||||
|
||||
|
|
@ -1696,6 +1697,7 @@ type MapDetail struct {
|
|||
EnergyCount int `json:"energy_count"`
|
||||
GridWidth int `json:"grid_width"`
|
||||
GridHeight int `json:"grid_height"`
|
||||
NetVotes int `json:"net_votes"` // Sum of +1/-1 votes from map_votes table
|
||||
CreatedAt string `json:"created_at"`
|
||||
Walls []mapPosition `json:"walls"`
|
||||
Cores []mapCore `json:"cores"`
|
||||
|
|
@ -1721,6 +1723,7 @@ func generateMapsIndex(data *IndexData, outputDir string) error {
|
|||
EnergyCount: m.EnergyCount,
|
||||
GridWidth: m.GridWidth,
|
||||
GridHeight: m.GridHeight,
|
||||
NetVotes: m.NetVotes,
|
||||
CreatedAt: m.CreatedAt.Format(time.RFC3339),
|
||||
}
|
||||
entries = append(entries, entry)
|
||||
|
|
@ -1743,6 +1746,7 @@ func generateMapsIndex(data *IndexData, outputDir string) error {
|
|||
EnergyCount: m.EnergyCount,
|
||||
GridWidth: m.GridWidth,
|
||||
GridHeight: m.GridHeight,
|
||||
NetVotes: m.NetVotes,
|
||||
CreatedAt: m.CreatedAt.Format(time.RFC3339),
|
||||
Walls: geo.Walls,
|
||||
Cores: geo.Cores,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue