Squash-merge verified telemetry query depth at exact head 02d16c58a4. Required validate and paired evaluation checks passed; advisory droid review had no blocking findings.
Squash-merge verified React and Vite expertise at exact head d4fd6cf70d. Required validate and paired evaluation checks passed; advisory droid review had no blocking findings.
Squash-merge verified routing remediation at exact head 690f9c14b0. Required validate and paired evaluation checks passed; advisory droid review had no blocking findings.
Squash-merge the verified #412 eval coverage implementation. Required validate and paired evaluation checks passed at exact head b43ac564a5919a0f23fdab49ba052d7c514915cb; droid-review BYOK failure had no findings and is advisory.
2026-09-01 19:58:35 -04:00
Magnus HedemarkGitHubfactory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Magnus HedemarkGitHubfactory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>factory-droid[bot] <138933559+factory-droid@users.noreply.github.com>
Document that the publish audio-guard fires only for --status published
(scheduling intentionally precedes audio attach) and that its pre-publish
episode GET consumes one rate-limit slot, relevant to bulk re-publish
loops.
Add references/skill-triggers.md rows for transistor and trakt, the two
thickened skills missing from the trigger index; phrasing follows each
skill frontmatter description.
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
2026-08-30 01:52:43 -04:00
Magnus Hedemarkandfactory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
udp listen ignored the universal --dry-run flag and bound UDP 50222,
hanging when no hub is on the LAN. Add a dry-run plan branch that
describes the listen parameters (bind address, port, timeout, show-all)
and exits 0 without creating any socket, so doc claims of universal
--dry-run support stay universal and true.
Four regression tests pin the plan shape, the defaults/--show-all
propagation, and prove no socket is constructed (and no token demanded).
Recipe 5 documents the udp listen plan object alongside the other plans.
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
2026-08-30 01:52:10 -04:00
Magnus Hedemarkandfactory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
main() sliced argv at the first occurrence of a known subcommand name,
so a value-flag pair whose value names a subcommand (e.g. login's
--server given `search`) made argparse dispatch the wrong subparser:
`jellyfin --server search browse ...` errored inside the `search`
sub-parser instead of running browse.
Dispatch now splits such misplaced pairs out of the top-level argv
(find_subcommand_token + split_misplaced_value_pairs) and re-attaches
them to the command tail, where each handler's parse_known_args already
tolerates unknown flags. A properly placed occurrence of the same flag
later in the tail still wins. Any other pre-command token (unknown
flags, stray positionals, `--`, dangling value flags) is untouched, so
argparse errors stay byte-identical to the pre-hardening CLI.
Also dedupe the twice-repeated "Bundled CLI --dry-run and exit-code
contract" section in references/worked-recipes.md (user-testing round 1
finding); content merged into one section.
Adds DispatchHardeningTests: the mis-slice scenario for every
subcommand shape, clean-argv dispatch for all 11 subcommands, flag
priority, argparse-owned error paths, and unit pinning of both helper
return-value tables.
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
2026-08-30 00:45:16 -04:00
Magnus Hedemarkandfactory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
jellyfin: send the access token over exactly ONE channel per request (drop
the simultaneous X-Emby-Token header; the MediaBrowser Token= parameter is
the sole transport, legacy fallback remains documented as substitute-never-
stack and is request-capture tested); remove the dead no-op conditional in
JellyfinClient.__init__; make the login error-path test exception-safe with
patch.object; document the test-pinned dry-run plan keys and the actual
0/1/2 exit-code mapping in worked-recipes and SKILL.md.
peertube: replace the stale dry-run shape prose ('url'/'form') with the
test-pinned {dry_run, method, path, params} / form_fields keys; harden
cmd_me against a non-dict role (no AttributeError) with regression tests;
remove the dead client facade, the unused cmd_channels variable, and the
unused List/Tuple imports (ruff F401/F841 clean).
ghost: fold the 5 nested with-statements (ruff SIM117) in test_ghost.py
into single with-statements.
All three skills double-runner + proxy-trap green (25/56/37 tests);
validate-evals, paired smoke, quality validator, core gates, and catalog
check modes green.
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
2026-08-29 20:32:06 -04:00
Magnus Hedemarkandfactory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Admin API writes carrying an html payload (create-post, update-post,
create-page) now attach the docs-required ?source=html query flag;
_post/_put gained params plumbing, and the create-post dry-run plan
includes params for plan/request parity. Regression tests pin the param
whenever an html payload is present (mocked request capture and dry-run
plans) and assert its absence on mobiledoc/lexical writes.
Docs: fix the jq interpolation typo in worked-recipes recipe 2 (missing
backslash made the scheduled-posts line exit 5), replace the blanket
"exit code 2" claim in admin-auth-and-basics with the script's actual
2-5 failure-class mapping, and state the source=html requirement in the
SKILL.md --html gotcha.
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
2026-08-29 19:53:50 -04:00
Magnus Hedemarkandfactory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Research-driven rebuild of the peertube skill (docs.joinpeertube.org REST
reference 8.1.0 + SepiaSearch + server source + live anonymous probes):
- SKILL.md rewritten to the lastfm model: intent-grouped commands, pipeline
recipes, jq guidance, researched gotchas, When-to-use/When-not-to-use,
reference routing table. New negative boundary in the description
(YouTube/Vimeo uploads, video editing, server administration).
- scripts/peertube-cli -> scripts/peertube, rewritten and extended:
offset (start/count) pagination replaces the nonexistent page param,
comments fixed to the hyphenated /comment-threads route, server command
now composes /config/about + /server/stats (canonical paths), search
gains --search-target with searchTarget=local default and help text
stating its instance-local scope, new video/comments/channel/account/
my-videos/logout commands, --server hoisted before or after the
subcommand, OAuth2 password grant hardened for 2FA (x-peertube-otp)
and the production client_secret masking behavior, per-instance
owner-only token file with refresh-before-expiry and revocation.
- references/: auth-and-tokens, search-and-discovery, endpoint-catalog,
gotchas-field-guide, worked-recipes - all cited to official docs with
Sources footers (URLs verified live at authoring time).
- scripts/test_peertube.py: 54 offline tests (help, argument errors,
dry-run plans, mocked OAuth2 persistence/refresh/revocation, handler
contracts, documented pipeline chains) passing pytest strict-markers,
unittest discovery, and the proxy-trap zero-egress rerun; one
env-guarded anonymous live probe (PEERTUBE_LIVE_TESTS=1).
- evals/evals.json: six schema-v1 cases incl. SepiaSearch-scope and
masked-secret cases plus a should-not-trigger YouTube negative probe.
- README refreshed for humans; root README blurb and skill-triggers row
synced; marketplace.json/llms.txt regenerated (codex artifacts
unchanged); test-results/ gitignored (pytest runner artifact).
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
2026-08-29 18:43:00 -04:00
Magnus Hedemarkandfactory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
- Root README blurb and references/skill-triggers.md trigger row now
match the thickened jellyfin description (manual-sync requirement).
- Regenerate .claude-plugin/marketplace.json and llms.txt via --write:
both embed skill descriptions, so the rewrite staled them; check
modes exit 0 again. Codex artifact unaffected (no descriptions).
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
2026-08-29 17:38:18 -04:00
Magnus Hedemarkandfactory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Full lastfm-model rebuild of the jellyfin skill against the 12.0-era
OpenAPI spec, core-dev authorization guidance, and server source:
- Document the researched auth sequence end to end: complete pre-token
Authorization: MediaBrowser Client/Device/DeviceId/Version header
required by POST /Users/AuthenticateByName (400 "Error processing
request." without it), AccessToken returned, then Token= on the same
header (legacy X-Emby-Token deprecated, disableable since 10.11,
targeted for removal at 12.0).
- Extend scripts/jellyfin: new `login` subcommand demonstrating the
pre-token header and printing session exports (password via
stdin/prompt/env only), seasons/episodes TV navigation, next-up
--series-id, browse --user-id (userId is required on non-API-key
auth per the ItemsController guard), modern Token= header transport
with X-Emby-Token fallback, 503 Retry-After handling, search
Id/deprecated-ItemId fallback.
- Add 5 cited reference files (auth/sessions, endpoint catalog,
user-scoping matrix, gotchas field guide, worked recipes) plus
quick-connect; all cite api.jellyfin.org and live-verified sources.
- Upgrade relocated scripts/test_jellyfin_cli.py to the double-runner
standard: 24 tests (was 8) covering help, argument errors, dry-run,
mocked login header sequence, TV navigation, search-id fallback, and
jq-executed pipeline-consumability chains; zero egress proven via
proxy-trap rerun.
- Add evals/evals.json (6 cases incl. emby-install-not-for-jellyfin
negative probe); rewrite SKILL.md (224 lines) and README; sync root
README blurb and skill-triggers row; regenerate marketplace.json and
llms.txt (description-embedding artifacts).
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Merging with required validation green. Droid Auto Review was retried twice and failed before producing a review because DeepSeek V4 Flash rejected the action's ApplyPatch tool; the check is non-required per branch protection. The diff was independently inspected and local/repository validation passed.
2026-08-26 19:42:25 -04:00
Magnus Hedemarkandfactory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Addresses the tracked follow-up debt from thicken-openlibrary: the client
already bounds /type/redirect stub chasing at MAX_REDIRECT_HOPS, but a
chain that outlives the budget silently handed back an opaque stub, which
downstream commands rendered as an empty-shaped record with no hint why.
The walk now emits a stderr warning naming the unresolved location before
returning; mocked test drives HOPS+1 chained stubs end to end.
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
2026-08-26 19:35:15 -04:00
Magnus Hedemarkandfactory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
cmd_work tolerates explicit "authors": null (and non-dict entries) via
(data.get("authors") or []) guarded iteration, returning an empty array
instead of raising TypeError. cmd_isbn --json now emits authors as an
array of bare OLA keys matching `work --json` under the same field:
the edition path uses tolerant key extraction (flat refs, stray
double-nested refs), dedupes, and falls back to the linked work's
double-nested author keys when the edition ships none; publishers
likewise become a real list. Human output still renders comma-joined
labels. Refreshes the recipe gotcha note that still described the old
raw-curl work-record shape.
Adds mocked coverage: null-author work record (JSON [] + human '?'),
cross-command symmetric author arrays, tolerant edition key-only and
mixed-shape refs, ISBN handoff type stability, human label rendering,
and label-vs-key separation on mixed records.
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
2026-08-26 19:32:59 -04:00
Magnus Hedemarkandfactory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
SKILL.md essential commands show --page usage, add a seq/jq page-loop
recipe driven by the pagination.page_count field of the JSON output
(with 429 Retry-After handling), and document that --json emits
movies/shows plus the normalized pagination object whose keys mirror
X-Pagination-* headers, degrading to {} when headers are absent; human
output notes the Page N of M footer rule. References state
per-invocation paging and the same degradation fallback. Evals replace
the header-only pagination case with an executable loop case and a
second-page trending case asserting --page, pagination keys, and array
preservation. README Quick Start and test-table rows updated to match.
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
2026-08-26 18:50:30 -04:00
Magnus Hedemarkandfactory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Every discovery command (movie/tv x trending/popular/anticipated) now
accepts --page alongside --limit and forwards both as query parameters.
TraktClient._get returns (data, pagination) where pagination is the
X-Pagination-* header set normalized onto the stable keys page, limit,
page_count, and item_count; missing or non-numeric headers degrade to an
empty object. JSON output keeps the movies/shows array beside a new
pagination object, human output appends "Page N of M" only when the
headers are present, and cmd_movie/cmd_tv collapse into one shared
cmd_discovery handler.
Adds mocked coverage for page=2 request params across all six commands,
header normalization (full/lowercase/partial/unparseable/missing),
missing-header fallback at client level, stable movie trending wrapper
and TV shapes beside pagination, and human page-line presence rules.
Green under pytest strict-markers, unittest discover, and the proxy
trap (zero egress).
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
2026-08-26 18:49:47 -04:00
Magnus Hedemarkandfactory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
- Replace raw-argv dispatch with parsed-attribute routing; add the
documented nested `genre list --type movie|tv` subparser while keeping
the flat legacy form a clean argparse rejection instead of a crash.
- Route `tv search` through client.search_tv (/search/tv) with TV
formatting (name / first_air_date) via new cmd_tv_search.
- Gate find --source to exactly the official eight external_source
values (imdb_id, facebook_id, instagram_id, tvdb_id, tiktok_id,
twitter_id, wikidata_id, youtube_id); docs explicitly reject retired
freebase_mid/freebase_id; SKILL.md documents both --type variants.
Adds parser-level regression tests for genre list, endpoint-selection
and output-shape tests for tv search, and parameterized acceptance and
rejection tests for external_source values (13 tests, 10 subtests,
green under pytest strict-markers, unittest discover, and the proxy
trap).
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
2026-08-26 18:29:26 -04:00
Magnus Hedemarkandfactory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Add researched TMDb references, external-ID and detail commands, offline tests, and eval coverage. Refresh the human README and generated catalogs.
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
2026-08-26 09:52:28 -04:00
Magnus Hedemarkandfactory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Root README blurb and skill-triggers row updated to match the new frontmatter description; marketplace.json and llms.txt regenerated via gen-*.rb --write (codex/agents outputs unchanged). Check modes all green.
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
2026-08-26 08:44:48 -04:00
Magnus Hedemarkandfactory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
SKILL.md rebuilt to the lastfm model: keyless setup with covers-host table, intent-grouped commands including new editions/ratings, ISBN-to-work-to-author pipeline recipe, jq guidance, Known Gotchas grounded in researched behavior (ISBN 302 redirects, merge stubs inside HTTP 200, OL...M/W/A suffix system with double-nested author refs, availability-needs-ia projection rule, silent-empty search errors, rate etiquette), When-to-use/When-not-to-use boundaries, and a four-row reference routing table. Body 240 lines. README rewritten for humans with verified What You Get paths. Description updated with imperative verb start and negative boundary.
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
2026-08-26 08:44:37 -04:00
Magnus Hedemarkandfactory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Six schema-v1 cases: ISBN-to-work-author key-graph walk, ebook discovery pipeline, the ISBN 302-redirect gotcha diagnosis, author disambiguation, a should-not-trigger probe for Koha/MARC library administration (id contains -not-), and keyless-setup/rate-etiquette guidance. Passes validate-evals and the fake-adapter paired smoke.
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
2026-08-26 08:44:08 -04:00
Magnus Hedemarkandfactory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
27 tests across five classes: help output, argument errors, dry-run plans, mocked-client logic (merge-stub following with .json suffix repair, work-author fallback for authors:null editions, editions paging, ratings join, covers-host URLs, empty-results-as-success), plus two live probes gated behind OPENLIBRARY_LIVE_TESTS=1 that skip cleanly otherwise. Passes strict-markers pytest, unittest discovery, and the proxy-trap zero-egress rerun.
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
2026-08-26 08:43:54 -04:00
Magnus Hedemarkandfactory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
New subcommands: editions (per-work edition listing with next_offset) and ratings (joined ratings + bookshelf counts). The client now follows in-body /type/redirect stubs left by merged records (appending .json to stub locations, since extension-less URLs 301 into HTML), recovers author keys from the linked work when edition records ship authors:null, normalizes bare/path key forms, unwraps {type,value} text fields centrally, assembles covers-host URLs skipping -1 placeholders, and validates sort choices client-side to avoid the server's plain-text 500 on unknown values. Existing flags, subcommands, --json, and --dry-run preserved.
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
2026-08-26 08:43:43 -04:00
Magnus Hedemarkandfactory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Four cited reference files distilled from live-verified research against
openlibrary.org developer docs: OL...M/W/A key graph with merge-stub behavior,
search query syntax and error model, ISBN 302 redirect resolution and covers
host rules, plus worked curl/jq pipelines with a symptom-indexed gotcha table.
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
2026-08-26 08:43:13 -04:00
Magnus Hedemarkandfactory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
The die() message on connection failure told users to 'use --server',
but no such flag exists; JIRA_SERVER is the only endpoint override.
Replace the false clause with a hint that matches actual behavior.
Flagship scrutiny follow-up (non-blocking issue 1 from
thicken-jira-flagship validation).
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
2026-08-26 06:50:46 -04:00
Magnus Hedemarkandfactory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>