Skip to content

[Draft] TeamCard legacy wrapper spec — for alignment before implementation#7475

Draft
Eetwalt wants to merge 4 commits intomainfrom
tp-legacy
Draft

[Draft] TeamCard legacy wrapper spec — for alignment before implementation#7475
Eetwalt wants to merge 4 commits intomainfrom
tp-legacy

Conversation

@Eetwalt
Copy link
Copy Markdown
Collaborator

@Eetwalt Eetwalt commented May 7, 2026

Summary

  • ⚠️ This is a design spec for alignment, not an implementation PR.
  • No code changes — only the design document at docs/superpowers/specs/2026-05-06-teamcard-legacy-wrapper-design.md.
  • Please review and comment so we agree on the approach before any code is written.
  • The PR will be closed (not merged) after review; the spec file itself is local-only and will be removed before implementation lands.

How did you test this change?

n/a — spec only, no code changes.

@Eetwalt Eetwalt added documentation Improvements or additions to documentation c: team_card g: arenafps ArenaFPS c: team_participant labels May 7, 2026
1. `Custom.run` calls `LegacyTeamCard.run(Custom.config)` (where `Custom.config` is a table of per-wiki overrides — see Section 7).
2. `Legacy.run` retrieves all stashed args via `Template.retrieveReturnValues('LegacyTeamCard')`.
3. First entry = header (from `columns start`); remaining entries = cards (from each `TeamCard`).
4. Header is mapped into TP top-level args (`minimumplayers`, `store`, `date`); per-card `import=false` is set on each opponent.
Copy link
Copy Markdown
Collaborator

@Rathoz Rathoz May 7, 2026

Choose a reason for hiding this comment

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

