Skip to content

Commit 3fba646

Browse files
committed
v2.11.3 — Twin-spool repair finished: the two chips of a spool now agree on remaining weight + container weight (repair master = most-recently-updated chip; flag twinFix.v5, re-runs once), so the stock value is consistent and matches a friend's view. Mis-linked pairs (two different products glued by the timestamp auto-linker) are now UN-linked, and the auto-linker guards on product identity so it stops re-merging them. Rack comparison made idempotent (canonical slot key) — no more repair ping-pong.
Detail panel: "Ranger auto" now updates the Emplacement section IN PLACE (surgical swap of just that section — no full rebuild, so the panel keeps its scroll + media, no jump-to-top). Emplacement card restyled: icon-only auto-store button (larger 3-star "AI" sparkle, hover lights up the whole card via :has()), and a short one-word not-stored label ("Unracked"/"Non rangée"/…) across 9 locales.
1 parent 2fbbc61 commit 3fba646

18 files changed

Lines changed: 358 additions & 103 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,21 @@ Versions follow [Semantic Versioning](https://semver.org/).
55

66
---
77

8+
## v2.11.3 — 2026-07-15
9+
10+
### Changed
11+
12+
- **Twin-spool repair — source of truth is now the most-recently-updated chip.** The one-shot reconciliation (`reconcileTwinFields`) previously took whichever chip the inventory *displayed* (the smaller-UID one `deduplicateTwins` keeps) as authoritative. It now picks the chip with the greater `updatedAt` — the one you touched last (a fresh weigh-in, a just-set container) — so a conflict resolves to your latest intent even when the displayed chip held a stale value; ties fall back to the displayed chip for determinism. `updatedAt` parsing handles a live Firestore `Timestamp`, the serialized `{seconds}` / `{_seconds}` forms and a raw epoch — `renderer/inventory.js`.
13+
- **Twin repair now guards on product identity and breaks bad links.** A pair is force-synced only when both chips share the same `_spoolGroupKey` (`id_product` for Tiger Tag+, brand/material/colour/aspect for maker). Two chips that are genuinely *different* products were mis-linked (see the auto-linker fix below); the pass now clears `twin_tag_uid` on both docs so they become independent spools again — timestamp-neutral, counted as `unlinked` and shown in the Debug repair line. This stops one spool's fields overwriting an unrelated one's, and un-merges two different products that were shown (and valued) as one — `renderer/inventory.js`.
14+
- **Spool detail panel — storage-location card redesigned.** The auto-store control is now an icon-only button: a larger (16 px) sparkle with an `aria-label` (no text label, no hover title), a clear hover state (soft-primary background + border, icon turns primary and scales up), and — via `:has()` — hovering it lights up the whole location card (border, fill, label, box icon) so it is obvious what the action will fill. The not-stored status is a one-word label ("Unracked" / "Non rangée" / …) instead of "Pas rangée dans un rack". `icon_sparkle.svg` was redrawn from a magic-wand-plus-sparkles into a filled **3-star "AI" glyph** (also used by the rack autofill menu item) — `renderer/inventory.js`, `renderer/css/10-settings.css`, `assets/svg/icons/icon_sparkle.svg`.
15+
16+
### Fixed
17+
18+
- **The two chips of a twin spool now agree on remaining weight and container weight.** The repair mirrored image / container-id / rack / tags / note between twins but never the **weight**, so one physical spool's two chips could report different grams (e.g. 194 g vs 1000 g) — making the stock value swing with whichever chip was displayed, and diverge between your view and a friend's. Weight (`weight_available`) and container weight are now aligned to the freshest chip (timestamp-neutral); the container field compares `container_weight`, not just `container_id`, so a weight-only drift is repaired. Repair flag bumped to `tigertag.twinFix.v5.*` so every account re-runs the pass once — `renderer/inventory.js` (`reconcileTwinFields`, `_TWIN_FIELDS`).
19+
- **The twin auto-linker no longer merges two different products.** `autoLinkTwinsByTimestamp` paired chips by `id_tigertag` + chip-timestamp proximity (≤ 2 s) alone, so two unrelated spools programmed seconds apart at the factory were glued into one twin — and re-glued on every snapshot, undoing the repair's unlink. It now also requires an identical `_spoolGroupKey`. This is the root cause of the mis-linked pairs the repair breaks — `renderer/inventory.js`.
20+
- **The twin repair is now idempotent on the rack slot.** The rack field compared both the modern `rack` object and the legacy flat `rack_id`, but the copy only ever wrote the object, so a pair with mixed shapes never converged and the repair rewrote it on every pass (the "docs filled" count ping-ponging on repeated Debug runs). Comparison now uses a canonical slot key (`_twinRackSlot`) tolerant of both shapes — `renderer/inventory.js`.
21+
- **The detail panel reflects an auto-store immediately, and surgically.** Clicking "Ranger auto" wrote only the `rack` field (no timestamp), which `_rowSignature` ignores, so the "Emplacement" section did not repaint until the panel was reopened; forcing a full rebuild instead reset the panel scroll (a visible jump to the top) and reloaded the image/video. The structural signature is now split into a core (everything except the slot) and a location signature, so a location-only change swaps just the `.panel-storage-loc` node and re-wires it (`_patchDetailLocation` / `_wireStorageLoc`), leaving scroll and media intact — `renderer/inventory.js`.
22+
823
## v2.11.2 — 2026-07-15
924

1025
### Changed

‎FEATURES.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Tiger Studio Manager — Feature Catalogue
22

3-
Tiger Studio Manager is the Electron desktop companion to the TigerTag ecosystem: a filament-inventory manager built around RFID/NFC-tagged spools ("TigerTag" chips), a fully-digital "TigerCloud" tier, live 3D-printer integration across six brands, physical storage/rack management, a Firebase-backed social layer (friends, shareable wishlists, public profiles), and companion hardware (TD1S color sensor, TigerScale, TigerPOD dual-reader stand). This document catalogues every **shipped** feature, grouped by domain, current as of **v2.11.2**. Per-version release detail lives in `CHANGELOG.md`; forward-looking / in-progress work lives in `ROADMAP.md`.
3+
Tiger Studio Manager is the Electron desktop companion to the TigerTag ecosystem: a filament-inventory manager built around RFID/NFC-tagged spools ("TigerTag" chips), a fully-digital "TigerCloud" tier, live 3D-printer integration across six brands, physical storage/rack management, a Firebase-backed social layer (friends, shareable wishlists, public profiles), and companion hardware (TD1S color sensor, TigerScale, TigerPOD dual-reader stand). This document catalogues every **shipped** feature, grouped by domain, current as of **v2.11.3**. Per-version release detail lives in `CHANGELOG.md`; forward-looking / in-progress work lives in `ROADMAP.md`.
44

55
---
66

‎WORKLOG.md‎

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,24 @@
1-
# Worklog — v2.11.2
1+
# Worklog — v2.11.3 (in progress)
22

33
## Added
44

55
## Changed
6-
- **Twin-field repair now resolves conflicts, not just gaps — the DISPLAYED spool wins.** The v2.11.1 one-shot repair filled a twin's hollow chip but left genuine conflicts (both chips carrying a *different* container or custom image, set on each before mirroring existed) untouched. Real friend data showed 8 such pairs (7 container, 1 image), some with different container *weights* → the displayed net weight depended on which chip the UI happened to show. The reconciler now treats the twin the inventory actually displays (the one `deduplicateTwins` keeps — chosen before the sort, so independent of the user's sort column) as the source of truth: its per-spool fields overwrite the other chip's, resolving conflicts to exactly what the user sees; a hollow displayed chip is still filled from its twin. Flag bumped to `tigertag.twinFix.v2.*` so accounts that already ran the fill-gaps pass get one more pass to settle conflicts; still timestamp-neutral (never writes the chip `timestamp` or `updatedAt`) — `renderer/inventory.js` (`reconcileTwinFields`).
6+
7+
## Changed
8+
- Twin-tag reconciliation source of truth is now the **most-recently-updated chip** (`max updatedAt`), not the displayed/smaller-UID spool — the master is evolutive, following whichever chip you touched last (fresh weigh-in, just-set container…). On a tie it falls back to the displayed spool for determinism. This fixes conflicts where the displayed chip held a stale value that the old rule would have wrongly kept. `updatedAt` parsing handles a live Firestore Timestamp, the serialized `{seconds}`/`{_seconds}` forms and a raw epoch. — `reconcileTwinFields`, `renderer/inventory.js`
9+
- Twin reconciliation now guards on **same product identity** and **breaks bad links**: a pair is force-synced only when both chips share the same `_spoolGroupKey` (id_product for Tag+, brand/material/colour/aspect for maker). A pair whose two chips are *different* products was mis-linked — the pass now clears `twin_tag_uid` on both docs so they become independent spools again (timestamp-neutral), counted as `unlinked` and surfaced in the Debug repair line. This prevents one spool's fields from overwriting an unrelated one's, and fixes two genuinely-different products being shown (and valued) as one — `reconcileTwinFields`, `renderer/inventory.js`
10+
11+
## Changed
12+
- Detail panel "Emplacement": the **auto-store button is now icon-only** — a larger (16 px) sparkle icon with `aria-label` (no text label, no title), and a clear hover state (soft primary background + border, icon turns primary and scales up) so it's obvious the cursor is on it; hovering the button also **lights up the whole location card** (border + fill + label + box icon in primary, via `:has()`) so the user sees what the action will fill. The not-stored status is a short one-word label ("Unracked" / "Non rangée" / …) instead of the long "Pas rangée dans un rack" phrase — `renderer/inventory.js`, `renderer/css/10-settings.css`
13+
- `icon_sparkle.svg` redrawn as a filled **3-star "AI" sparkle** (was a magic-wand + sparkles) — the conventional AI-action glyph; shared by the detail-panel auto-store button and the rack autofill menu item — `assets/svg/icons/icon_sparkle.svg`
714

