You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Follow-ups from the Life/Light/Trickery/War Cleric domain wiring audit that need a design decision or new capability rather than a scoped bug fix. See the audit trace for how each finding was confirmed (real code, not just reasoning).
1. Design decision: wildcard presets always beat correct AI-mechanics data on fields the fingerprint doesn't cover
enrichFeatureLike (lib/import/enrich-import-modifiers.ts) applies SRD wildcard presets before merging AI-mechanics/phrase-detector detections. The cross-path dedup (isModifierRedundantAgainst / modifierInstanceFingerprint in lib/import/detect-feature-modifiers.ts) is fingerprint-based, and the uses fingerprint only includes type/fixedAmount/abilityModifier — not recharge. So if a preset's uses recharge is stale or wrong, a correct AI-mechanics usesRecharge hint for the same feature is silently discarded as a "duplicate," because the preset was added to linkedModifiers first.
Confirmed concretely via War Priest (now fixed as a one-off stale-preset correction — see PR/commit), but the underlying ordering + fingerprint blind spot is general: any preset with a uses pool is exposed to this whenever its recharge drifts from official text and a re-import supplies a correct AI-mechanics hint.
Options to evaluate:
Make the uses fingerprint recharge-aware so a differing recharge is not treated as a duplicate (risk: could produce two coexisting uses pools where today's fingerprint intentionally treats near-duplicates as one).
Change merge priority so AI/detector-sourced uses data can patch/override a preset's recharge instead of being dropped outright.
Leave as-is and keep fixing individual stale presets as they're found during audits (status quo — cheap per-instance, but the class of bug will recur).
No code change proposed here — needs a decision on which direction before touching the shared dedup/merge logic, since it's load-bearing for every preset with a uses pool.
2. New capability: "bonus to a missed attack roll (self or ally, reaction)" has no wiring path
Guided Strike (War Domain, 2024 PHB — same pattern as the 2014 SRD version): "When you or a creature within 30 feet of you misses with an attack roll, you can expend a use of Channel Divinity and give that roll a +10 bonus... reaction if it's for another creature." Traced through the real pipeline — nothing wires (no mechanics[] kind, no phrase-detector rule, no preset).
The closest existing pattern is failedRollTriggerPreset (lib/compendium/enrich-srd-class-features.ts), used today only via hardcoded feature-name presets (Peerless Skill, Tactical Mind, Countercharm) — none targeting attack rolls or a reaction on someone else's roll.
Recommend: extend this into a proper mechanics[].kind (e.g. failed_roll_trigger) with rollKind including "attack", plus a targetScope: self | ally_in_range and useReaction flag, so this wires generically instead of needing a new hardcoded preset every time a class reuses the pattern (it will recur — Guided Strike is a classic).
3. To-do: narrative-only custom actions should still appear on the character sheet as actions
Per audit findings, these Channel-Divinity-cost (or similarly gated) features have real activation cost/timing but no matching characteristic/effect kind, so today they produce no sheet presence at all — not even a button — despite being real, frequently-used actions:
Preserve Life (Life Domain) — Channel Divinity, splits 5×Cleric-level HP among Bloodied creatures in range, capped at half max HP each
Radiance of the Dawn (Light Domain) — Channel Divinity, 30-ft emanation, Con save, 2d10+level radiant, half on success
War God's Blessing (War Domain) — Channel Divinity, cast Shield of Faith/Spiritual Weapon without a slot, no concentration
Ask (from the audit follow-up): even where there's no modifier to compute, these should show up on the character sheet as actions with their narrative text attached (name, activation cost/resource spend, description) rather than being invisible. This likely means a lighter-weight "custom action, no mechanical effect" characteristic/registration path distinct from the fully-modeled effect kinds — worth scoping as its own change since it probably benefits every future "complex/narrative-only" feature, not just these four.
Follow-ups from the Life/Light/Trickery/War Cleric domain wiring audit that need a design decision or new capability rather than a scoped bug fix. See the audit trace for how each finding was confirmed (real code, not just reasoning).
1. Design decision: wildcard presets always beat correct AI-mechanics data on fields the fingerprint doesn't cover
enrichFeatureLike(lib/import/enrich-import-modifiers.ts) applies SRD wildcard presets before merging AI-mechanics/phrase-detector detections. The cross-path dedup (isModifierRedundantAgainst/modifierInstanceFingerprintinlib/import/detect-feature-modifiers.ts) is fingerprint-based, and theusesfingerprint only includestype/fixedAmount/abilityModifier— not recharge. So if a preset'susesrecharge is stale or wrong, a correct AI-mechanicsusesRechargehint for the same feature is silently discarded as a "duplicate," because the preset was added tolinkedModifiersfirst.Confirmed concretely via War Priest (now fixed as a one-off stale-preset correction — see PR/commit), but the underlying ordering + fingerprint blind spot is general: any preset with a
usespool is exposed to this whenever its recharge drifts from official text and a re-import supplies a correct AI-mechanics hint.Options to evaluate:
usesfingerprint recharge-aware so a differing recharge is not treated as a duplicate (risk: could produce two coexistingusespools where today's fingerprint intentionally treats near-duplicates as one).usesdata can patch/override a preset's recharge instead of being dropped outright.No code change proposed here — needs a decision on which direction before touching the shared dedup/merge logic, since it's load-bearing for every preset with a
usespool.2. New capability: "bonus to a missed attack roll (self or ally, reaction)" has no wiring path
Guided Strike (War Domain, 2024 PHB — same pattern as the 2014 SRD version): "When you or a creature within 30 feet of you misses with an attack roll, you can expend a use of Channel Divinity and give that roll a +10 bonus... reaction if it's for another creature." Traced through the real pipeline — nothing wires (no
mechanics[]kind, no phrase-detector rule, no preset).The closest existing pattern is
failedRollTriggerPreset(lib/compendium/enrich-srd-class-features.ts), used today only via hardcoded feature-name presets (Peerless Skill, Tactical Mind, Countercharm) — none targeting attack rolls or a reaction on someone else's roll.Recommend: extend this into a proper
mechanics[].kind(e.g.failed_roll_trigger) withrollKindincluding"attack", plus atargetScope: self | ally_in_rangeanduseReactionflag, so this wires generically instead of needing a new hardcoded preset every time a class reuses the pattern (it will recur — Guided Strike is a classic).3. To-do: narrative-only custom actions should still appear on the character sheet as actions
Per audit findings, these Channel-Divinity-cost (or similarly gated) features have real activation cost/timing but no matching characteristic/effect kind, so today they produce no sheet presence at all — not even a button — despite being real, frequently-used actions:
Ask (from the audit follow-up): even where there's no modifier to compute, these should show up on the character sheet as actions with their narrative text attached (name, activation cost/resource spend, description) rather than being invisible. This likely means a lighter-weight "custom action, no mechanical effect" characteristic/registration path distinct from the fully-modeled effect kinds — worth scoping as its own change since it probably benefits every future "complex/narrative-only" feature, not just these four.
Audit source: Life/Light/Trickery/War Cleric domains, traced via
enrichWildcardFeaturePresets/aiMechanicsToDetections/detectFeatureModifiers/mergeFeatureModifierDetections.