Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
101 commits
Select commit Hold shift + click to select a range
cec879c
chore(backlog): T-011 done
BrandanBurgess Jul 16, 2026
d0a1e4f
docs(agent): orchestrator state snapshot for session handoff
BrandanBurgess Jul 16, 2026
613cad2
feat(screens): whiteboard page with toolbar, view menu, record/save (…
BrandanBurgess Jul 16, 2026
b5d7160
merge: T-030 whiteboard page into integration
BrandanBurgess Jul 16, 2026
24ccc96
chore(backlog): T-030 done, T-031 + T-033 doing
BrandanBurgess Jul 16, 2026
23e21ff
feat(screens): patterns page with libraries, chips, search, details (…
BrandanBurgess Jul 16, 2026
880efb4
merge: T-031 patterns page into integration
BrandanBurgess Jul 16, 2026
733ac3f
feat(screens): roster page with CRUD, sliders, double-exposure warnin…
BrandanBurgess Jul 16, 2026
598c97a
fix(infra): seed database in e2e boot path so fresh environments pass…
BrandanBurgess Jul 16, 2026
b165909
merge: T-031 seed-on-boot fix into integration
BrandanBurgess Jul 16, 2026
09c9fe2
merge: reconcile main squash history into integration
BrandanBurgess Jul 16, 2026
ea0930f
Merge remote-tracking branch 'origin/main' into integration
BrandanBurgess Jul 16, 2026
7fd5a3a
merge: T-033 roster page into integration (resolve nav shell, schemas…
BrandanBurgess Jul 16, 2026
add1c38
chore(backlog): T-031 done, T-033 pr, T-032 + T-034 doing
BrandanBurgess Jul 16, 2026
e8926a7
Merge remote-tracking branch 'origin/main' into integration
BrandanBurgess Jul 16, 2026
f331829
chore(backlog): T-033 done
BrandanBurgess Jul 16, 2026
c634850
feat(screens): formations page with keystones, keycards, rondo map (T…
BrandanBurgess Jul 16, 2026
877ad0d
merge: T-032 formations page into integration
BrandanBurgess Jul 16, 2026
35a07a2
chore(e2e): drop duplicated nav assertion left by merge
BrandanBurgess Jul 16, 2026
ce9695c
feat(screens): identity page with reference teams, pass-risk, cult co…
BrandanBurgess Jul 16, 2026
62c8b24
Merge remote-tracking branch 'origin/main' into integration
BrandanBurgess Jul 16, 2026
02cf1c3
merge: T-034 identity page into integration (all five nav entries live)
BrandanBurgess Jul 16, 2026
f8fde64
Merge remote-tracking branch 'origin/main' into integration
BrandanBurgess Jul 16, 2026
4d7ff05
chore(backlog): T-032 + T-034 done, screens phase complete
BrandanBurgess Jul 16, 2026
d1ce7c1
chore(backlog): T-040 + T-041 doing
BrandanBurgess Jul 16, 2026
abb4823
feat(collab): role gating suite, API enforcement audit (T-040)
BrandanBurgess Jul 16, 2026
817df6d
merge: T-040 role gating suite into integration
BrandanBurgess Jul 16, 2026
8732131
chore(backlog): founder decisions recorded, add T-012 + T-043
BrandanBurgess Jul 16, 2026
0151d7b
feat(collab): playstyle suggestion flow (T-041)
BrandanBurgess Jul 16, 2026
27c9211
Merge remote-tracking branch 'origin/main' into integration
BrandanBurgess Jul 16, 2026
2131cc4
merge: T-041 suggestion flow into integration
BrandanBurgess Jul 16, 2026
0e4cf0c
chore(backlog): T-041 pr, T-012 doing
BrandanBurgess Jul 16, 2026
302040d
Merge remote-tracking branch 'origin/main' into integration
BrandanBurgess Jul 16, 2026
7f69ea2
chore(backlog): T-041 done
BrandanBurgess Jul 16, 2026
ea71eae
feat(platform): role-scoped join codes, head coach member management …
BrandanBurgess Jul 16, 2026
0282683
merge: T-043 team management into integration
BrandanBurgess Jul 16, 2026
7116ee6
feat(content): identity age_hint column, migration, Bible backfill (T…
BrandanBurgess Jul 16, 2026
335e147
Merge remote-tracking branch 'origin/main' into integration
BrandanBurgess Jul 16, 2026
c3f273c
merge: T-012 identity age_hint into integration
BrandanBurgess Jul 16, 2026
0fc6f18
merge-fix: re-point T-012 migration to 0005 after T-043's 0004
BrandanBurgess Jul 16, 2026
41763d4
Merge remote-tracking branch 'origin/main' into integration
BrandanBurgess Jul 16, 2026
f23238e
docs(agent): session 2 handoff snapshot, T-012 + T-043 done
BrandanBurgess Jul 16, 2026
be6e74c
feat(collab): sessions draft builder, send, receipts, player view (T-…
BrandanBurgess Aug 7, 2026
52f8113
feat(demo): scripts/seed_demo.py and a `make demo` target
BrandanBurgess Aug 7, 2026
274dda1
feat(screens): phone pass, styled auth screens, shared ghost button (…
BrandanBurgess Aug 7, 2026
6dd1273
feat(verify): demo-path journey, permission gate in CI, one search ma…
BrandanBurgess Aug 7, 2026
8e61cb0
feat(docs): screenshot capture script, docs/screenshots, and the README
BrandanBurgess Aug 7, 2026
08a55a5
feat(platform): deployable image, single-origin serving, Render bluep…
BrandanBurgess Aug 7, 2026
4659426
fix(ci): pin the dev tooling so CI and a checkout cannot drift
BrandanBurgess Aug 7, 2026
1e78386
merge: reconcile squash-merged main back into integration
BrandanBurgess Aug 7, 2026
fa5ca0a
docs(readme): live demo URL and a deployment section
BrandanBurgess Aug 7, 2026
ab3cc46
merge: reconcile squash-merged main back into integration
BrandanBurgess Aug 7, 2026
559d773
docs(epic): commission Epic T-100 Tactics Lab
BrandanBurgess Aug 7, 2026
33ee04f
docs(scope): amend Brief scope table for Tactical Depth epic (T-100)
BrandanBurgess Aug 7, 2026
5ea7bd2
merge: T-100 scope amendment into integration
BrandanBurgess Aug 7, 2026
e04b188
chore(backlog): T-100 done
BrandanBurgess Aug 7, 2026
22bf9bc
feat(board): superiority engine, JdP grid and matchup read (T-104)
BrandanBurgess Aug 7, 2026
a95bf77
feat(schema): Tactics Lab schema, migration 0006, scoped tables (T-101)
BrandanBurgess Aug 7, 2026
d20324a
merge: T-104 superiority engine into integration
BrandanBurgess Aug 7, 2026
e39bd90
merge: T-101 tactics lab schema into integration
BrandanBurgess Aug 7, 2026
deaa8e9
chore(backlog): T-101 and T-104 done
BrandanBurgess Aug 7, 2026
04ca643
feat(api): tactics lab routes for phases, matchups, rotations, archet…
BrandanBurgess Aug 7, 2026
dedde00
merge: T-108 tactics API into integration
BrandanBurgess Aug 7, 2026
74417ef
chore(backlog): T-108 done, add T-110 for the slot-to-unit crosswalk gap
BrandanBurgess Aug 7, 2026
0ef6954
feat(content): position archetypes, combinations, unit balance rules …
BrandanBurgess Aug 7, 2026
50112df
merge: T-102 archetype seeds into integration
BrandanBurgess Aug 7, 2026
2b2617c
chore(backlog): T-102 done
BrandanBurgess Aug 7, 2026
a8d1ee3
feat(content): formation phases, rotation systems, rondo map, matchup…
BrandanBurgess Aug 7, 2026
07c7a48
merge: T-103 formation phases, rotations and reference systems into i…
BrandanBurgess Aug 7, 2026
55f398e
chore(backlog): T-103 done, add T-111 for the orphan counterpress row
BrandanBurgess Aug 7, 2026
445aff1
fix(schema): delete orphan counterpress rondo zone row (T-111)
BrandanBurgess Aug 7, 2026
30f29ca
merge: T-111 orphan counterpress row migration into integration
BrandanBurgess Aug 7, 2026
2d77434
chore(backlog): T-111 done
BrandanBurgess Aug 7, 2026
5e0c519
feat(board): phase morph playback and mirrored opponent layer (T-105)
BrandanBurgess Aug 7, 2026
e7e5434
merge: T-105 phase morph playback and opponent layer into integration
BrandanBurgess Aug 7, 2026
c0c03af
chore(backlog): T-105 done
BrandanBurgess Aug 7, 2026
9806a51
feat(screens): Formations page rebuild for the Tactics Lab (T-106)
BrandanBurgess Aug 7, 2026
365d457
merge: T-106 formations page rebuild into integration
BrandanBurgess Aug 7, 2026
a5ae2e4
chore(backlog): T-106 done, add T-112 for the unrendered counterpress…
BrandanBurgess Aug 7, 2026
1ec4403
chore(backlog): T-112 unblocked, doc 06 section 2.3 specifies the no-…
BrandanBurgess Aug 7, 2026
bedf43a
fix(screens): render the counterpress ring, six rondo zones again (T-…
BrandanBurgess Aug 7, 2026
51327ad
merge: T-112 counterpress ring into integration
BrandanBurgess Aug 7, 2026
f2f2d32
chore(backlog): T-112 done, rondo map back to six zones
BrandanBurgess Aug 7, 2026
f6d5868
feat(content): slot-to-unit crosswalk and coach-only unit balance (T-…
BrandanBurgess Aug 7, 2026
935a73c
merge: T-110 slot to unit crosswalk into integration
BrandanBurgess Aug 7, 2026
9b132bf
chore(backlog): T-110 done
BrandanBurgess Aug 7, 2026
ba1be11
feat(screens): personnel panel with archetypes, suggestions, unit bal…
BrandanBurgess Aug 7, 2026
fe7eb6c
merge: T-107 personnel panel into integration
BrandanBurgess Aug 7, 2026
3a7ad86
chore(backlog): T-107 done, add T-113 for unwired personnel persistence
BrandanBurgess Aug 7, 2026
9cd6acd
chore(verify): port isolation, demo path tactics beat, stale comment …
BrandanBurgess Aug 7, 2026
74a0d32
merge: T-109 epic hardening into integration
BrandanBurgess Aug 7, 2026
d404718
chore(backlog): T-109 done, add T-114 and T-115 for the unmet DoD points
BrandanBurgess Aug 7, 2026
b959102
chore(backlog): add T-070 brand refresh epic
BrandanBurgess Aug 7, 2026
564297e
feat(brand): logo integration, nav shield mark, sign-in lockup, favic…
BrandanBurgess Aug 7, 2026
8ed981c
fix(brand): lockup contrast, 16px favicon, drop dead 144w mark (T-070)
BrandanBurgess Aug 7, 2026
6e4cc56
feat(screens): brand palette and board token layer (T-071)
BrandanBurgess Aug 7, 2026
5fa4612
merge: T-070 logo integration into integration
BrandanBurgess Aug 7, 2026
38a792b
merge: T-071 brand palette into integration
BrandanBurgess Aug 8, 2026
0725372
chore(brand): point palette guard comments at check_palette.py
BrandanBurgess Aug 8, 2026
bfef94c
chore(backlog): T-070 and T-071 done
BrandanBurgess Aug 8, 2026
23a821c
merge: reconcile squash-merged main back into integration
BrandanBurgess Aug 9, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,6 @@ test-results/
*.db-shm
.DS_Store
*.egg-info/
# scripts/build_logo_assets.py review composites: not shipped, regenerated
# on every run.
build/logo_review/
41 changes: 41 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,44 @@
VENV := .venv
PY := $(VENV)/bin/python

# T-109: derive a stable, distinct POP_WEB_PORT / POP_API_PORT pair from
# this checkout's own path, so `make dev` / `make e2e` / `make verify` no
# longer collide when several ticket worktrees run them at the same time.
# Before this, both defaulted to 5173/8000 everywhere (scripts/dev.sh's
# fallback, playwright.config.ts's fallback), so a second worktree's
# `make verify` would find the FIRST worktree's dev server already
# listening (reuseExistingServer is true outside CI) and quietly test the
# wrong worktree's code against the wrong worktree's database. That
# doesn't fail loudly, it looks exactly like a flaky assertion, and it
# cost this epic several false diagnoses (doc 06 section 6, T-109).
#
# `?=` means an explicit `POP_WEB_PORT=7673 POP_API_PORT=10500 make
# verify` (or an exported value from the shell) always wins over this
# default, so the manual override every ticket in this epic already
# relied on keeps working unchanged, including running two worktrees on
# the SAME two ports on purpose (e.g. one at a time, by hand).
#
# CURDIR is make's own absolute working directory (set once at startup,
# unaffected by any `cd` inside a recipe), so it is exactly the
# per-worktree checkout path. cksum is POSIX and present on both macOS
# and the Linux CI runner, so this needs no new dependency. Folding the
# checksum into 0-999 keeps the derived ports inside a low-collision,
# non-privileged range (5173-6172 for web, 8000-8999 for api) without a
# real port-availability probe, which is unnecessary here: CI only ever
# runs one checkout at a time, so its derived pair is simply "some
# deterministic port instead of 5173", never a coordination problem.
#
# `printf '%s'`, not `echo -n`: make always runs shell functions through
# /bin/sh regardless of the caller's login shell, and /bin/sh's builtin
# echo does not honour -n on macOS OR on Debian/Ubuntu's dash (the CI
# runner's /bin/sh), so `echo -n "$(CURDIR)"` hashes the literal 4
# characters "-n " glued onto the path instead of the path alone. Still
# deterministic, but needlessly fragile; printf has no such flag ambiguity
# in any POSIX shell.
WORKTREE_OFFSET := $(shell printf '%s' "$(CURDIR)" | cksum | awk '{print $$1 % 1000}')
export POP_WEB_PORT ?= $(shell echo $$(( 5173 + $(WORKTREE_OFFSET) )))
export POP_API_PORT ?= $(shell echo $$(( 8000 + $(WORKTREE_OFFSET) )))

bootstrap:
python3 -m venv $(VENV)
$(VENV)/bin/pip install --quiet --upgrade pip
Expand Down Expand Up @@ -30,9 +68,12 @@ test:
e2e:
npx playwright test

# Static source guards. check_palette.py is here rather than in the vitest
# suite because it reads the shipped CSS text, which vitest stubs out.
check-copy:
$(PY) scripts/check_copy.py
$(PY) scripts/validate_seeds.py
$(PY) scripts/check_palette.py

# The Brief section 3 permission table, every row (backend/tests/test_permissions.py).
# `make test` already runs it, but this target also fails when a row is
Expand Down
Binary file added assets/brand/patternsofplaylogo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions backend/app/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
roster,
sessions,
suggestions,
tactics,
teams,
whiteboard,
)
Expand All @@ -27,6 +28,7 @@
app.include_router(formations.router)
app.include_router(identity.router)
app.include_router(sessions.router)
app.include_router(tactics.router)


@app.get("/api/health")
Expand Down
2 changes: 1 addition & 1 deletion backend/app/models/formations.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ class RondoZone(Base):

formation_code: Mapped[str] = mapped_column(ForeignKey("formations.code"), primary_key=True)
# first_line | midfield_box | flank_corridor_left | flank_corridor_right
# | last_line | counterpress
# | last_line | counterpress_ring
zone_key: Mapped[str] = mapped_column(String(30), primary_key=True)
polygon_json: Mapped[list] = mapped_column(JSON, nullable=False)
rondo_name: Mapped[str] = mapped_column(String(120), nullable=False)
Expand Down
29 changes: 22 additions & 7 deletions backend/app/routers/formations.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,24 @@
FORMATION_ORDER = ("433", "4231", "442", "352", "343", "541")

# Bible 3G.2's rondo map order (first-line build-up through to the
# counterpress moment); only 433 carries seeded zones today (seeds/
# rondo_zones.json), but the ordering applies to any formation that gains
# a rondo map later. flank_corridor split into left/right (T-101,
# migration 0006, doc 06 section 3.1); left before right matches the
# repo's own slot-naming convention (formations.json lists every '_l'
# slot before its '_r' counterpart, e.g. fb_l before fb_r).
# counterpress moment); T-103 seeds all six zones on all six formations.
# flank_corridor split into left/right (T-101, migration 0006, doc 06
# section 3.1); left before right matches the repo's own slot-naming
# convention (formations.json lists every '_l' slot before its '_r'
# counterpart, e.g. fb_l before fb_r).
#
# The last key is `counterpress_ring`, doc 06 section 2.3's name for it.
# It read `counterpress` until T-112, the pre-0007 zone key, which no seed
# has written since T-103. That stale entry sorted the ring to the end by
# ACCIDENT (an unknown key falls to len(order)) rather than by intent, and
# would have silently mis-sorted the moment a seventh zone existed.
ZONE_ORDER = (
"first_line",
"midfield_box",
"flank_corridor_left",
"flank_corridor_right",
"last_line",
"counterpress",
"counterpress_ring",
)


Expand Down Expand Up @@ -79,6 +84,7 @@ def list_formations(
FormationPositionOut(
slot=p["slot"],
position_code=p["position_code"],
slot_family=p["slot_family"],
x=p["x"],
y=p["y"],
)
Expand All @@ -95,6 +101,15 @@ def list_formations(
teaches=z.teaches,
polygon=z.polygon_json,
trains_pattern_codes=z.trains_pattern_codes,
# doc 06 section 2.3 (T-112). canonical_rondo is the
# no-opposition fallback label; zone_kind and radius
# are what tell the Rondo Map that the counterpress
# ring is a circle around the ball rather than the
# polygon seeded alongside it, which only bounds the
# half of the pitch the ring is coached in.
canonical_rondo=z.canonical_rondo,
zone_kind=z.zone_kind,
radius=z.radius,
)
for z in zones
],
Expand Down
Loading
Loading