Skip to content

docs: plan match tags (opponent/partner names, competition) - #139

Closed
EMRahman wants to merge 4 commits into
mainfrom
claude/serene-lovelace-ft49uz
Closed

EMRahman wants to merge 4 commits into
mainfrom
claude/serene-lovelace-ft49uz

Conversation

@EMRahman

@EMRahman EMRahman commented Oct 1, 2026 •

Copy link
Copy Markdown
Owner

Superseded by merged PR #142. The revised docs/features/MATCH_TAGS_PLAN.md is now on main, preserving this proposal and its review fixes while extending it to in-progress matches, comparison and private notes. Both review threads on this PR are resolved; there are no separate implementation changes to merge.

Summary

Adds docs/features/MATCH_TAGS_PLAN.md, a design for tagging a finished match with:

  • who was played (opponent, plus partner and second opponent in doubles), with names you can pick again later
  • the Competition Type: Friendly / League / Tournament / Practice

Tags are edited on iOS and shown read-only on the watch in v1. They're used in the AI Coach prompt and in shared reports. The doc also includes a sensitive-data review.

This PR is docs only. No code changes.

Key findings recorded in the plan

  • The current merge rule would silently delete tags. In MatchMergePolicy.resolve, case 4 picks the record with the later endTime and uses >=. The watch's copy of a finished match has the same endTime as the phone's, so the next full-history push from the watch replaces the phone's tagged record with an untagged one. ArchiveBackupPolicy.resolveBackup has the same shape. Tags therefore merge separately, using their own updatedAt last-write-wins clock. That Core PR must land before any UI can write a tag.
  • Mixed versions: an older build re-encodes a record without tags. So nil means "no information", and clearing tags is stored as an empty MatchTags with a newer timestamp.
  • Naming clash: MatchType already means singles/doubles, so the new enum is CompetitionType, matching its "Competition Type" UI label.
  • Forward compatibility: the competition type is stored as a raw string. A case added later then shows as unknown on older builds instead of making the whole [MatchRecord] archive fail to decode (TECHNICAL_DEBT docs: tidy micro-site hero layout #18 and docs: reword iPhone line in hero subtitle to reduce repetition #19).
  • Delivery to the watch: tag edits go on a dedicated matchTagsUpdate key. Sending a full record would go through .singleMatch, which fires completeCurrentMatchIfMatching. The phone also resends tags when watch history arrives with older or missing tags, and when a match newly appears in the watch's manifest (§6.1).
  • Roster comes from the archive: the list of players is built from saved matches, so there is no second store to back up, sync or tombstone.

Sensitive-data review (§8 of the plan)

These are the app's first third-party names. Decisions:

  • Names are left out of the AI prompt by default (opt-in toggle).
  • Names never go in filenames or spoken announcements, and are never logged with privacy: .public.
  • Names in the HTML export go through the existing scriptSafe and HTML escaping, with tests using hostile names.
  • "Forget player" removes a name everywhere.
  • No Contacts access.
  • The privacy policy wording changes in the PR that ships the feature, not this one.
  • The App Store label is expected to stay "Data Not Collected".

Owner decisions (§11)

  • UI label: Competition Type; the code uses the same name (CompetitionType, MatchTags.competitionType, Meta.competitionTypeLabel)
  • Practice is included as a fourth option
  • Player names are on by default in shared reports, with a toggle to turn them off
  • iPhone-only editing in v1; the watch shows tags read-only
  • The six proposed defaults are confirmed (§11.1)

Verification

Docs only, so nothing to build or test. I checked the cited code locations (merge sites, wire handling, HTML escaping, test file names) against the current main.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Q4hwsXcv3uCzZ8W2pypt4r

Design for tagging a finished match with who was played and whether it
was a friendly, league or tournament match. Records the merge hazard that
would silently wipe phone-side tags on the next watch sync, the
derived-roster approach for re-selecting players, the sync/export surfaces,
and a sensitive-data review of third-party names.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q4hwsXcv3uCzZ8W2pypt4r

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: cb042490c4

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread docs/features/MATCH_TAGS_PLAN.md Resolved
Comment thread docs/features/MATCH_TAGS_PLAN.md Resolved
claude added 3 commits October 1, 2026 15:35
Edit-time sends can be skipped for good (manifest lag, an older watch that
later upgrades), so the plan adds reconciliation on watch history/manifest
arrival. Manual entry only builds in-progress records, so it no longer
carries tag fields in v1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q4hwsXcv3uCzZ8W2pypt4r
Competition Type as the UI label, Practice as a fourth case, names on by
default in shared reports, iPhone-only editing in v1, and the six
proposed defaults confirmed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q4hwsXcv3uCzZ8W2pypt4r
Matches the 'Competition Type' UI label. Related identifiers follow
(competitionType, competitionTypeRaw, Meta.competitionTypeLabel), and the
unknown-value test example moves off 'practice', which is now a real case.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q4hwsXcv3uCzZ8W2pypt4r
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.

2 participants