Skip to content

docs(design): retire the HOME contract and re-point GC entry points to the Progress tab - #1090

Merged
wei18 merged 2 commits into
mainfrom
session/jittery-shrike-qc3g
Sep 14, 2026
Merged

wei18 merged 2 commits into
mainfrom
session/jittery-shrike-qc3g

Conversation

@wei18

@wei18 wei18 commented Sep 14, 2026 •

Copy link
Copy Markdown
Owner

Closes #1081
part of #1014

Docs-only. HOME was deleted by #1020 / #1038 and STATS became the Progress tab in #1051, but docs/screen-contracts.md and docs/navigation-flows.md still described the HOME-era entry points as current. contracts.py only checks that headings exist, so the prose passed the gate.

Commits: b0dee32 (the retirement) + 5f11a79 (PM CR follow-up: SETTINGS / N20 "Home leaderboard card" mentions marked retired, stub gains the Practice card, case-insensitive hit list below).

Decisions (per the PM scope on #1081)

## HOME heading: kept as a one-paragraph retired stub. EXPECTED_SLUG_COUNT stays 23 and C-1 (HOME 整節刪除) keeps its anchor. No element inventory, interaction table or destination contract survives; the stub says where each former HOME element went (resume pill/banner → TodayTabHost, Leaderboard card → Progress rows, Practice card → Practice tab root, Settings card → per-tab gear, Statistics card → Progress tab) and points at git show 6341999a:docs/screen-contracts.md for the pre-retirement text.

C-20 / C-34 re-anchored HOME → SUD-DAILY-HUB. Reasoning:

  • The resume pill's as-built home is GameAppKit/TodayTabHost.swift: it wraps each app's Today content, renders ResumePill while rootViewModel.resumeCandidate is non-nil, and resumeTapped() pushes onto the selected tab's stack.
  • The canonical doc has no ## TODAY / ROOT-TABS section (C-16 is still unanchored); the Today tab root is contracted under SUD-DAILY-HUB / MS-DAILY-HUB (C-2 / C-2b).
  • Sibling Today-tab rows C-2, C-6, C-7, C-18, C-19 already anchor to SUD-DAILY-HUB, with the MS side on the b twin where one exists. C-20 / C-34 have no twin, so they anchor to the Sudoku reference section.
  • C-34's §3.6.2 triggers are as-built, not aspirational: GameRootViewModel.setPath(_:for:) calls handlePathShrink on ANY tab's path shrinking, plus dismissGame() and bootstrap().
  • To keep the anchor honest rather than a bare rename, the pill facts (element, tap outcome, refresh triggers, degraded state) moved out of HOME into a "Today tab host" note in SUD-DAILY-HUB; MS-DAILY-HUB carries a pointer note plus the one MS-specific fact (.resumeBoard tier-1 loader), the same shape as its existing "see SUD-DAILY-HUB's callout" banner.

Every rewritten cell (section / old / new)

File / section Old New
screen-contracts.md Conventions IDs are HOME, SETTINGS, … IDs are PROGRESS, SETTINGS, …
## HOME (whole section) 67-line live contract (entry points, code, element inventory, interaction table, covering, state variants) 15-line retired stub
## SUD-DAILY-HUB — + "Today tab host (resume pill — the C-20 / C-34 anchor …)" note
## MS-DAILY-HUB — + "Today tab host (resume pill)" pointer note + .resumeBoard tier-1 fact
## SUD-BOARD entry points HOME resume pill Today tab resume pill (TodayTabHost, see SUD-DAILY-HUB)
## MS-BOARD entry points HOME resume pill (→ .resumeBoard …) Today tab resume pill (→ .resumeBoard …)
## SUD-BOARD-LOAD-FAILED Close row, lands on HOME/hub that pushed the board — on iOS … the tab root / hub that pushed the board — on iOS … (pre-existing SUD/MS asymmetry: the MS twin describes only the resume caller)
## MS-BOARD-LOAD-FAILED entry points (HOME resume pill — tier 1, …) (Today tab resume pill — tier 1, …)
## MS-BOARD-LOAD-FAILED Close row, lands on HOME (resume pill's caller) Today tab root (resume pill's caller)
## PAUSE-OVERLAY Leave row, lands on HOME (iOS: cover collapses) or the hub … the tab root (iOS: cover collapses) or the hub …
## SUD-COMPLETION-OVERLAY Close row, lands on HOME/hub that pushed the board (never the solved board — #667 fix) the tab root / hub that pushed the board (never …)
## MS-COMPLETION-OVERLAY Close row, lands on HOME/hub that pushed the board the tab root / hub that pushed the board (pre-existing asymmetry: the SUD twin carries the "(never the solved board — #667 fix)" parenthetical, which is Sudoku's exitToHub fix and does not apply to MS's plain dismiss(); base 6341999 already differed)
## SETTINGS GC row, destination (5f11a79) (same guard the Home leaderboard card uses) (the same guard the PROGRESS GC rows use — and the retired pre-3.0 HOME leaderboard card used)
## SETTINGS AS-BUILT NOTE (5f11a79) alongside the Home leaderboard card (#685/#714; … alongside the retired pre-3.0 HOME leaderboard card — today's other entry points are the PROGRESS GC rows (#685/#714; …
## GC-DASHBOARD entry points HOME leaderboard card; SETTINGS GC row PROGRESS Leaderboards row (.leaderboards) and Achievements row (.achievements, C-26 / C-36); SETTINGS GC row; all through presentGameCenterOrAlert; HOME card retired (C-35)
## GC-SIGNED-OUT-ALERT entry points HOME leaderboard card tap, OR SETTINGS GC row PROGRESS Achievements / Leaderboards row tap (C-35 / N-AA), OR SETTINGS GC row; HOME card entry retired
## GC-SIGNED-OUT-ALERT covering HOME stays visible but non-interactive the origin screen (tab root or SETTINGS) stays visible but non-interactive
## ATT-PRIMER Continue row, lands on HOME, banner now resolves … Today tab, banner now resolves …
## ATT-PRIMER Not now row, lands on HOME Today tab
## ATT-PRIMER covering HOME stays mounted the Today tab stays mounted
navigation-flows.md header — + "Partially superseded by 3.0" banner naming N-A / N-D / N-E / N-C as the owners of the remaining HOME passages ("pre-3.0 record, superseded by the 3.0 spec PR")
navigation-flows.md §intro Screen IDs (HOME, SUD-BOARD, …) Screen IDs (PROGRESS, SUD-BOARD, …)
S5 HOME(Leaderboard, authenticated) → GC-DASHBOARD / HOME(Leaderboard, signed out) → GC-SIGNED-OUT-ALERT → OK → HOME PROGRESS(Leaderboards or Achievements row, authenticated) → GC-DASHBOARD(external) / PROGRESS(either row, signed out) → GC-SIGNED-OUT-ALERT → OK → PROGRESS; notes cite C-15 / C-36 / N-F and N14
M6 HOME(Leaderboard, authenticated) → GC-DASHBOARD / signed-out → alert PROGRESS(Leaderboards or Achievements row, authenticated) → GC-DASHBOARD(external) / signed-out → alert (N-F2)
N14 reachable from HOME leaderboard card OR SETTINGS GC row reachable from the PROGRESS tab's Leaderboards / Achievements rows — N-Q / N-AA — OR the SETTINGS GC row
N20 (5f11a79) the surviving GC entry points (Home card / Settings row) the surviving GC entry points (PROGRESS GC rows / Settings row; the pre-3.0 Home card is retired, #1020)
contracts.py C-20 anchor HOME anchor SUD-DAILY-HUB (+ 2-line comment)
contracts.py C-34 anchor HOME anchor SUD-DAILY-HUB

Not touched on purpose: S1–S3 / M1–M3, the §3 mermaid diagrams, the §1 route enums, §2 hub list and #679 refresh prose, N4 — they are owned by anchored BREAK rows N-A / N-D / N-E / N-C and are the 3.0 spec PR's rewrite; the new banner names them as the pre-3.0 record.

Surviving hits at head 5f11a79 — rg -n -i '\bhome\b' docs/screen-contracts.md docs/navigation-flows.md (35 + 41 = 76 lines)

Classes: stub (the ## HOME section itself) · historical (the passage itself says retired / superseded / pre-3.0) · banner-covered (pre-3.0 record named by the nav-flows banner, owned by an anchored BREAK row) · still-true ("Home" used as the generic landing-screen noun; the statement holds for the Today tab) · not-the-screen (English word).

screen-contracts.md (35):

Lines Class Note
5, 7, 11 historical pre-existing "Partially superseded by 3.0" header banner (home route on 7)
39, 41, 44, 52 stub the retired ## HOME stub
63, 64, 68, 117 historical SUD-DAILY-HUB re-anchor callout / "no HOME"
73, 77, 78 historical new Today-tab-host note: "moved here from the retired HOME contract", "replaced HOME's game.home.root"
155, 159 historical MS-DAILY-HUB re-anchor callout / "no HOME"
224, 226, 281, 284 historical PRACTICE-HUBs: "HOME Practice card entry is retired / no HOME"
818, 822, 823, 829 historical PROGRESS: "HOME itself was retired by #1020"
891 historical PROGRESS: "mirrors #1020 C-35's retired HOME leaderboard card"
977, 989 historical SETTINGS (5f11a79): "the retired pre-3.0 HOME leaderboard card"
1205, 1206 historical GC-DASHBOARD: "pre-3.0 HOME leaderboard card is retired"
1230 historical GC-SIGNED-OUT-ALERT: "pre-3.0 HOME leaderboard card entry is retired"
1240 not-the-screen "the alert's home" = where the alert is mounted
1276 historical ATT-PRIMER: "Pre-3.0 this was GameHomeView's banner slot; HOME is retired"
1311 still-true ATT-PRIMER E2E note: "dismissal + Home unaffected" — holds for the Today tab; not rewritten per PM
1321, 1322 still-true UMP-CONSENT: "never blocks Home" / "Home renders" — holds for the Today tab; not rewritten per PM

navigation-flows.md (41):

Lines Class Note
5, 8, 10 historical the new superseded banner
49, 55, 72, 76, 77, 78 banner-covered §1 pre-3.0 route enums (case home, .home, HOME root) — N-A
89, 155 banner-covered §2 hub list / #679 refresh prose — N-C
171–204, 222–256 (18 lines) banner-covered §3 mermaid diagrams — N-D / N-E
210, 211, 212, 262, 263, 264 banner-covered S1–S3 / M1–M3 chains — N-D / N-E
214 historical S5, rewritten: "Re-pointed from the retired HOME leaderboard card by #1081"
282 banner-covered N4 "Cancel pops back to HOME" — N-J
293, 294, 295 still-true N15 / N16 / N17 "Home unaffected" / "never gates Home" / "host screen (Home / …)" — holds for the Today tab; not rewritten per PM
298 historical N20 (5f11a79): "the pre-3.0 Home card is retired, #1020"

Absent at head (grep 0 hits, case-insensitive): home resume pill, home/hub, home (resume, home stays, home leaderboard card (authenticated, home leaderboard card tap, home leaderboard card uses, alongside the home leaderboard card (, statistics card tap, ## stats.

Verification

python3 scripts/design/contracts.py at 5f11a79 (exit 0):

contract anchoring gate
  repo root: /Users/zw/GitHub/Wei18/Sudoku-spec-worktree-session-jittery-shrike-qc3g
==============================================================================
canonical shape
  screen-contracts.md : 23 slug sections (expected 23)
  navigation-flows.md : 38 rows  S=7 M=8 N=23  (expected S=7 M=8 N=23, total 38)

anchors

coverage
  change entries      : 36 screen-contracts (40 anchor rows), 28 navigation-flows (32 anchor rows)
  canonical touched   : 19/23 slug sections, 24/38 nav rows
  untouched sections  : CLEAR-CACHE-DIALOG, REMINDER-DENIED, REMINDER-PRIMER, UMP-CONSENT
  NOT YET ANCHORED    : 2 screen (C-16, C-27), 7 nav (N-A, N-B, N-C, N-X, N-Y, N-Z, N-AB)
                        (these describe new sections or prose-level model changes;
                         anchoring them is the remaining spec-PR work item)

RESULT: PASS — canonical shape matches, every stated anchor resolves

git diff --stat origin/main...HEAD: 3 files, docs/navigation-flows.md, docs/screen-contracts.md, scripts/design/contracts.py only. No Packages/, App/, .github/ changes. lychee: no links added or removed.

Every #NNN in the new prose was checked with gh issue view / gh pr view: #1014, #1020, #1038, #1051, #1064, #1075, #1081, #685, #714, #679, #667, #1058, #1021.

🤖 Generated with Claude Code

…o the Progress tab

HOME was deleted by #1020/#1038 and STATS became the Progress tab in #1051,
but docs/screen-contracts.md and docs/navigation-flows.md still described
the HOME-era entry points as current. The anchoring gate only checks that
headings exist, so the stale prose passed.

- screen-contracts.md `## HOME`: whole section replaced by a one-paragraph
  retired stub (heading kept so C-1 stays anchored and the section count
  stays 23). The resume-pill facts move into a "Today tab host" note in
  SUD-DAILY-HUB / MS-DAILY-HUB, which is where the pill lives as-built
  (GameAppKit/TodayTabHost.swift).
- contracts.py: C-20 and C-34 re-anchored HOME -> SUD-DAILY-HUB (the Today
  tab root section, C-2); EXPECTED_SLUG_COUNT unchanged at 23.
- GC-DASHBOARD / GC-SIGNED-OUT-ALERT entry points, S5 / M6 / N14: rewritten
  to the Progress tab's Leaderboards / Achievements rows + the SETTINGS GC
  row, matching C-15 / C-35 / C-36 / N-F / N-F2 / N-Q / N-AA.
- Remaining "HOME resume pill" / "HOME/hub that pushed the board" / "HOME
  stays visible" cells in as-built sections say "Today tab" / "the tab root"
  now.
- navigation-flows.md gains a "partially superseded by 3.0" banner naming
  the anchored BREAK rows (N-A / N-D / N-E / N-C) that own the remaining
  pre-3.0 HOME mentions (route enums, diagrams, S1-S3 / M1-M3, N4).

Verified: python3 scripts/design/contracts.py -> RESULT: PASS, 23 sections.

part of #1014
Closes #1081

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@wei18

wei18 commented Sep 14, 2026

Copy link
Copy Markdown
Owner Author

T6 fresh-context acceptance (sonnet) — head b0dee32

總判定:ACCEPT

驗收範圍:PR #1090(head b0dee323,base 6341999a,三點 diff),對照 issue #1081 全文(含 PM 的 Decision and scope / Session done-when / Additional constraints)。

逐條驗收

A. HOME stub — PASS
git show b0dee323:docs/screen-contracts.md 第 39–53 行:## HOME 只剩 retired stub(14 行),無 element inventory / interaction table / destination contract。Stub 指向「landing screen is the Today tab root, contracted under SUD-DAILY-HUB / MS-DAILY-HUB (C-2 / C-2b)」——PR body 有解釋這是對 issue 第 1 條「pointing at ## TODAY (or whatever the as-built landing section is)」的合理落實(doc 裡確實沒有 ## TODAY 這個 heading)。

B. C-20 / C-34 anchor 與程式碼一致 — PASS
讀 Packages/GameAppKit/Sources/GameAppKit/TodayTabHost.swift(磁碟,HEAD=b0dee323):resume pill 確實在此檔,resumeHeader 渲染 ResumePill,tap → rootViewModel.resumeTapped();a11y anchor game.today.root 取代舊 game.home.root,與新 note 逐句相符。
GameRootViewModel.swift:217-226 的 setPath(_:for:):newPath.count < path(for: tab).count 才觸發 handlePathShrink,對任一 tab 皆成立,與「任一 tab 的 path 縮短」敘述一致;dismissGame()(:289-297)呼叫 refreshResumeCandidate();bootstrap()(:125-)內部也呼叫 fetchResume 設 resumeCandidate。三個觸發點(path shrink / dismissGame / bootstrap)與新 note 逐一對應,無矛盾。contracts.py:51 C-1 仍 anchor "HOME",未被動到。

C. EXPECTED_SLUG_COUNT / ## HOME heading 存續 — PASS
grep -n "EXPECTED_SLUG_COUNT" scripts/design/contracts.py → 41 行 = 23;grep -c "^## " docs/screen-contracts.md → 23;## HOME heading 仍在(第 39 行)。PR body 明確說明此選擇("## HOME heading: kept as a one-paragraph retired stub...")。

D. GC-DASHBOARD / S5 / N14 entry points 改 Progress,且與 contracts.py 一致 — PASS
docs/screen-contracts.md ## GC-DASHBOARD 新文字(Leaderboards/Achievements 列、presentGameCenterOrAlert)與 ## PROGRESS 的 interaction table(約 886–889 行:Achievements tap → .achievements state、Leaderboards tap → .leaderboards state、signed-out 走 presentGameCenterOrAlert)描述一致,無矛盾。navigation-flows.md S5/M6/N14 全改為 Progress 入口。contracts.py 確認錨點存在且描述吻合:C-15(入口從 HOME 卡改 PROGRESS 列)、C-36(Progress Achievements 列入口)、N-F/N-F2(GC 起點改 PROGRESS)、N-Q/N-AA(GC signed-out 入口敘述改 PROGRESS)。M6(N-F2)也確實改了(diff 第 46–47 行)。

E. Gate 綠燈 + HOME 命中分類 — PASS
git status --short 乾淨、git rev-parse HEAD = b0dee32,執行 python3 scripts/design/contracts.py 結尾為 RESULT: PASS — canonical shape matches, every stated anchor resolves。
rg -n "HOME" docs/screen-contracts.md docs/navigation-flows.md 共 60 行,與 PR body 聲稱數字一致。抽查 8 個命中(screen-contracts 71/75/1202/1227、navigation-flows 89/155/214/282):71/75 是新 Today-tab-host note 裡對已退役 HOME 的歷史指涉;1202/1227 是 GC-DASHBOARD / GC-SIGNED-OUT-ALERT 裡「pre-3.0 HOME leaderboard card is retired」的明確歷史句;89/155 屬 §2 hub list / #679 refresh prose,PR 自己分類為「owned by N-C」,而 contracts.py 的 NOT YET ANCHORED 清單確實列出 N-C(尚未錨定,屬後續 spec PR 工作,不在 #1081 範圍內的 5 個指定地點);214 是 S5 列本身,重寫後仍保留一句對「retired HOME leaderboard card」的歷史指涉,合理;282 是 N4 負流程,PR 分類為「owned by N-J / 交給 spec PR」,同樣不在 issue 指定的 5 個地點內。8 個都與 PR 分類表吻合,且都不是「把 HOME 當作現行入口描述」的活文字。

F. Session done-when #2 — PASS
PR 標題 docs(design): retire the HOME contract and re-point GC entry points to the Progress tab,小寫開頭,與 issue 裡 PM 建議標題逐字相同。body 含 Closes #1081、part of #1014、C-20/C-34 re-anchor 理由段落、surviving-HOME-hit 清單。

G. Additional constraints — PASS
git diff 6341999a...b0dee323 --stat:只有 docs/navigation-flows.md(+20/−12)、docs/screen-contracts.md(+82(net)/−94(net) 行,實際 150 行變動)、scripts/design/contracts.py(+6/−4,共 3 檔),無 Packages/、App/、.github/ 改動。contracts.py 的改動僅限 C-20/C-34 兩個 anchor 值(HOME → SUD-DAILY-HUB)+ 一段 2 行註解,EXPECTED_SLUG_COUNT 未變(本來就該不變,因為 ## HOME heading 保留)。

H. 抽查 6 列 rewritten cell 表 — PASS
逐字核對 diff:GC-DASHBOARD entry points(diff 267–283 行)、S5(diff 37–38)、PAUSE-OVERLAY Leave row(diff 244–245)、ATT-PRIMER Not now row(diff 317–320)、contracts.py C-34(diff 347–348)、MS-COMPLETION-OVERLAY Close row(diff 262–263)——PR body 表格的 old/new 文字與實際 diff 逐字相符,無落差。

I. 引用 issue/PR 號存在且主題相符 — PASS
gh issue view / gh pr view 逐一查證 #1014(OPEN,3.0 epic)、#1020(CLOSED,3-tab skeleton 退役 HOME)、#1038(MERGED,同主題)、#1051(MERGED,today/practice/progress tab screens)、#1064(CLOSED,contracts.py FAIL 追蹤)、#1075(MERGED,contracts.py 接入 lint)、#1081(OPEN,本 issue)、#685(CLOSED,GC 入口死點)、#714(CLOSED,presentGameCenter 加固)、#679(MERGED,resume 候選修正)、#667(CLOSED,leaderboard-fetch-on-loss guard)、#1058(CLOSED,banner/.task 阻斷)、#1021(CLOSED,Today/Practice/Progress tab)。13 個全部存在且主題與引用上下文相符。

J. 鏡像原則 — PASS(附一則 pre-existing 差異,非本 PR 造成)
SUD-COMPLETION-OVERLAY / MS-COMPLETION-OVERLAY 的 Close row 新文字皆為「the tab root / hub that pushed the board」,措辭一致。
唯一不對稱處:SUD-BOARD-LOAD-FAILED Close row 用「the tab root / hub that pushed the board」,MS-BOARD-LOAD-FAILED Close row 只用「Today tab root (resume pill's caller)」。用 git show 6341999a:docs/screen-contracts.md 比對 pre-PR 版本(456 行 vs 535 行),確認這個不對稱在 PR 之前就存在(舊文字分別是「HOME/hub that pushed the board — on iOS …」vs「HOME (resume pill's caller)」),本 PR 只是逐字替換 HOME,沒有引入新的不一致,PR body 也明確標注「pre-existing SUD/MS asymmetry」。判定:非本 PR 造成,PASS。

Findings

無 blocker、無 should-fix。

  • nit:PR body 聲稱「lychee: no links added or removed」,我沒有跑 lychee 或掃描 diff 裡新增的 markdown link 語法獨立驗證;純散文字改動風險低,信心中等。

我沒驗的部分 + 信心度

…ons retired (#1081 CR)

PM CR on #1090: two SETTINGS passages ("same guard the Home leaderboard
card uses"; "alongside the Home leaderboard card") and the N20 row
("Home card / Settings row") still treated the card as live, contradicting
the rewritten GC-DASHBOARD / GC-SIGNED-OUT-ALERT text. They escaped the
case-sensitive HOME grep. All three now say the card is the retired
pre-3.0 one and name the PROGRESS GC rows as today's entry points.

Also: the `## HOME` stub's "moved as follows" list gains the Practice card
(-> Practice tab root, C-3 / C-3b) and is re-wrapped.

Surviving-hit list re-run with `rg -n -i '\bhome\b'`; classification is in
the PR body. `python3 scripts/design/contracts.py` -> RESULT: PASS.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@wei18

wei18 commented Sep 14, 2026

Copy link
Copy Markdown
Owner Author

PM review record: CR (doc-vs-code) + fresh-context acceptance; merging at 5f11a790.

  • CR read every one of the 24 rewritten cells against the production source (TodayTabHost, GameRootViewModel.setPath/handlePathShrink/dismissGame/bootstrap, ResumePill, GameCenterEntryRow, ProgressScreen, SettingsView, MS Live.swift): all as-built. C-20/C-34 → SUD-DAILY-HUB grounded. contracts.py PASS, 23 sections, anchors resolve, C-1 still anchored to the HOME stub.
  • CR found one MAJOR the PR had not touched: ## SETTINGS still described the HOME leaderboard card as a live guard reference, contradicting the rewritten GC sections. Cause: the PR's own hit check was case-sensitive (HOME) and missed Home. Fixed in the follow-up together with one more lowercase hit (N20), the stub's Practice-card line, and the MS-COMPLETION-OVERLAY row marked as pre-existing asymmetry. The PR body now carries the case-insensitive classified list (76 hits).
  • Verified from the ref before merge: no live "Home leaderboard card" phrasing remains; gate exit 0; contracts.py diff limited to the two re-anchors.

@wei18
wei18 merged commit 728ef19 into main Sep 14, 2026
14 checks passed
@wei18
wei18 deleted the session/jittery-shrike-qc3g branch September 14, 2026 16:06
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.

docs(design): screen-contracts and navigation-flows still describe retired HOME entry points

1 participant