Top level date should not be needed (doesn't exist), only opponent level date?

Comment on lines +24 to +27
Wiki templates (on-wiki, edited at deploy):
Template:TeamCard columns start → invoke Module:Template fn=stashArgs namespace=LegacyTeamCard
Template:TeamCard → invoke Module:Template fn=stashArgs namespace=LegacyTeamCard
Template:TeamCard columns end → invoke Module:TeamCard/Legacy/Custom fn=run
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Technically one more tempalte that we need to care about at deploy. The toogle pplayers button

6. The wrapper sets the `team` / `teamRR` global page vars from the first non-TBD card (preserving an old TC behavior that TP's `setPageVars` doesn't cover).
7. The collected TP args are passed into a render path equivalent to `TeamParticipantsController.fromTemplate`, which itself calls `TeamParticipantsRepository.save` (storing in a TC-compatible shape) and `TeamParticipantsRepository.setPageVars` (defining the per-team / per-player wiki vars).

## Section 1 — Module layout & wiki templates
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Do we need to care about TeamPartipantGroups (mapping the old Team Card manual groupings into the new one)?

Comment on lines +85 to +86
| `Template:TeamCard columns start` | `<div class="template-box">…<#vardefine>` | `{{#invoke:Lua\|invoke\|module=Template\|fn=stashArgs\|namespace=LegacyTeamCard}}` |
| `Template:TeamCard` | `{{#invoke:Lua\|invoke\|module=TeamCard\|fn=draw\|...}}` | `{{#invoke:Lua\|invoke\|module=Template\|fn=stashArgs\|namespace=LegacyTeamCard}}` |
Copy link
Copy Markdown
Collaborator

@Rathoz Rathoz May 7, 2026

Choose a reason for hiding this comment

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

Just FYI, may need to insert an empty div or something similiar inorder for MW parser to be happy, otherwise it may insert
for each call

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

yes you need to insert empty div for mw not to add a ton of linebreaks

| TC header param | TP top-level arg | Notes |
|---|---|---|
| `defaultRowNumber` | `minimumplayers` | Closest semantic match. |
| `disable_storage`/`nostorage` (header-level) | `store = false` (top-level) | Honored only when set on the header, since TP's `store` is top-level. Per-card occurrences are ignored (out-of-scope). |
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Never set on the heading in TC afaik


Hardcoded by the wrapper:
- `import = false` is set **per card** (not at header level — TP reads `import` off each Opponent), so old pages use explicit rosters.
- `store` defaults to true (TP's default) unless the header disabled storage. TP's `Repository.save` produces records with the same `objectName` shape as old TC and the same legacy participant fields via `Opponent.toLegacyParticipantData`.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

store doesn't need to be hardcoded tby the wrapper. The existing logic will take care o whther r not it's needed. Hardcoding would force it to store even if SaveLpdb=false from wiki vars.

Hardcoded by the wrapper:
- `import = false` is set **per card** (not at header level — TP reads `import` off each Opponent), so old pages use explicit rosters.
- `store` defaults to true (TP's default) unless the header disabled storage. TP's `Repository.save` produces records with the same `objectName` shape as old TC and the same legacy participant fields via `Opponent.toLegacyParticipantData`.
- `date` — passed through if set on header, else TP's tournament-date default applies.
Copy link
Copy Markdown
Collaborator

@Rathoz Rathoz May 7, 2026

Choose a reason for hiding this comment

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

Don't think that date needs to be set by the wrapper (doesn't exist on this level afik in TC). TP handles fallbacks

- `store` defaults to true (TP's default) unless the header disabled storage. TP's `Repository.save` produces records with the same `objectName` shape as old TC and the same legacy participant fields via `Opponent.toLegacyParticipantData`.
- `date` — passed through if set on header, else TP's tournament-date default applies.

Before invoking the TP render, the wrapper also sets two global page vars from the first non-TBD card (matching old TC behavior): `team` (resolved team name at `tournament_date`) and `teamRR` (redirect-resolved name). TP's `setPageVars` does the per-team `<TeamName>_pN` style vars itself, so those are not duplicated here.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

What? Is this needed? Not sure


Before invoking the TP render, the wrapper also sets two global page vars from the first non-TBD card (matching old TC behavior): `team` (resolved team name at `tournament_date`) and `teamRR` (redirect-resolved name). TP's `setPageVars` does the per-team `<TeamName>_pN` style vars itself, so those are not duplicated here.

If the first stash entry contains a `team` key (i.e. it looks like a card, not a header — defensive case for pages where `columns start` is missing or malformed), treat all entries as cards and synthesize an empty header.
Copy link
Copy Markdown
Collaborator

@Rathoz Rathoz May 7, 2026

Choose a reason for hiding this comment

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

Spit out a warning or tracking category if this happens. The "columns end" template might be missing then too

|---|---|---|
| `link` (or fallback to `team`) | positional `[1]` (template) | TC's `team` is the display name, `link` is the team template. The wrapper uses `args.link or args.team` for the TP template arg. |
| `team` (display name) | dropped | TP derives display from the team template; no separate display override. |
| `team2`/`team3` set | TP `contenders` (list of team templates) | Maps to TP's `contenders` parsing path: opponent becomes TBD with `potentialQualifiers` populated from each team template (`Opponent.readOpponentArgs({type=team, template=…})`). `link2`/`link3` are used as templates if present. |
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Don't forget about team when using team2, team3 for contenders

Comment on lines +119 to +120
| `image1`/`imagedark1`/`imagesize` | dropped | TP gets logos from team templates. Image override (#7295) was reverted (#7449). |
| `flag` (header flag) | dropped | No TP equivalent. |
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
| `image1`/`imagedark1`/`imagesize` | dropped | TP gets logos from team templates. Image override (#7295) was reverted (#7449). |
| `flag` (header flag) | dropped | No TP equivalent. |
| `image1`/`imagedark1`/`imagesize` | dropped | Not relevant, using team templates |
| `flag` (header flag) | dropped | Not relevant |

Comment on lines +127 to +128
| `notes` | appended to `notes` list as `{text=notes, highlighted=false}` | |
| `inotes` | appended to `notes` list as `{text=inotes, highlighted=false}` | If both `notes` and `inotes` are set, both entries are added to the TP `notes` list. |
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The text parameter is wrong I think? The text should be the onctent of the note or inote, not a hardcoded string.

Copy link
Copy Markdown
Collaborator

@Rathoz Rathoz May 7, 2026

Choose a reason for hiding this comment

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

Suggested change
| `notes` | appended to `notes` list as `{text=notes, highlighted=false}` | |
| `inotes` | appended to `notes` list as `{text=inotes, highlighted=false}` | If both `notes` and `inotes` are set, both entries are added to the TP `notes` list. |
| `notes` | appended to `notes` list as `{[1] = value, highlighted=false}` | |
| `inotes` | appended to `notes` list as `{[1] = value, highlighted=false}` | If both `notes` and `inotes` are set, both entries are added to the TP `notes` list. |

It's this right?

Comment on lines +164 to +165
| `pNdnp` (truthy) | `played = false` | `dnp` wins over `played`/`result` if both set. |
| `pNplayed` / `pNresult` | `played` (boolean) | |
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Verify functionality when in combination with certain config parameters. They can interact weirdly, especially with, e.g., subs.

Comment on lines +186 to +187
| `c1` (default) | `role = head coach` | First coach is head coach. Override via per-wiki `coachRoles` config (Section 7). |
| `c2..cN` (default) | `role = coach` | Override via per-wiki `coachRoles` config. |
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Don't assume this. Any coach without a role should be assumed to be the role "Coach".


**Coach mapping** (per `cN`, `scN`, `fcN`, `t2cN`, `t3cN`):

| TC param | TP `Person` field | Notes |
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think cNpos needs to be mapped as well


| Key | Type | Default | Purpose |
|---|---|---|---|
| `coachRoles` | `string[]` | `{'head coach', 'coach'}` | Role assigned to `cN` by index — `coachRoles[1]` → `c1`, `coachRoles[2]` → `c2`, with `'coach'` for any further coaches beyond the array length. |
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Don't think this is needed. Map by cNpos. Default to coach

| Key | Type | Default | Purpose |
|---|---|---|---|
| `coachRoles` | `string[]` | `{'head coach', 'coach'}` | Role assigned to `cN` by index — `coachRoles[1]` → `c1`, `coachRoles[2]` → `c2`, with `'coach'` for any further coaches beyond the array length. |
| `positionMapping` | `table<string, string>` | `{}` (identity / TP-RoleUtil-only) | Maps TC `pNpos` values to TP `role` values when the wiki uses non-standard position labels (e.g. dota2 might map `1` → `'carry'`). When empty, `pNpos` is passed through as-is and `RoleUtil.readRoleArgs` normalizes it. |
Copy link
Copy Markdown
Collaborator

@Rathoz Rathoz May 7, 2026

Choose a reason for hiding this comment

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

Should be normalized later anyway. Probably not needed

Comment on lines +293 to +295
| `playerParamMap` | `table<string, string>` | `{}` | Optional per-wiki rename of TC player suffixes to TP person fields (e.g. `{ ['pNheroes'] = 'extradata.heroes' }`) for wiki-specific input. Empty default; rarely needed. |
| `coachParamMap` | `table<string, string>` | `{}` | Same shape as `playerParamMap`, applied to `cN`/`scN`/`fcN` etc. |
| `cardParamMap` | `table<string, string>` | `{}` | Per-wiki rename of TC card-level params to TP opponent fields. |
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Not sure if theres are needed outside of dota. I think only dota need a forced number mapping

| `playerParamMap` | `table<string, string>` | `{}` | Optional per-wiki rename of TC player suffixes to TP person fields (e.g. `{ ['pNheroes'] = 'extradata.heroes' }`) for wiki-specific input. Empty default; rarely needed. |
| `coachParamMap` | `table<string, string>` | `{}` | Same shape as `playerParamMap`, applied to `cN`/`scN`/`fcN` etc. |
| `cardParamMap` | `table<string, string>` | `{}` | Per-wiki rename of TC card-level params to TP opponent fields. |

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Missing config for the very important for biz logic property

subdnpdefault

@ElectricalBoy ElectricalBoy removed g: arenafps ArenaFPS labels May 7, 2026
Copy link
Copy Markdown
Collaborator

@hjpalpha hjpalpha left a comment

Choose a reason for hiding this comment

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

this wrapper is not applicable for sc, sc2, sg

Comment thread docs/superpowers/specs/2026-05-06-teamcard-legacy-wrapper-design.md

## Out of scope

- Per-wiki bot-edit work to insert `{{TeamCard columns start}}` / `{{TeamCard columns end}}` around naked `{{TeamCard}}` runs. The wrapper assumes columns markers are always present.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

maybe a bot run with
"\{\{[bB]ox\s*\|\s*start[^\}]*\}\}\s*\{\{[tT]eamCard" "{{TeamCard columns start}}\n{{TeamCard"
"\{\{[bB]ox\s*\|\s*break[^\}]*\}\}\s*\{\{[tT]eamCard" "{{TeamCard"
"\{\{[tT]eamCard([^\}]*)\}\}\s*\{\{[bB]ox\s*\|\s*end\}\}" "{{TeamCard\1}}\n{{TeamCard columns end}}"
prior?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

note for myself - prep bot run on sc (<2k), sc2 (~300), sg (<100):

pwb replace -lang:starcraft2 -transcludes:TeamCard -regex -summary:"prep for conversion" "\{\{[bB]ox\s*\|\s*start[^\}]*\}\}\s*\{\{[tT]eamCard" "{{TeamList\n|{{TeamCard" "\{\{[bB]ox\s*\|\s*break[^\}]*\}\}\s*\{\{[tT]eamCard" "|{{TeamCard" "\{\{[tT]eamCard([^\}]*)\}\}\s*\{\{[bB]ox\s*\|\s*end\}\}" "|{{TeamCard\1}}\n}}"

allows the wrapper in place apply to be a simple template adjust + purge run
(for subst inner ones need to be converted to use json (with subst) plus the outer one using the conversion wrapper which generates the wiki code)

Comment thread docs/superpowers/specs/2026-05-06-teamcard-legacy-wrapper-design.md Outdated
Comment thread docs/superpowers/specs/2026-05-06-teamcard-legacy-wrapper-design.md Outdated
Comment thread docs/superpowers/specs/2026-05-06-teamcard-legacy-wrapper-design.md Outdated
Comment thread docs/superpowers/specs/2026-05-06-teamcard-legacy-wrapper-design.md Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

c: team_card c: team_participant documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants