diff --git a/.github/forge-posts/v1.4.4.md b/.github/forge-posts/v1.4.4.md index 01bcfff..a2530d7 100644 --- a/.github/forge-posts/v1.4.4.md +++ b/.github/forge-posts/v1.4.4.md @@ -17,19 +17,18 @@ spricht jetzt bei unbekannten ChatTypes. IPC-Callback-Methode jetzt einen 1-Zeilen-Banner darüber, der den Thread-Kontext direkt am Call-Site benennt (framework only, framework scheduled, any). Mehr Hilfe für künftige Reviews als ein abstraktes Threading-Kapitel - **Unsubscribe-Failure ist jetzt sichtbar.** `TryUnsubscribe` hat ein Honorific-Unsubscribe-Failure bisher als Debug - geloggt, was bei Standard-Loglevel verschluckt wurde. Eine geleakte Subscription kann den Service über - Plugin-Reloads hinweg leben lassen, also läuft der Log jetzt auf Warning + geloggt, was bei Standard-Loglevel verschluckt wurde. Eine geleakte Subscription kann den Service über Plugin-Reloads + hinweg leben lassen, also läuft der Log jetzt auf Warning - **AutoTranslate-Warmup blockiert den Plugin-Unload nicht mehr.** Der Cache-Warmup-Thread war ohne `IsBackground=true` - unterwegs, was den Unload um 100-300 ms verzögern konnte. Pattern-Match zu MessageManager und RetentionSweep - (beide seit v1.4.0) -- **Privacy-Filter loggt unbekannte ChatTypes.** Wenn FFXIV durch einen Patch einen neuen ChatType einführt der weder - in der Whitelist noch in den Defaults steht, wird er bisher silent durch den Failsafe geleitet. Jetzt loggt der - Filter einmalig pro Runtime eine Warning mit dem Type und dem Failsafe-Wert. Dedup über ein NonSerialized-HashSet, - also kein Log-Spam + unterwegs, was den Unload um 100-300 ms verzögern konnte. Pattern-Match zu MessageManager und RetentionSweep (beide + seit v1.4.0) +- **Privacy-Filter loggt unbekannte ChatTypes.** Wenn FFXIV durch einen Patch einen neuen ChatType einführt der weder in + der Whitelist noch in den Defaults steht, wird er bisher silent durch den Failsafe geleitet. Jetzt loggt der Filter + einmalig pro Runtime eine Warning mit dem Type und dem Failsafe-Wert. Dedup über ein NonSerialized-HashSet, also kein + Log-Spam - **Default-Flip für neue Installationen.** `PrivacyPersistUnknownChannels` startet bei neuen Configs jetzt auf `true`, - damit ein Patch-bedingt neuer ChatType nicht stillschweigend gedroppt wird bevor der User entscheiden kann. - Bestehende Configs behalten ihre Wahl, weil der Deserializer den Initializer überschreibt. Keine Migration, kein - Schema-Bump + damit ein Patch-bedingt neuer ChatType nicht stillschweigend gedroppt wird bevor der User entscheiden kann. Bestehende + Configs behalten ihre Wahl, weil der Deserializer den Initializer überschreibt. Keine Migration, kein Schema-Bump Keine User-sichtbaren Funktions-Änderungen außer dem Default-Flip für neue Installationen. Settings, Themes, Tabs und das Privacy-Verhalten für Bestand bleiben unangetastet. diff --git a/HellionChat/packages.lock.json b/HellionChat/packages.lock.json index d3d3517..486be32 100644 --- a/HellionChat/packages.lock.json +++ b/HellionChat/packages.lock.json @@ -1,110 +1,110 @@ { - "version": 1, - "dependencies": { - "net10.0-windows7.0": { - "DalamudPackager": { - "type": "Direct", - "requested": "[15.0.0, )", - "resolved": "15.0.0", - "contentHash": "411vwC8/X8Z/sQ2TI6v3SvOn66xFPeOjFn3Zn+h0d3Ox2t1kFm66AhDvmx/qcMwVrR+Hidxj0dadpQ2dgyXMBQ==" - }, - "DotNet.ReproducibleBuilds": { - "type": "Direct", - "requested": "[1.2.39, )", - "resolved": "1.2.39", - "contentHash": "fcFN01tDTIQqDuTwr1jUQK/geofiwjG5DycJQOnC72i1SsLAk1ELe+apBOuZ11UMQG8YKFZG1FgvjZPbqHyatg==" - }, - "MessagePack": { - "type": "Direct", - "requested": "[3.1.4, 4.0.0)", - "resolved": "3.1.4", - "contentHash": "BH0wlHWmVoZpbAPyyt2Awbq30C+ZsS3eHSkYdnyUAbqVJ22fAJDzn2xTieBeoT5QlcBzp61vHcv878YJGfi3mg==", - "dependencies": { - "MessagePack.Annotations": "3.1.4", - "MessagePackAnalyzer": "3.1.4", - "Microsoft.NET.StringTools": "17.11.4" + "version": 1, + "dependencies": { + "net10.0-windows7.0": { + "DalamudPackager": { + "type": "Direct", + "requested": "[15.0.0, )", + "resolved": "15.0.0", + "contentHash": "411vwC8/X8Z/sQ2TI6v3SvOn66xFPeOjFn3Zn+h0d3Ox2t1kFm66AhDvmx/qcMwVrR+Hidxj0dadpQ2dgyXMBQ==" + }, + "DotNet.ReproducibleBuilds": { + "type": "Direct", + "requested": "[1.2.39, )", + "resolved": "1.2.39", + "contentHash": "fcFN01tDTIQqDuTwr1jUQK/geofiwjG5DycJQOnC72i1SsLAk1ELe+apBOuZ11UMQG8YKFZG1FgvjZPbqHyatg==" + }, + "MessagePack": { + "type": "Direct", + "requested": "[3.1.4, 4.0.0)", + "resolved": "3.1.4", + "contentHash": "BH0wlHWmVoZpbAPyyt2Awbq30C+ZsS3eHSkYdnyUAbqVJ22fAJDzn2xTieBeoT5QlcBzp61vHcv878YJGfi3mg==", + "dependencies": { + "MessagePack.Annotations": "3.1.4", + "MessagePackAnalyzer": "3.1.4", + "Microsoft.NET.StringTools": "17.11.4" + } + }, + "Microsoft.Data.Sqlite": { + "type": "Direct", + "requested": "[10.0.7, )", + "resolved": "10.0.7", + "contentHash": "DZ6G2QuyPrsh5VS+wfiZbNBtYT6p+CkxXjD0aZHF04xso7QsG/uk0JpG30hzYlK6u/wtTzta1Dqfgbc/Sl2sDA==", + "dependencies": { + "Microsoft.Data.Sqlite.Core": "10.0.7", + "SQLitePCLRaw.bundle_e_sqlite3": "2.1.11", + "SQLitePCLRaw.core": "2.1.11" + } + }, + "morelinq": { + "type": "Direct", + "requested": "[4.4.0, )", + "resolved": "4.4.0", + "contentHash": "QX3bsK9oFeUXk8tFsc9NkI6NnCr8Ar/ex027p+ZZ/jdLCdX2RlryDtxUqZW5j45NVwn4E4Z4hzupsoMQd6Yxtg==" + }, + "Pidgin": { + "type": "Direct", + "requested": "[3.5.1, 4.0.0)", + "resolved": "3.5.1", + "contentHash": "zU7tkXlF3D6d2GLTjJDomAL3nnl4AwfZvSgSz8D4b+Ry21/clqedYlxBnEAkAU/bkGfEv6uRR7QCdWZUpKrB/g==" + }, + "SixLabors.ImageSharp": { + "type": "Direct", + "requested": "[3.1.12, 4.0.0)", + "resolved": "3.1.12", + "contentHash": "iAg6zifihXEFS/t7fiHhZBGAdCp3FavsF4i2ZIDp0JfeYeDVzvmlbY1CNhhIKimaIzrzSi5M/NBFcWvZT2rB/A==" + }, + "SQLitePCLRaw.lib.e_sqlite3": { + "type": "Direct", + "requested": "[3.50.3, )", + "resolved": "3.50.3", + "contentHash": "tVyhqQ8wxgedWiiPFChyZhE8I3PkOM/AE1azsj1qsdYUws13ONBFyi3aDxju4tD2kzedB2q5+50WrTyY0h2gMQ==" + }, + "MessagePack.Annotations": { + "type": "Transitive", + "resolved": "3.1.4", + "contentHash": "aVWrDAkCdqxwQsz/q0ldPh2EFn48M99YUzE9OvZjMq2RNLKz4o2z88iGFvSvbMqOWRweRvKPHBJZe22PRqzslQ==" + }, + "MessagePackAnalyzer": { + "type": "Transitive", + "resolved": "3.1.4", + "contentHash": "CTaSsN/liJ7MhLCAB7Z4ZLBNuVGCq9lt2BT/cbrc9vzGv89yK3CqIA+z9T19a11eQYl9etZHL6MQJgCqECRVpg==" + }, + "Microsoft.Data.Sqlite.Core": { + "type": "Transitive", + "resolved": "10.0.7", + "contentHash": "xVrtBg3M1wJlBDkoT0dXEYB/wSc8bIHJPYtw/bu1AqpWgF79uPSs87DAhERR/Ilumre6TKZa1cjMg3VUUObVLA==", + "dependencies": { + "SQLitePCLRaw.core": "2.1.11" + } + }, + "Microsoft.NET.StringTools": { + "type": "Transitive", + "resolved": "17.11.4", + "contentHash": "mudqUHhNpeqIdJoUx2YDWZO/I9uEDYVowan89R6wsomfnUJQk6HteoQTlNjZDixhT2B4IXMkMtgZtoceIjLRmA==" + }, + "SQLitePCLRaw.bundle_e_sqlite3": { + "type": "Transitive", + "resolved": "2.1.11", + "contentHash": "DC4nA7yWnf4UZdgJDF+9Mus4/cb0Y3Sfgi3gDnAoKNAIBwzkskNAbNbyu+u4atT0ruVlZNJfwZmwiEwE5oz9LQ==", + "dependencies": { + "SQLitePCLRaw.lib.e_sqlite3": "2.1.11", + "SQLitePCLRaw.provider.e_sqlite3": "2.1.11" + } + }, + "SQLitePCLRaw.core": { + "type": "Transitive", + "resolved": "2.1.11", + "contentHash": "PK0GLFkfhZzLQeR3PJf71FmhtHox+U3vcY6ZtswoMjrefkB9k6ErNJEnwXqc5KgXDSjige2XXrezqS39gkpQKA==" + }, + "SQLitePCLRaw.provider.e_sqlite3": { + "type": "Transitive", + "resolved": "2.1.11", + "contentHash": "Y/0ZkR+r0Cg3DQFuCl1RBnv/tmxpIZRU3HUvelPw6MVaKHwYYR8YNvgs0vuNuXCMvlyJ+Fh88U1D4tah1tt6qw==", + "dependencies": { + "SQLitePCLRaw.core": "2.1.11" + } + } } - }, - "Microsoft.Data.Sqlite": { - "type": "Direct", - "requested": "[10.0.7, )", - "resolved": "10.0.7", - "contentHash": "DZ6G2QuyPrsh5VS+wfiZbNBtYT6p+CkxXjD0aZHF04xso7QsG/uk0JpG30hzYlK6u/wtTzta1Dqfgbc/Sl2sDA==", - "dependencies": { - "Microsoft.Data.Sqlite.Core": "10.0.7", - "SQLitePCLRaw.bundle_e_sqlite3": "2.1.11", - "SQLitePCLRaw.core": "2.1.11" - } - }, - "morelinq": { - "type": "Direct", - "requested": "[4.4.0, )", - "resolved": "4.4.0", - "contentHash": "QX3bsK9oFeUXk8tFsc9NkI6NnCr8Ar/ex027p+ZZ/jdLCdX2RlryDtxUqZW5j45NVwn4E4Z4hzupsoMQd6Yxtg==" - }, - "Pidgin": { - "type": "Direct", - "requested": "[3.5.1, 4.0.0)", - "resolved": "3.5.1", - "contentHash": "zU7tkXlF3D6d2GLTjJDomAL3nnl4AwfZvSgSz8D4b+Ry21/clqedYlxBnEAkAU/bkGfEv6uRR7QCdWZUpKrB/g==" - }, - "SixLabors.ImageSharp": { - "type": "Direct", - "requested": "[3.1.12, 4.0.0)", - "resolved": "3.1.12", - "contentHash": "iAg6zifihXEFS/t7fiHhZBGAdCp3FavsF4i2ZIDp0JfeYeDVzvmlbY1CNhhIKimaIzrzSi5M/NBFcWvZT2rB/A==" - }, - "SQLitePCLRaw.lib.e_sqlite3": { - "type": "Direct", - "requested": "[3.50.3, )", - "resolved": "3.50.3", - "contentHash": "tVyhqQ8wxgedWiiPFChyZhE8I3PkOM/AE1azsj1qsdYUws13ONBFyi3aDxju4tD2kzedB2q5+50WrTyY0h2gMQ==" - }, - "MessagePack.Annotations": { - "type": "Transitive", - "resolved": "3.1.4", - "contentHash": "aVWrDAkCdqxwQsz/q0ldPh2EFn48M99YUzE9OvZjMq2RNLKz4o2z88iGFvSvbMqOWRweRvKPHBJZe22PRqzslQ==" - }, - "MessagePackAnalyzer": { - "type": "Transitive", - "resolved": "3.1.4", - "contentHash": "CTaSsN/liJ7MhLCAB7Z4ZLBNuVGCq9lt2BT/cbrc9vzGv89yK3CqIA+z9T19a11eQYl9etZHL6MQJgCqECRVpg==" - }, - "Microsoft.Data.Sqlite.Core": { - "type": "Transitive", - "resolved": "10.0.7", - "contentHash": "xVrtBg3M1wJlBDkoT0dXEYB/wSc8bIHJPYtw/bu1AqpWgF79uPSs87DAhERR/Ilumre6TKZa1cjMg3VUUObVLA==", - "dependencies": { - "SQLitePCLRaw.core": "2.1.11" - } - }, - "Microsoft.NET.StringTools": { - "type": "Transitive", - "resolved": "17.11.4", - "contentHash": "mudqUHhNpeqIdJoUx2YDWZO/I9uEDYVowan89R6wsomfnUJQk6HteoQTlNjZDixhT2B4IXMkMtgZtoceIjLRmA==" - }, - "SQLitePCLRaw.bundle_e_sqlite3": { - "type": "Transitive", - "resolved": "2.1.11", - "contentHash": "DC4nA7yWnf4UZdgJDF+9Mus4/cb0Y3Sfgi3gDnAoKNAIBwzkskNAbNbyu+u4atT0ruVlZNJfwZmwiEwE5oz9LQ==", - "dependencies": { - "SQLitePCLRaw.lib.e_sqlite3": "2.1.11", - "SQLitePCLRaw.provider.e_sqlite3": "2.1.11" - } - }, - "SQLitePCLRaw.core": { - "type": "Transitive", - "resolved": "2.1.11", - "contentHash": "PK0GLFkfhZzLQeR3PJf71FmhtHox+U3vcY6ZtswoMjrefkB9k6ErNJEnwXqc5KgXDSjige2XXrezqS39gkpQKA==" - }, - "SQLitePCLRaw.provider.e_sqlite3": { - "type": "Transitive", - "resolved": "2.1.11", - "contentHash": "Y/0ZkR+r0Cg3DQFuCl1RBnv/tmxpIZRU3HUvelPw6MVaKHwYYR8YNvgs0vuNuXCMvlyJ+Fh88U1D4tah1tt6qw==", - "dependencies": { - "SQLitePCLRaw.core": "2.1.11" - } - } } - } -} \ No newline at end of file +} diff --git a/README.md b/README.md index 9ca9a87..a4a23d0 100644 --- a/README.md +++ b/README.md @@ -287,15 +287,15 @@ An optional submission to the Dalamud main plugin repo (in addition to the custo ## Project Status **Version 1.4.4** — Threading and IPC safety polish on top of the v1.4.3 async-load foundation. The -`AutoTellTabsService` hot-path getter now reads from an `Interlocked` counter instead of taking a lock on every -render frame, with a resync hook for the snapshot-restore path in `SaveConfig` and a pure-helper test mirror in the -Build-Suite repo. The Honorific integration carries per-method threading banners so the framework-thread invariant is -visible at the call site, and an unsubscribe failure now logs at Warning instead of Debug — a leaked subscription -across plugin reloads is exactly the kind of thing that should not be silent. The AutoTranslate warmup thread is -finally marked `IsBackground = true`, matching the pattern used in `MessageManager` and `Plugin.RetentionSweep` since -v1.4.0. The privacy filter logs once per unknown ChatType so a future patch's added channel does not drop off the -radar, and new installs default `PrivacyPersistUnknownChannels` to `true` as a failsafe; existing configs keep their -explicit choice. No schema bump, no migration. Fifth sub-patch of the v1.4.x polish sweep series (as of 2026-05-12). +`AutoTellTabsService` hot-path getter now reads from an `Interlocked` counter instead of taking a lock on every render +frame, with a resync hook for the snapshot-restore path in `SaveConfig` and a pure-helper test mirror in the Build-Suite +repo. The Honorific integration carries per-method threading banners so the framework-thread invariant is visible at the +call site, and an unsubscribe failure now logs at Warning instead of Debug — a leaked subscription across plugin reloads +is exactly the kind of thing that should not be silent. The AutoTranslate warmup thread is finally marked +`IsBackground = true`, matching the pattern used in `MessageManager` and `Plugin.RetentionSweep` since v1.4.0. The +privacy filter logs once per unknown ChatType so a future patch's added channel does not drop off the radar, and new +installs default `PrivacyPersistUnknownChannels` to `true` as a failsafe; existing configs keep their explicit choice. +No schema bump, no migration. Fifth sub-patch of the v1.4.x polish sweep series (as of 2026-05-12). Hellion Chat is a standalone plugin, no longer a fork in the repository sense. Fully completed: diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 7f880f4..7754a78 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -20,21 +20,21 @@ unknown ChatType shows up. in sync with `Config.Tabs` from inside the existing mutation paths. `Initialize()` seeds the counter from the persisted Tabs list, and `SaveConfig`'s snapshot-restore path calls a new `ResyncTempTabCounter()` so the mid-step `RemoveAll` doesn't leave the counter drifting. Pure-helper test mirror lives in the Build-Suite repo -- `HonorificService` per-method threading banners replace the block comment at the bottom of the file. Each IPC - callback (`TryInitialPull`, `OnTitleChanged`, `OnReady`, `OnDisposing`, `TryUnsubscribe`) and the `CurrentTitle` - field carry a one-line `// Thread:` annotation so the framework-thread invariant is visible at the call site +- `HonorificService` per-method threading banners replace the block comment at the bottom of the file. Each IPC callback + (`TryInitialPull`, `OnTitleChanged`, `OnReady`, `OnDisposing`, `TryUnsubscribe`) and the `CurrentTitle` field carry a + one-line `// Thread:` annotation so the framework-thread invariant is visible at the call site - `TryUnsubscribe` log-level upgraded from `Debug` to `Warning`. A silent unsubscribe failure leaks a live subscription across plugin reloads, which is exactly the kind of issue that should not be at Debug -- `AutoTranslate.PreloadCache` thread now has `IsBackground = true` and a thread name. Without `IsBackground` the - warmup blocks plugin unload (typically 100-300 ms). Pattern-match to `MessageManager` (F6.1) and `Plugin.RetentionSweep` +- `AutoTranslate.PreloadCache` thread now has `IsBackground = true` and a thread name. Without `IsBackground` the warmup + blocks plugin unload (typically 100-300 ms). Pattern-match to `MessageManager` (F6.1) and `Plugin.RetentionSweep` (F9.3), both since v1.4.0 -- `Configuration.IsAllowedForStorage` adds a one-line `Plugin.Log.Warning` for the first occurrence of any ChatType - that isn't in `PrivacyPersistChannels`. Dedup via a `NonSerialized` `HashSet`, so the warning fires once - per runtime — not once per frame, not once per install. Failsafe routing through `PrivacyPersistUnknownChannels` - is unchanged +- `Configuration.IsAllowedForStorage` adds a one-line `Plugin.Log.Warning` for the first occurrence of any ChatType that + isn't in `PrivacyPersistChannels`. Dedup via a `NonSerialized` `HashSet`, so the warning fires once per + runtime — not once per frame, not once per install. Failsafe routing through `PrivacyPersistUnknownChannels` is + unchanged - `PrivacyPersistUnknownChannels` field default flipped from `false` to `true` for new installs via a constant in - `PrivacyDefaults`. Existing configs keep their explicit choice — the deserializer overrides the initializer. No - schema bump, no migration, no first-run banner + `PrivacyDefaults`. Existing configs keep their explicit choice — the deserializer overrides the initializer. No schema + bump, no migration, no first-run banner Modding & support: join Hellion Forge —