promotional bannermobile promotional banner

Ka0s KickCD

Tracks interrupt + CC cooldowns on a movable icon grid
Back to Files

1.2.1-release

File nameKickCD-1.2.1-release.zip
Uploaded
Jul 26, 2026
Downloads
15
Size
8.4 MB
Flavors
Retail
File ID
8513701
Type
R
Release
Supported game versions
  • 12.0.7

What's new

tag e0b19a7626a892d1be40c414ec2e2f1294f69f84 1.2.1-release
Author:    Tushar Saxena <tushar.saxena@gmail.com>
Date:    Sun Jul 26 20:11:00 2026 +0530

commit 0abaf716443cb75c8757139127a9abc3755bdfb9
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Sun Jul 26 14:40:01 2026 +0000

    Chore: prep for 1.2.1 release

    Patch, not a minor: the release is bugfixes and internals with no new
    user-facing features. The headline is issue #8, where the addon tracked
    nothing at all on non-English clients. There is a saved-variables schema
    bump (v2 -> v3) behind it, but it migrates transparently on login and each
    profile is caught as it activates, so nothing is asked of the user.

    Version stamped in KickCD.toc and NS.VERSION. README gains a Version History
    row and a rewritten "What's new" section.

    Two deliberate departures worth noting for the next bump:

    * The "What's new" section carries BOTH releases -- 1.2.1's fixes, then an
      "Also in 1.2.0" subsection with the previous release's bullets. 1.2.1 is a
      small patch riding on a large feature release, so anyone arriving from
      1.1.x sees the whole picture. The convention is that this section covers
      only the current release, so the "Also in 1.2.0" block should be dropped
      when 1.3.0 lands rather than inherited.
    * `/kcd debug duration` was added and removed inside this same release
      window, so it appears in neither the release notes nor the history row.
      Users never saw it; the commits carry that history instead.

    docs/smoke-tests.md's "saved by v1.2.0 or earlier" is deliberately left
    alone -- it states which builds carry the pre-v3 schema, which is still
    true, and bumping it would break the upgrade-path smoke test.

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01YD1nuzd8pJxh3HfL1NaMha