815
## Fixed
16+
- Detail panel now reflects an **auto-store** ("Ranger auto") immediately **and surgically**: the location section is patched in place, never a full rebuild. `refreshOpenDetail`'s early-return was gated on `_rowSignature` alone (which omits the rack slot), so an auto-store — writing only `rack`, no timestamp — never repainted the "Emplacement" section until reopened; a naive fix rebuilt the whole panel, which reset the scroll (a visible "jump to top") and reloaded the image/video. Now the structural signature is split into a core (everything except the slot) + a location signature: a location-only change swaps just the `.panel-storage-loc` node and re-wires it (`_patchDetailLocation` / `_wireStorageLoc`, mirroring the toolbox surgical pattern), keeping scroll + media intact — `renderer/inventory.js`
17+
- Twin auto-linker (`autoLinkTwinsByTimestamp`) no longer pairs two chips that are **different products**: it linked by `id_tigertag` + chip-timestamp proximity (≤2 s) alone, so two unrelated spools programmed seconds apart got merged into one twin (and re-merged on every snapshot, undoing the reconciler's unlink). It now also requires an identical `_spoolGroupKey` — the root cause of the mis-linked pairs — `renderer/inventory.js`
18+
- Twin reconciliation is now **idempotent on rack**: the field compared the `rack` object AND the legacy flat `rack_id`, but `copy` only ever wrote the object — so a pair with mixed rack shapes never converged and the repair re-wrote it on every pass (visible as the "docs filled" count ping-ponging on repeated Repair clicks). Comparison now uses a canonical slot key (`_twinRackSlot`) tolerant of both shapes — `renderer/inventory.js`
19+
- Twin-tag spools now keep their **remaining weight** and **container weight** in sync between the two chips — the repair pass (`reconcileTwinFields` / `_TWIN_FIELDS`) previously mirrored box/picture/rack/tags/note but not weight, so the two chips of one physical spool could report different grams (e.g. 194 g vs 1000 g). This made the stock value swing depending on which chip was displayed, and diverge between own-view and friend-view. Now the two docs align to the freshest chip's weight (timestamp-neutral); the container field also compares `container_weight` (not just `container_id`) so a weight-only drift is repaired. Repair flag bumped `twinFix.v2 → v3` so accounts re-run the pass once — `renderer/inventory.js`
920

1021
## Removed
1122

1223
## i18n
24+
- Changed: `storageNotPlaced` shortened to a one-word label ("Unracked" / "Non rangée" / …) — 9 locales

‎assets/svg/icons/icon_sparkle.svg‎

Lines changed: 1 addition & 1 deletion
Loading

‎data/release-notes/v2.11.3.md‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Tiger Studio Manager v2.11.3
2+
3+
The final round of twin-tag spool cleanup, plus a tidier auto-store.
4+
5+
## Fixed
6+
7+
- The two linked NFC tags of one spool now always agree on the **remaining weight** (and the box), so the stock value reads the same whichever tag the app happens to show — and matches what a friend sees on your inventory.
8+
- Two genuinely **different** spools that had been wrongly linked together as one are now separated back into two, each with its own details and value.
9+
- Clicking **Auto-store** now updates the spool's location on the spot, without the details panel jumping back to the top.
10+
11+
## Changed
12+
13+
- The **Auto-store** button in a spool's details is now a clear sparkle icon that lights up — along with the whole location card — when you hover it, so you can see exactly where the spool will go. The "not stored" label is shorter and reads cleanly in every language.
14+
15+
---
16+
17+
📖 **[Full changelog](https://github.com/TigerTag-Project/TigerTag-Studio-Manager/blob/main/CHANGELOG.md)** · ⬇️ Grab the installer for your OS from the **Assets** below (macOS `.dmg`, Windows `Setup .exe`, Linux `.AppImage`).

‎data/whatsnew.json‎

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6292,5 +6292,60 @@
62926292
}
62936293
}
62946294
]
6295+
},
6296+
"2.11.3": {
6297+
"date": "2026-07-15",
6298+
"items": [
6299+
{
6300+
"icon": "link",
6301+
"title": {
6302+
"en": "Your twin spools stopped arguing",
6303+
"fr": "Tes bobines jumelles se sont réconciliées",
6304+
"de": "Deine Zwillingsspulen sind sich endlich einig",
6305+
"es": "Tus bobinas gemelas dejaron de discutir",
6306+
"it": "Le tue bobine gemelle hanno smesso di litigare",
6307+
"zh": "你的双标签线盘终于一致了",
6308+
"pt": "As tuas bobinas gêmeas pararam de discutir",
6309+
"pt-pt": "As tuas bobinas gémeas pararam de discutir",
6310+
"pl": "Twoje bliźniacze szpule przestały się kłócić"
6311+
},
6312+
"body": {
6313+
"en": "The two NFC tags on one spool now agree on how much filament is left, so your stock value reads the same everywhere — and matches what your friends see. Bonus: two different spools mixed up as one are back to being two.",
6314+
"fr": "Les deux puces NFC d’une même bobine sont enfin d’accord sur le poids restant : ta valeur de stock est la même partout — et colle à ce que voient tes amis. En bonus, deux bobines différentes collées par erreur redeviennent deux.",
6315+
"de": "Die zwei NFC-Tags einer Spule sind sich jetzt einig, wie viel Filament übrig ist — dein Lagerwert stimmt überall und passt zu dem, was deine Freunde sehen. Bonus: zwei versehentlich verschmolzene Spulen sind wieder zwei.",
6316+
"es": "Las dos etiquetas NFC de una bobina ya coinciden en cuánto filamento queda, así que el valor de tu stock es el mismo en todas partes — y cuadra con lo que ven tus amigos. Extra: dos bobinas distintas fundidas en una vuelven a ser dos.",
6317+
"it": "I due tag NFC di una bobina ora concordano su quanto filamento resta, così il valore del tuo stock è uguale ovunque — e combacia con ciò che vedono i tuoi amici. Bonus: due bobine diverse unite per sbaglio tornano a essere due.",
6318+
"zh": "同一线盘的两个 NFC 标签现在对剩余用量达成一致,你的库存价值在哪儿看都一样——也和好友看到的对得上。附赠:被误当成一卷的两卷不同线盘又变回两卷。",
6319+
"pt": "As duas tags NFC de uma bobina agora concordam sobre quanto filamento resta, então o valor do teu stock é o mesmo em todo o lado — e bate com o que os teus amigos veem. Bônus: duas bobinas diferentes coladas por engano voltaram a ser duas.",
6320+
"pt-pt": "As duas tags NFC de uma bobina agora concordam sobre quanto filamento resta, por isso o valor do teu stock é o mesmo em todo o lado — e coincide com o que os teus amigos veem. Bónus: duas bobinas diferentes coladas por engano voltaram a ser duas.",
6321+
"pl": "Dwa tagi NFC jednej szpuli zgadzają się teraz co do pozostałego filamentu, więc wartość magazynu jest wszędzie taka sama — i zgadza się z tym, co widzą znajomi. Bonus: dwie różne szpule sklejone przez pomyłkę znów są dwiema."
6322+
}
6323+
},
6324+
{
6325+
"icon": "sparkle",
6326+
"title": {
6327+
"en": "Auto-store, now with sparkle",
6328+
"fr": "Le rangement auto, version paillettes",
6329+
"de": "Auto-Einlagern, jetzt mit Glitzer",
6330+
"es": "Guardado automático, ahora con brillo",
6331+
"it": "Sistemazione automatica, ora con scintillio",
6332+
"zh": "自动归位,闪亮登场",
6333+
"pt": "Arrumação automática, agora com brilho",
6334+
"pt-pt": "Arrumação automática, agora com brilho",
6335+
"pl": "Auto-odkładanie, teraz z błyskiem"
6336+
},
6337+
"body": {
6338+
"en": "The auto-store button is a bright sparkle that lights up the whole slot card when you hover — so you see exactly where your spool will land. Click it and the spot updates on the spot, no more jumping back to the top.",
6339+
"fr": "Le bouton de rangement auto est une étincelle qui illumine toute la carte au survol — tu vois pile où la bobine va atterrir. Un clic et l’emplacement se met à jour sur place, fini le saut vers le haut.",
6340+
"de": "Der Auto-Einlagern-Knopf ist ein helles Funkeln, das beim Überfahren die ganze Platz-Karte aufleuchten lässt — du siehst genau, wo deine Spule landet. Ein Klick und der Platz aktualisiert sich direkt, kein Sprung mehr nach oben.",
6341+
"es": "El botón de guardado automático es un destello que ilumina toda la tarjeta al pasar el ratón — ves justo dónde caerá tu bobina. Un clic y el sitio se actualiza al momento, sin saltar arriba del todo.",
6342+
"it": "Il pulsante di sistemazione automatica è uno scintillio che illumina tutta la scheda al passaggio del mouse — vedi esattamente dove finirà la bobina. Un clic e il posto si aggiorna sul posto, niente più salto in cima.",
6343+
"zh": "自动归位按钮是个闪亮的星光,悬停时整张位置卡都会点亮——你能看清线盘会落在哪里。一点就地更新,不再蹦回顶部。",
6344+
"pt": "O botão de arrumação automática é um brilho que ilumina o cartão inteiro ao passar o rato — vês exatamente onde a bobina vai parar. Um clique e o lugar atualiza-se ali mesmo, sem saltar para o topo.",
6345+
"pt-pt": "O botão de arrumação automática é um brilho que ilumina o cartão inteiro ao passar o rato — vês exatamente onde a bobina vai parar. Um clique e o lugar atualiza-se ali mesmo, sem saltar para o topo.",
6346+
"pl": "Przycisk auto-odkładania to jasny błysk, który po najechaniu podświetla całą kartę miejsca — widzisz dokładnie, gdzie wyląduje szpula. Klik i miejsce aktualizuje się od razu, bez skakania na górę."
6347+
}
6348+
}
6349+
]
62956350
}
62966351
}

‎package.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "tigertag-inventory",
3-
"version": "2.11.2",
3+
"version": "2.11.3",
44
"description": "Tiger Studio Manager — desktop app",
55
"main": "main.js",
66
"engines": {

0 commit comments

Comments
 (0)