Backlog sweep (12 issues): wrapper parity, WCL analytics, Blizzard + CurseForge providers, identity, decision docs - #36
Merged
Merged
Conversation
The warcraft-cli wrapper imports 10 provider apps at module load but
declared only 5 as runtime deps, so a standalone `pip install warcraft-cli`
(outside the `warcraft` umbrella wheel) would ModuleNotFoundError.
- Declare the 4 missing standalone provider distributions in
warcraft-cli/pyproject.toml (raiderio-cli, simc-cli, warcraft-wiki-cli,
wowprogress-cli) and sort the dependency list.
- Give warcraftlogs-cli its first pyproject.toml (was source-only). It
declares simc-cli to formalize the existing import-linter-sanctioned
warcraftlogs_cli.main -> simc_cli.talent_transport edge, plus its
import-derived deps (typer, httpx, warcraft-{core,api,content}-cli).
- Add warcraftlogs-cli to the wrapper deps now that it has a distribution.
- Add tests/test_warcraft_cli_packaging.py: static ast+tomllib guard that
every provider app imported by the wrapper is a declared dep, so the gap
cannot silently reappear. Verified it fails pre-fix, passes post-fix.
Relocating the shared talent-transport symbol to drop the provider->provider
dep is tracked in AUR-501.
Co-Authored-By: OpenAI Codex <noreply@openai.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ting Routing/doctor/registration are already shipped; this slice locks them down with regression tests and refreshes the contract docs. No routing-heuristic change (the alpha-only report-code contract is preserved). - Add a registry-vs-CLI capability parity test: for every registered provider, wrapper_capabilities[search|resolve] must equal that CLI's own doctor.capabilities[surface], and a bare-`ready` surface may never sit over a CLI reporting coming_soon/not_supported/ready_explicit_report_only. Scoped to search/resolve (only warcraftlogs/simc/blizzard-api emit a `doctor` key). - Add regression tests proving `warcraft search`/`resolve` on a non-report warcraftlogs query keep WCL in the fanout as ready_explicit_report_only, return the structured discovery hint (count:0, message, supported_inputs, suggested_commands), and never surface a fabricated resolved match. - Docs: refresh WRAPPER_PROVIDER_CONTRACT.md WCL "Current state" line + add the previously-missing raidbots and blizzard-api entries; align docs/warcraft/README.md. Co-Authored-By: OpenAI Codex <noreply@openai.com> Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Today `warcraft --expansion <key> <none-provider> ...` (simc, blizzard-api) fails with exit 1 unsupported_provider_expansion. A none-expansion provider has no expansion semantics to honor, so relax it to passthrough with an advisory. - New _expansion_passthrough_advisory: none-mode + requested expansion returns an advisory; fixed/profiled mismatch still hard-errors (genuine mismatch). - New _run_passthrough centralizes all 10 proxy commands. For the relax case it captures both provider streams, attaches an additive advisory to the JSON payload (expansion_filter + expansion_advisory block), preserves the payload verbatim, and surfaces the advisory on stderr when output is non-JSON. - Fix latent _invoke_sub_app bug: under standalone_mode=False click *returns* a typer.Exit code instead of raising, silently swallowing provider failures to exit 0; now re-raised so passthrough propagates non-zero exits (both paths). - Author "Phase 4 Expansion Policy" in EXPANSION_FILTERING.md: provider-promotion criteria, wrapper-key -> WCL site-profile mapping table, none-expansion passthrough rule. Added missing raidbots/blizzard-api matrix rows. - Tests: wrapper relax (blizzard + simc doctor), fixed-mismatch error, no-advisory baseline; contract none-mode reason == provider_has_no_expansion_support. Co-Authored-By: OpenAI Codex <noreply@openai.com> Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Metadata-consistency closeout for the guide comparison/handoff surfaces. - warcraft_content.write_article_bundle stamps an ISO-8601 UTC `exported_at` into the manifest (method/icy-veins/warcraft-wiki; export_version unchanged); _bundle_descriptor carries it through to comparisons. - _guide_build_handoff_freshness single-bundle path reads exported_at, so `guide-builds-simc <bundle>` now reports freshness.status=known instead of unknown. - New shared _guide_comparison_packet adds a top-level `freshness` rollup and a `comparison_evidence` block (compared bundle count, providers, matching rules, per-bundle freshness) to BOTH guide-compare and guide-compare-query, preserving comparison_scope + citations.bundle_paths. New --max-age-hours (default 24). - Orchestration export rows source exported_at from the bundle manifest so reuse freshness and comparison freshness read one timestamp. - Older timestamp-less bundles degrade gracefully (no export_version bump). - Tests: article-bundle manifest exported_at; method/icy-veins/wiki export manifest exported_at; guide-compare + guide-compare-query freshness/evidence; guide-builds-simc known-from-bundle. Docs: USAGE.md + CHANGELOG. Co-Authored-By: OpenAI Codex <noreply@openai.com> Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add an additive `trust` block to `warcraftlogs character-rankings` (ranking_basis, resolved scope echo, reused sampled freshness, and a source-character class_spec_identity) alongside the preserved `raw` passthrough. Built from existing identity/freshness helpers only; WCL exposes class as an internal classID enum so the class name is not fabricated (spec-only normalization). Add `warcraftlogs spec-kill-samples`: a new sampled cross-report primitive that hardens the existing `--spec-name` participant filter into an explicit, labeled cohort (requires --spec-name + boss scope). Reuses collect_boss_kill_rows; emits sample_size (full matching cohort), matching_participant_count, exclusion/truncation counts, freshness, and citations. Because the shared sampler orders kills by ascending duration, the truncated head is flagged with truncation_order + not-a-representative-sample note (SAFE_ANALYTICS_RULES: no silent caps). Explicitly not a spec ranking leaderboard. Register in ALL_COMMANDS + canonical envelope key spec_kill_samples (legacy `kills` dual-emitted/deprecated); document in PAYLOAD_KEYS.md, README, SCOPING, LIVE_MATRIX; add unit + envelope + gated live tests and a matrix case. CHANGELOG updated. Co-Authored-By: OpenAI Codex <noreply@openai.com> Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Key Warcraft Logs report cache TTL on finish state. Finished reports
(endTime > 0) cache under the new WARCRAFTLOGS_FINISHED_REPORT_CACHE_TTL_SECONDS
(default 24h, added to CacheTTLConfig); live reports keep the 60s TTL. The TTL
is resolved at the cache-write site (both client and user GraphQL endpoints) via
a finish-state resolver, so a live report is never stored under the finished TTL.
Report rankings (population-relative percentiles that keep changing) and report
listings stay on the short TTL even when finished; the finished TTL applies only
to immutable report-detail payloads (fights/events/tables/graphs/master-data/
player-details + the report metadata lookup). Added report-level endTime to the
report-detail queries so the resolver can read finish state.
Sampled cross-report commands (boss-kills, top-kills, spec-kill-samples,
kill-time-distribution, boss-spec-usage, comp-samples, ability-usage-summary)
now emit cache_provenance {finished, live, cache_ttl_seconds, source}, a
populated integer freshness.cache_ttl_seconds (was null), and a consolidated
sample_scope (ranking_basis + filters + returned/excluded/truncated).
Report-encounter commands gain the same cache_provenance block. In cache-off
deployments (WARCRAFTLOGS_CACHE_BACKEND=none) the emitted cache_ttl_seconds is
null rather than claiming a TTL that is never applied.
New caching contract in docs/warcraftlogs/CACHING.md (linked from the README,
which condenses the two prior aspirational sections); CHANGELOG updated.
Co-Authored-By: OpenAI Codex <noreply@openai.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add `raiderio leaderboard mythic-plus`, a thin season-scoped view over the existing sampled-run primitive. Emits kind `mythic_plus_leaderboard`, a query block with the explicit `resolved_season`, run rows, sampled freshness (sampled_at + cache_ttl_seconds), and `citations.leaderboard_urls`. It paginates to satisfy `--limit` (deriving pages from the 20-runs-per-page Raider.IO page size, capped at 10 pages) and emits a `sample` block (requested_limit, returned_run_count, pages_requested, pages_fetched, limit_reached) so a short provider response is explicit, never a silent cap. Every Mythic+ analytics command (standalone `mythic-plus-runs` + the sample/distribution/threshold families) now additionally surfaces `resolved_season` in its `query` block alongside the existing `season` key. `--season current` (or empty) resolves to the Raider.IO current default season: the request omits the season param and the effective slug is recovered from the API response, instead of forwarding the literal "current". `raiderio doctor` reports `mythic_plus_leaderboard: ready`. README command surface updated and the stale "Suggested Next Commands" examples reconciled to shipped command shapes. Unit tests (incl. pagination + season-current + empty degrade) and a RAIDERIO_LIVE_TESTS-gated live contract test. CHANGELOG updated. Co-Authored-By: OpenAI Codex <noreply@openai.com> Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… fix Add two provider-local analytics commands and fix a progression difficulty token bug: - guild-snapshot: derives current guild state (progression, item-level rank context, per-tier rank series) from a single guild-history traversal, with no extra guild-page fetch in the command layer. fetch_guild_history now carries the main page's current_item_level/current_encounters so the current state survives an empty/incomplete history series. - history-trajectory: oldest-to-newest tier timeline with delta_vs_previous rank/item-level movement. Deltas compare consecutive tiers (different raids/difficulties), so they are emitted as descriptive movement with explicit caveat notes, not a normalized metric. - Fix client.py difficulty token to use _progress_snapshot()["difficulty"] (token "M") instead of the "N/N (M)" summary string. - doctor reports guild_snapshot/history_trajectory capabilities as ready. - Freshness emits cache_ttl_seconds: null when caching is disabled. - Docs: USAGE.md, docs/wowprogress/README.md, skills reference, CHANGELOG. Co-Authored-By: OpenAI Codex <noreply@openai.com> Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Completes the AUR-390 scaffold with a client-credentials OAuth token flow
and three typed read commands.
- New blizzard_api_cli/client.py: client-credentials OAuth (ported from
warcraftlogs) — token fetched once and cached in shared state under
blizzard-api-client-credentials, keyed by sha256(region, id, secret),
region-scoped in-memory + cross-process reuse until ~60s before expiry.
- Commands: `blizzard realm <slug>` (dynamic), `blizzard item <id>` (static),
`blizzard character <realm> <name>` (profile, retail only). Region/namespace
routing via --region (default BLIZZARD_REGION, else us; us/eu/kr/tw/cn with
aliases) and --game-version retail|classic (or --classic shorthand); --locale
passes through. Realm/character slugs are lowercased.
- Envelope: {ok, provider, command, kind, query, provenance, data} on success;
{ok:false, ..., error:{code, message}} + nonzero exit (never a traceback) for
missing_client_credentials, unsupported_region, unsupported_game_version,
classic_profile_unsupported, http_error, network_error, invalid_response.
- doctor flips game_data/profile to ready, surfaces the region/routing block and
the client-credentials token-cache state.
HONESTY: the endpoint hosts, OAuth token URL, and namespace strings follow
documented Blizzard API conventions but have NOT been confirmed against live
endpoints in this environment (no credentials available to run the spike).
doctor carries region.verification and every command payload carries
provenance.verified=false. A human must run
`BLIZZARD_LIVE_TESTS=1 pytest -q -m live tests/test_blizzard_api_live.py` with
real credentials to confirm them (CN endpoints + classic namespaces least
certain).
Tests: fixture-backed contract tests (monkeypatched request_with_retries),
updated doctor test, gated live tests. Docs: blizzard-api README,
AUTH_ARCHITECTURE phase 3, CONTRACT_TEST_CATALOG, CHANGELOG.
Co-Authored-By: OpenAI Codex <noreply@openai.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Wrap raw class/spec/encounter/ability data in the shared warcraft_core.identity contract on the remaining provider surfaces. Purely additive — raw fields are preserved alongside each new sibling identity block. - raiderio: class_spec_identity on ranking roster rows, resolve character-profile candidates, character search results (class-only), and guild roster_preview rows. high confidence only when class+spec resolve. - raidbots: class_spec_identity on inspect-report actor summaries from the sim report's class/specialization (high when both present, gated on non-whitespace content; unknown when both missing). - wowprogress: class_spec_identity on the character payload (normalized, confidence none; spec sourced from the SimDPS table), and encounter_identity on guild encounter kill rows (name-only -> normalized, encounter_id null). Also fixes a pre-existing parser bug where two-word classes (Death Knight, Demon Hunter) were truncated to the trailing token in class_name/race. - method + icy-veins: ability_identity on Wowhead spell linked-entity rows (canonical, spell_id set); other entity types unchanged. Docs: IDENTITY_CONTRACT coverage matrix + notes updated; CHANGELOG. Tests: resolved + degrade pairs per provider, guild-no-identity + non-spell-unchanged guards. Co-Authored-By: OpenAI Codex <noreply@openai.com> Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…aidPlan DEFER) Rewrite the three later-provider research stubs into decision docs: - CurseForge = GO: Decision section with gate-referencing rationale, an Expected User Workflow (addon lookup by slug/id -> metadata + files + changelog) marked approved-but-not-yet-implemented, required wrapper capabilities, expansion_mode=none, and a link to the AUR-499 scaffold. - Undermine Exchange = DEFER and RaidPlan = DEFER, each with a concrete, checkable un-gate condition so the next revisit is itself AFK-able. Fix stale doc indexes to match shipped providers and the decisions: - architecture/README.md: drop shipped blizzard-api/raidbots from the docs-only list; relabel as candidate decision docs. - README.md: replace generic (planned) tags with GO/DEFER candidate tags; blizzard-api no longer tagged planned. - WRAPPER_PROVIDER_CONTRACT.md: blizzard-api entry updated from scaffold/ coming_soon to shipped Game Data + Profile (AUR-455). - IDENTITY_CONTRACT.md: blizzard-api note no longer implies the Game Data/ Profile endpoints are pending; identity wiring is separately deferred. - ROADMAP.md: record the AUR-395 decisions in its row and add an AUR-499 scaffold row. Decision-only deliverable; no code changed. make check green (1059 passed). Co-Authored-By: OpenAI Codex <noreply@openai.com> Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Stand up a read-only `curseforge` provider, mirroring the blizzard-api
scaffold (the GO decision from AUR-395):
- New packages/curseforge-cli: auth.py (static x-api-key discovery via
.env.local -> provider env -> process env), client.py (api.curseforge.com,
slug/id resolution with client-side exact-slug + gameId guards, metadata +
latest files + best-effort changelog), main.py (doctor + addon commands).
- addon returns {metadata, latest_files, changelog} with the standard
{ok, provider, command, kind, query, provenance, data} envelope; errors
(missing_api_key, addon_not_found, http_error, network_error,
invalid_response) emit a clean ok:false envelope, never a traceback.
- Changelog is best-effort: a failed fetch (HTTP, network, or malformed body)
degrades to an explicit {file_id, error} marker; it never fails the lookup
and is never silently reported as "no changelog".
- Host/endpoints/response shapes follow the documented public CurseForge Core
API but are pending one-time live confirmation (provenance.verified=false;
CURSEFORGE_LIVE_TESTS=1).
Wiring: root pyproject (script + wheel + mypy_path), .importlinter (3
contracts), warcraft-cli dep, providers.py registration (expansion_mode=none,
doctor/addon ready, search/resolve coming_soon), wrapper passthrough command,
conftest sys.path, dev_deploy.sh BIN_NAMES. Bumped provider-count and the
exact none-expansion / fanout exclusion sets across the wrapper + provider
contract tests.
Tests: fixture-backed contract suite (slug/id resolution, exact-slug + cross-
game + gameId guards, all error codes, best-effort changelog markers), doctor +
auth discovery, wrapper routing, and a CURSEFORGE_LIVE_TESTS-gated live test.
make check green (1082 passed). Docs + CHANGELOG updated; CurseForge graduated
from candidate decision doc to shipped scaffold.
Co-Authored-By: OpenAI Codex <noreply@openai.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…, curseforge) Progressive-disclosure pass: the `warcraft` skill is a concise SKILL.md router plus per-provider references loaded on demand, but its index covered only 9 providers and omitted blizzard-api (AUR-455) and curseforge (AUR-499). - Add consumer-facing references/blizzard-api.md and references/curseforge.md (Best For / Start With / Auth / Effective Use / Boundaries), matching the existing reference style; each notes its auth requirement and the verified:false trust posture so agents treat unconfirmed results as best-effort. - Wire both into SKILL.md's Provider Synopsis table and Read Next index, so the harness now discloses all 11 registered providers. The standalone-skill generator (scripts/generate_provider_skills.py) is a curated subset and intentionally untouched here; references/*.md + SKILL.md are the consumer source of truth. Co-Authored-By: OpenAI Codex <noreply@openai.com> Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Branch-vs-main diffwarden flagged that the new spec-kill-samples command (AUR-387) was absent from warcraftlogs doctor's capabilities map, so doctor-as-source-of-truth no longer matched the command set. Add the spec_kill_samples capability alongside its sampled-analytics siblings (top_kills/boss_spec_usage/comp_samples), assert it in the doctor phase-one capabilities test to prevent regression, and note the doctor surface in the AUR-387 CHANGELOG entry (matching the AUR-392 "<provider> doctor reports the new ... capabilities" convention). Co-Authored-By: OpenAI Codex <noreply@openai.com> Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…e-to-null)
Branch-vs-main diffwarden flagged that an empty-but-present changelog
(file exists, endpoint returns data:null) emits {file_id, source_url,
body: null} rather than a top-level null, arguing callers keying off
`changelog is None` will misclassify it.
The recommended fix (return null) is declined: it would degrade the
deliberate three-state design and contradict the already-tested
error-marker behavior. top-level null is reserved for "no file to
fetch"; a failed fetch returns {file_id, error}; so a successful-but-
empty fetch returning a {file_id, source_url, body: null} object (more
provenance than a failure, not less) is the consistent choice and
preserves which file was checked + its source url.
The real defect was contract clarity, so this:
- adds an inline invariant comment at the body:null return so future
review runs do not re-fixate;
- makes docs/curseforge/README.md and skills/.../references/curseforge.md
precise and consistent (null only when no files; detect empty notes via
changelog.body, not `changelog is null`); the old "when a file exposes
none it is null" wording was the misleading bit;
- adds a contract test locking in the empty-body object form.
No code behavior change; output shape unchanged from what AUR-499 shipped.
Co-Authored-By: OpenAI Codex <noreply@openai.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Branch-vs-main diffwarden (final pass) surfaced three valid P2s in the new provider work; all verified against the code and fixed: 1. Blizzard live suite gated by the wrong env var. test_blizzard_api_live.py was added (and documented as the BLIZZARD_LIVE_TESTS path) but never registered in conftest LIVE_TEST_ENV_BY_FILE, so the collection hook fell back to WOWHEAD_LIVE_TESTS and `BLIZZARD_LIVE_TESTS=1 pytest ...` silently skipped. Register it; add a wrapper meta-test asserting every test_<provider>_live.py declares its own flag so this can't recur. 2. `--classic` silently overrode an explicit `--game-version retail`. resolve_game_version only treated --classic as conflicting for *unsupported* versions, so `--game-version retail --classic` routed to classic with no error. Reject any explicit non-classic --game-version paired with --classic (--classic alone leaves game_version=None, so the shorthand still works). Contract test added. 3. CurseForge numeric lookups labeled non-WoW/malformed records as WoW. The gameId gate only rejected a *present int* != 1, so an absent or non-int gameId still returned ok:true with provenance.game_id hardcoded to 1. Require a present int gameId (invalid_response otherwise), matching the non-string-changelog schema-drift posture. Contract test added. CHANGELOG: corrected the AUR-499 changelog-null wording to match the clarified contract, and noted the AUR-455 contradictory-flag rejection. make check green (1086 passed). Co-Authored-By: OpenAI Codex <noreply@openai.com> Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…te freshness Default-set diffwarden loop (iter 2) flagged the `or _iso_now_utc()` fallback in _process_guide_compare_provider as stamping legacy timestamp-less bundles as freshly exported, so a stale bundle could be reused without a real anchor. Declined as a false positive after tracing the full data flow: all three guide-compare providers stamp exported_at on export (wowhead via _guide_export_manifest; method/icy-veins via write_article_bundle), and the fallback lives in the export path (guide-export just re-wrote the bundle), so "now" reflects a real just-happened export. A timestamp-less bundle is also never reused: the reuse gate requires freshness "fresh" and _guide_compare_freshness(None) is always "stale", forcing a re-export. Strengthened the inline comment so future runs don't re-fixate. No code behavior change. Co-Authored-By: OpenAI Codex <noreply@openai.com> Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ot a regression Default-set diffwarden loop (iter 4) flagged the relax-to-passthrough StringIO capture as buffering the whole provider output in memory and losing streaming for large simc/report workflows. Declined: the buffering only runs on the explicit `warcraft --expansion <key> <none-provider> ...` combination (normal `warcraft <provider> ...` returns at the advisory-is-None branch and streams untouched), and there is no incremental streaming to lose anyway — provider commands emit a single JSON envelope all at once, and attaching the expansion advisory as an additive sibling key requires the whole payload to parse it. The buffering is intrinsic to the annotate-the-payload feature (AUR-496: "relax is never silent"), not a regression of normal workflows. Strengthened the inline comment so future runs don't re-fixate. No code behavior change. Co-Authored-By: OpenAI Codex <noreply@openai.com> Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ge search/resolve
Default-set diffwarden loop (iter 5) flagged that curseforge advertises
search/resolve as coming_soon in doctor but doesn't define those
commands, so `curseforge search dbm` returns Click's "No such command"
(exit 2) instead of the structured envelope callers expect for
not-yet-ready surfaces. Verified valid: simc already defines coming_soon
search/resolve stubs (the repo precedent), and BOTH new providers
(curseforge AND blizzard-api) had the identical gap.
Fix both: define search/resolve as structured coming_soon stubs (exit 0,
{ok, provider, command, kind: coming_soon, coming_soon: true,
suggested_command, ...}) mirroring simc. Capabilities stay coming_soon,
so the wrapper still excludes them from search/resolve fanout
(provider_supports_surface unchanged) — the stubs only fix direct and
`warcraft <provider> ...` passthrough probes.
Added per-provider contract tests plus a cross-provider wrapper meta-test
asserting any surface a provider's doctor advertises as coming_soon emits
a structured stub (exit 0), never a Click error — so this can't recur for
a future provider. CHANGELOG notes the stub behavior for both providers.
Co-Authored-By: OpenAI Codex <noreply@openai.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Autonomous backlog sweep of 12 Linear issues (AUR-384–499) plus a progressive-disclosure
documentation pass, across 13 commits. Each issue followed the same loop: read issue + linked
issues + code → plan → independent plan review → implement →
make check→ diffwarden (defaultreviewer set) until clean → commit/push → Linear → docs. Declined diffwarden findings carry inline
code comments explaining the invariant/tradeoff.
make checkis green on the tip: ruff + mypy + import-linter (boundaries kept) + 1082 testspassed.
Issues shipped
warcraftlogs-clipyprojectcharacter-rankingstrust block +spec-kill-samplescohortresolved_seasonguild-snapshot+history-trajectory(+ two-word-class fix)doctor+addonlookup)Plus: a documentation refactor completing the
warcraftskill's progressive-disclosure index —added consumer-facing
references/blizzard-api.md+references/curseforge.mdand wired both intoSKILL.md so all 11 registered providers are disclosed.
Notable design decisions
provenance.verified: false. No live Blizzard credentials orCurseForge API key were available to run the one-time endpoint-confirmation spikes, so
blizzard-api(AUR-455) andcurseforge(AUR-499) follow documented API conventions but markevery payload unverified.
*_LIVE_TESTS-gated tests confirm them once credentials exist:BLIZZARD_LIVE_TESTS=1/CURSEFORGE_LIVE_TESTS=1.gameId); slug lookupsmatch the exact slug client-side (with a cross-game
gameIdguard) so an ignored/renamed filterparam can never bind the wrong mod; changelog is best-effort with an explicit
{file_id, error}marker, never a silent null and never fatal.
ttl_override; a livereport is never stored under the 24h finished TTL.
cache_provenancedescribes the report'sfinish state (documented caveat for the bounded live→finished window) — see
docs/warcraftlogs/CACHING.md.reconciled (architecture/README, docs/README, WRAPPER_PROVIDER_CONTRACT, IDENTITY_CONTRACT,
ROADMAP).
Verification
make checkgreen (lint + typecheck + import boundaries + 1082 fast tests).rationale comments. Provider CLIs remain intentionally outside mypy
files=(repo convention;documented in
pyproject.toml).blizzard-apiandcurseforge, plus*_LIVE_TESTS-gatedlive contract tests that skip when unconfigured.
Reviewer notes
test_warcraft_wrapper.py,test_provider_contract.py, and the live wrapper tests.[Unreleased]records every user-visible change.🤖 Generated with Claude Code