commit 6183e828036d5aecf4f68cb2edbc41346aaf0d66
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Sun Jul 26 14:30:38 2026 +0000

    Remove the DurationObject probe and two dead exports; sync docs

    The `/kcd debug duration` probe was scaffolding. It existed to answer one
    question -- which DurationObject getters are usable in combat -- and it
    answered it: every getter except HasSecretValues() is secret-tainted,
    booleans included, so there is no Lua-side way to detect a cooldown change
    mid-fight. Keeping a diagnostic command around for a question that is now
    settled is dead weight, so it goes: Compat.DebugDuration, the DEBUG_COMMANDS
    entry, its test suite, and the doc rows describing it.

    The measured findings STAY in midnight-quirks.md -- that table is the
    expensive part and re-deriving it would mean another round-trip through a
    live client. The pointers to the removed command are replaced with
    instructions for re-measuring by hand after a patch.

    Also reverted the argument-remainder threading in runDebug that was added
    for that verb. No other debug subcommand takes an argument, so leaving it
    would be speculative plumbing with no caller.

    Dead exports removed:

    * `Util.ResetSpecNameCache` -- added earlier the same day as a "test/reload
      hook" and never called, including by the tests. The locale maps are
      self-healing (a build that saw no client data isn't cached, so the next
      call retries), so nothing needed it.
    * `Util.RegisterTargetEvent` -- superseded by RegisterUnitCastEvent, zero
      call sites. The surrounding comment block that described it is updated
      too.

    Doc sync against current code:

    * module-map: corrected a stale claim that IconGrid_Render consumes
      `IconGrid._isTargetCasting` -- that hook is gone; the glow trigger reads
      the per-instance `inst.isCasting` resolver. Added IconGrid.Icon, the
      Icon:Apply state/time split, and the MaterialChange log gate.
    * data-flow: new section on why SPELL_STATE fires ~10x/sec per spell on
      cooldown and what that forces on the logging and render paths -- the
      single most surprising thing about this pipeline for anyone reading it
      fresh.
    * agent-context: two hard rules that were only recorded in ARCHITECTURE or
      in code comments -- never derive a persisted key from a localised string
      (issue #8), and the DurationObject secrecy result.

    Tests 151 -> 146 (the probe suite is gone); no coverage lost elsewhere.
    Frozen audit/review/plan bundles still reference RegisterTargetEvent and are
    deliberately left untouched -- they are dated records of what was true when
    written, not live docs.

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01YD1nuzd8pJxh3HfL1NaMha

commit 9fc0d8b1b320c056fd7d1974b6e7bc878761c756
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Sun Jul 26 14:16:44 2026 +0000

    Cut redundant icon render work; probe the 12.0 DurationObject API

    Two related changes: measuring what the duration API can actually do, and
    acting on the answer.

    `/kcd debug duration [spellID]` (Compat.DebugDuration) probes every
    DurationObject getter on the live client and reports whether each is present
    and whether its return is secret-tainted right now. Blizzard documents the
    methods but not their combat secrecy, and this addon's history is a catalog
    of APIs that read fine out of combat and error the moment it opens. Every
    call is pcall'd and every result rendered through the issecretvalue gate, so
    the probe can never itself be the thing that errors. Debug verbs now receive
    their argument remainder, so a verb can take a parameter.

    The measured answer (12.0.7, recorded in midnight-quirks.md): IN COMBAT EVERY
    GETTER IS SECRET, including the booleans -- HasExpired, HasStarted, IsActive
    and IsZero all come back tainted, and a secret boolean cannot be branched on
    at all. Only HasSecretValues() stays plain.

    That settles a question this addon has been working around blind. There is NO
    Lua-side way to detect "this spell's cooldown changed" in combat, so
    Cooldowns:StateChanged's identity compare is not a shortcut -- it is the only
    signal available. It over-fires (the API mints a fresh object per call) but
    never under-fires, and nothing can replace it. The emit rate is therefore
    fixed, and the only thing left to cut is what each emit costs.

    So Icon:Apply now splits its work. The alpha/tint/GCD curve evaluations, the
    swipe re-arm and the countdown text are time-varying and still run on every
    payload. Glow (four LibCustomGlow calls), the charges badge and the Show/Hide
    calls depend only on plain state fields and are gated behind plainStateMoved
    -- measured at 35% fewer widget calls per repeat apply, which for a spell
    parked on a 60s cooldown is most of a minute of pure waste.

    Two details that keep the gate honest. A config-driven re-apply passes
    force=true: it hands back the SAME state table, so the gate would otherwise
    skip exactly the work the config change needed. And charges stay outside the
    gate entirely -- they can be secret, a secret cannot be compared, and
    SetFormattedText renders one fine, so freezing the badge to save two calls
    would strand a stale count on screen for a whole fight.

    Also corrects Compat.GetSpellCooldownDuration's docstring: it returns a
    ZEROED object, not nil, for a spell that is off cooldown, so a non-nil handle
    is not an "is on cooldown" signal.

    Adding C_CurveUtil to the test mock revealed that branch 1 of Icon:Apply --
    the main full-cooldown render path -- had never been exercised headlessly:
    BuildCurves bailed without the API and every case fell through to the idle
    branch. Now covered, along with a duration-object mock mirroring the two
    traits that matter (fresh per call, possibly secret).

    Tests 140 -> 151. Smoke-tests gains 9c for the visuals the mock cannot judge
    -- swipe smoothness and the GCD_UPPER alpha step in a cooldown's final 1.6s,
    which is the transition most at risk from over-gating.

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01YD1nuzd8pJxh3HfL1NaMha

commit 0a696cf99e1cdc8dee43ab4d9ecc49c4c59cdb54
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Sun Jul 26 13:52:11 2026 +0000

    Fix: key spell lists on numeric spec IDs, not localised names (#8)

    The per-spec spell-list key was derived from GetSpecializationInfo's
    SECOND return -- the localised display name -- while defaults/Spells.lua
    shipped English keys. On any non-English client the two never met: a frFR
    Elemental Shaman derived "ELEMENTAIRE", looked up spells.SHAMAN.ELEMENTAIRE,
    got nil, and tracked nothing at all. Silently, because an absent spec list
    is indistinguishable from a deliberately emptied one. Only specs spelled
    identically in English worked, which is why it looked class-specific.

    Spec keys are now Blizzard's numeric specID (Const.SPEC, verified against
    the live ChrSpecialization export). Localised names stay for DISPLAY only:
    the Spells dropdown labels in the player's own language and the slash
    commands accept a localised name, but output always echoes the English
    token so pasted bug reports read the same in every locale.

    Database:MigrateSpecKeys carries v2 profiles forward (schema v3). It is
    shape-driven rather than version-gated: schemaVersion is per-ACCOUNT but
    spells are per-PROFILE, so a gated step would migrate only whichever
    profile was active at upgrade and strand the rest. Unresolvable keys are
    left in place rather than dropped, and a string key never overwrites an
    existing numeric one.

    Also in this change:

    * Settings > Spells now follows an in-game spec swap while open. It only
      re-seeded on a fresh Settings open, so the dropdown stayed pinned to the
      old spec until the window was fully closed and reopened.

    * The rebuild debug line now names the class/spec IDs and every watched and
      skipped spellID, so a pasted log is diagnosable on its own -- which is
      exactly what this issue needed.

    * Cooldown-handle churn no longer floods the debug console.
      C_Spell.GetSpellCooldownDuration mints a fresh object per call, so a
      spell parked on an unchanged cooldown compared unequal on every poll and
      logged ~10 lines/sec for the whole cooldown. The re-emit is load-bearing
      (Icon:Apply re-evaluates its alpha/tint/GCD curves off the emitted
      object and nothing else re-runs them), so the emit is unchanged and only
      the log is gated, on a new MaterialChange predicate.

    Recorded the locale rule as an ARCHITECTURE invariant and documented the
    CooldownDuration trap -- plus the wider DurationObject method surface this
    addon does not yet use -- in docs/midnight-quirks.md.

    Tests 111 -> 140, including a frFR client suite driving the reported
    scenario end to end. luacheck clean.

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01YD1nuzd8pJxh3HfL1NaMha

This mod has no related projects