Commit Graph
94 Commits
Author SHA1 Message Date
rootandClaude Opus 5.5 cb3fb9b128 docs(runbook): files authorization matrix, restore guards and identify limits after W6-B
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-28 00:50:52 +08:00
rootandClaude Opus 5.5 d3de2c8971 fix(files,test): probe requires organize.execute; rename duplicate E6 to E10; trash approval replay test
- POST /files/probe writes media_asset.media_info, so scope organize.read -> organize.execute
- e2e e6-w4a-endpoints -> e10-w4a-endpoints (number clashed with e6-auto-recover)
- trash: reusing a consumed approval / retired planId is rejected and the file stays

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-28 00:50:29 +08:00
rootandClaude Opus 5.5 2e3c2098fd docs: S-9 sync READMEs and porting notes with W5 code
- contracts README lists files.ts / auth.ts / browser.ts / redact.ts and auth:"session"
- adapters README fs row: FsProxy and the ./fsworker export
- server README: file-manager module, worker:agent and internal fsworker roles
- moviepilot-rust-transfer §7: compiled-binary fsworker and trash_item done (W5-E)
- 04 S9 row marked fixed (W6-B TOTP entry)

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-28 00:50:29 +08:00
rootandClaude Opus 5.5 2ddaf7bfa6 fix(fs): S-10 hang test hook requires UMT_FS_TEST_HOOKS=1; preflight warns when set
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-28 00:48:45 +08:00
rootandClaude Opus 5.5 b4560be48b fix(files): S-6 identify goes through the shared TMDB limiter and caps remote queries
- invoke-limits: sharedInvokeLimiter() (one semaphore set per process); agent
  capability routes default to it
- /files/identify: catalog.lookup with includeRemote runs under the shared
  TMDB semaphore + 15s timeout; at most 20 distinct remote queries per
  request, further items fall back to local recall with a warning

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-28 00:48:45 +08:00
rootandClaude Opus 5.5 ba1361a9b6 feat(web): S-3 TOTP entry in the account popover
Account popover (cookie sessions) gets a "二次验证" item showing the current
state; the dialog wires GET/POST /auth/totp: begin shows the one-time base32
secret (grouped) and otpauth URI for manual entry, enable confirms with a
6-digit code, disable takes current password + code. No QR image (would need
a new dependency); session query is invalidated so the state label updates.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-28 00:46:55 +08:00
rootandClaude Opus 5.5 17cf3cbf97 fix(files,security): S-1 per-source Move authorization, S-2 session-only annotation, S-5 restore guards
S-1 (/files/move, /files/organize action=move):
- organize-guard: authorizeMoveEntities checks every source's media entities
  (declared entity plus entities of registered assets under the source);
  one-time approval still covers the whole request; any source that cannot
  be attributed to an entity only passes with an approval; denial lists every
  unauthorized item; optional non-consuming pre-check
- transfer: entities per source (directory = registered assets beneath it)
- organize: all move groups pre-checked before any group executes; any
  denial -> whole request 403 approval_required
S-2:
- api.ts: GET /files/download and POST /files/trash/purge marked
  auth:"session"; files routes attach requireAdminSession from the registry
  annotation; handler-side purge check removed, download keeps a same-rule
  defense check; permanent delete uses isAdminSession
- DEV key rule written down: equals an admin-scope key for session-only
  endpoints, still admin for Move/delete approval bypass (as authorizeMove)
- api-registry.test: session list updated; new reverse assertion that no
  non-session endpoint answers 403 to an admin-scope bearer
S-5 (trash restore):
- restore-to requires a writable managed library root (isWritableTarget)
- in-place restore rebuilds missing parents level by level without
  following symlinks (mkdirWithin), realpath-checked per level
- cross-volume restore capped by FILES_TRASH_CROSS_MAX_BYTES; cross-volume
  copies (trash in / restore out) go through fsproxy
Tests: multi-entity move 403 + listing, unattributed source, organize foreign
asset 403, download/purge 403 for DEV and admin-scope keys, restore target
not writable, symlinked parent, rebuild parents, cross-volume cap.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-28 00:45:56 +08:00
rootandClaude Opus 5.5 9887d8b311 chore(lint): clear biome warning (unused dt2) and redundant fragment
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-28 00:45:56 +08:00
rootandClaude Opus 5.5 47bd04aec0 fix(adapters,security): S-4 rss/browser redaction use the shared contracts key table
- contracts: isSensitiveQueryParam (whole-name match on SENSITIVE_QUERY_PARAMS
  or isSensitiveKey), the single source for query credential names
- rss/redact: drop local SENSITIVE_QUERY_KEYS; param checks go through
  isSensitiveQueryParam (+ caller extras); REDACTED re-exported from contracts
- browser/redact: CREDENTIAL_PARAM built from SENSITIVE_QUERY_PARAMS, JSON keys
  also checked with isSensitiveKey; keeps only its own rules (path passkey,
  cookie names, a11y password fields); remove stray regex statement
- redact-consistency.test: 24 credential spellings (pass_key, c_secure_pass,
  refresh_token, password, uid_key, auth, ...) masked by contracts, rss and
  browser alike; plain params untouched; rss extract/unredact round-trip

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-28 00:45:56 +08:00
rootandClaude Opus 5.5 b48d8592d5 docs(changelog): B1 complete [0.1.0] with file manager, subscriptions, transfer, agent UI and known limits
Covers W4-E4/F, W5-A..E and W6-A grouped by feature; known limitations
replaced with the 19 items from docs/plan/07 §8 (stale series-completion
item removed).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-28 00:34:36 +08:00
rootandClaude Fable 5.1 1c7af8b7e5 docs(plan): second-round v0.1 final review
Co-Authored-By: Claude Fable 5.1 <[email protected]>
2026-09-28 00:33:30 +08:00
rootandClaude Opus 5.5 887843f777 fix(server,test): W6-A stabilize CI — sync lost update, atomic recovery summary, serial PG tests
- downloads.ts observe: re-read download_task FOR UPDATE inside the tx and merge
  from the locked row; qB sync could overwrite imported back to importing when
  verifyAndImport committed between the sync read and write (E8 flake).
- agent finalize: accept summaryPrefix so the recovery verdict is written with
  the terminal status in one update (E6 read a budget_exceeded run before the
  "未恢复:…" annotation landed); recover-summary step kept, now idempotent no-op.
- organize.ts: drop local slotComplete and the once-subscription completion
  write; completion/history are decided only by applySlotEvent(verify_passed)
  (W5-C follow-up, removes double write). Manual slot organize uses the shared
  subscriptions.slotComplete.
- vitest: server split into unit (parallel) and pg (file-serial, groupOrder 1)
  projects; packages/tasks file-serial; explicit worker concurrency in e2e.
- docs: W6 stabilization record in 04-v0.1-acceptance.md.

Test expectations unchanged. Full `deno task ci` x3 green: 369s / 341s / 337s.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-28 00:32:57 +08:00
rootandClaude Opus 5.5 36aa99b8aa feat(files): W5-A2 move/copy via planImport, organize overrides, delete records, download
- /files/move|copy go through planImport's new `transfer` variant (keep names, directory
  expanded to per-file plan) → organization_record + verifyAndImport/executeRecord: per-file
  ledger resumable, fsproxy, cross-volume directory move = per-file copy→verify→delete then
  remove empty source dirs; shared plan store + plan_stale; asset_location follows per file,
  path_binding revised when a whole directory moved (finalizeTransfer); request waits up to
  FILES_TRANSFER_WAIT_SEC, else executed.pending
- /files/organize per-item overrides take effect: season/episodes (domain planOrganize
  overrides), contentUnitId coverage, targetDir (no binding), operation, slotId (satisfied
  after verify); warnings only for inapplicable overrides
- delete/trash/restore write organization_record (action trash|delete|restore, file-level
  results; migration 0026)
- GET /files/download (admin session, nfo/subtitle/image, size cap, streamed, audited)
- GET /files/records?ids|planIds for the organize page
- fs race errors map to 503/404/403/400 instead of 500
- runbook updated

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-27 23:53:50 +08:00
rootandClaude Opus 5.5 3641ab9573 feat(server,fs): W5-E production fsworker role, settings auto-investigate mode, replace old file to trash_item
- main.ts: `--role fsworker` dispatched before the rest of the module graph is
  loaded (other imports became dynamic); runs fsWorkerMain from the new
  `@umt/adapters/fsworker` export (~150 ms startup in the compiled binary)
- fsproxy: default worker command picked per runtime (deno CLI -> `deno run
  fsworker.ts`, compiled binary -> `<execPath> --role fsworker`); stats expose
  workerKind; UMT_FS_TEST_HANG_AFTER_BYTES acceptance switch for containers
- compile: --allow-run adds /app/umt-server (spawn self); start task allows deno
- organize: replaced old file moved into the file-manager trash layout
  (<root>/.umt-trash/<day>/<uuid>/<rel>) and registered in trash_item, ledger
  result follows; organize.transfer log carries fsproxy stats
- settings: autoInvestigateMode (investigate/recover) + max recover attempts
- deploy.md: container verification (subprocess self, TIMEOUT -> SIGKILL x3)

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-27 23:50:10 +08:00
rootandClaude Opus 5.5 fc49c58359 docs(plan): mark W5-C subscription enhancement status in 05-subscription-gap
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-27 23:34:13 +08:00
rootandClaude Opus 5.5 80780add66 feat(web): W5-C subscription progress, manual search and episode total
- subscription sheet: 立即搜索, active-search times, 追更进度 (per-season total with source/lock,
  per-episode state chips, in-flight/deferred counts) and set/lock season episode total
- labels for subscription pending and candidate decision deferred

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-27 23:34:13 +08:00
rootandClaude Opus 5.5 7aa6cac717 feat(ao,sources): W5-C subscription completion, Slot × unit reservation, deferral, pack file selection, active search
- completion by season episode_total ledger (applySlotEvent verify_passed hook overrides organize's
  complete): unknown total keeps tracking and records suspected-missing; pending never completes;
  once / continuous current-season completion writes subscription_history
- evaluation: missing = release units ∩ episodeRange − covered − in-flight; series slots may hold
  several unit-disjoint in-flight plans; overlapping/busy releases are deferred (slot_deferral) and
  re-evaluated when a plan ends (next_evaluate_at due) or on the periodic slot re-evaluation
- per-unit upgrade via slot_unit ledger; site scope (params.siteIds); site facts in evaluation context
- season packs: after submit read qB files and setFilePriority(0) for covered/in-flight episodes;
  whole pack with recorded reason when undeterminable; removed downloads release their reservation
- searchSubscription task (title/aliases × enabled sites via liveSearch, snapshot + rate limiter):
  on create, every searchIntervalHours (default 24h) and POST /subscriptions/{id}/search
- refreshMetadata writes season totals (only grows, floored by covered, lock respected) and turns
  metadata_pending subscriptions active; plan loop refreshes tracked series every 6h
- endpoints: subscription progress, episode-total, subscription-history; e9 continuous-series e2e

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-27 23:34:07 +08:00
rootandClaude Opus 5.5 1dd460d359 feat(db,contracts): W5-C subscription units migration 0025, contracts and mapping
- subscription: status pending (TMDB not ready: searchable/evaluable, not completable),
  last_searched_at / next_search_at
- content_unit (season): episode_total ledger with source / lock / timestamp
- acquisition_plan: unit_keys (Slot × unit reservation) and file_selection; drop the
  one-in-flight-per-slot unique index (checked under slot row lock per unit instead)
- new tables slot_deferral, slot_unit (per-unit quality ledger), subscription_history
- contracts: SubscriptionParams, SubscriptionHistory, SlotDeferral, SlotUnit, SubscriptionProgress,
  EpisodeTotalSet, CandidateEvaluation pri/trace/unitKeys and decision deferred;
  endpoints subscriptions.search/progress/setEpisodeTotal and subscription-history
- mapping: evaluation messages via describeViolation, pri/trace passthrough

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-27 23:33:56 +08:00
rootandClaude Opus 5.5 d162d464c4 feat(domain): W5-C subscription gaps, episode totals, multi-inflight slot, hard conditions and priority ladder
- resolveEpisodeTotal: totals only grow; TMDB regression floored at highest covered episode; manual lock
- computeUnitGaps / seasonProgress / unitsOverlap: missing = units ∩ range − covered − in-flight,
  season wildcard reservation, suspected-missing when total unknown
- transitionWithInflight: slot status aggregates several in-flight plans (Slot × unit reservation)
- hard conditions: excludeSources, hdr sets, codec sets, per-unit size, include/exclude regex
  (whitelist-validated), site scope, minSeeders, freeOnly (site facts via EvaluationContext)
- priority ladder (MP rule-group tiers) → pri 0-100 with per-tier trace; priority-basis upgrades,
  targetPri ceiling, upgrade modes movie/per_unit/full_pack, improvableUnits
- all evaluations carry readable trace via describeViolation

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-27 23:33:46 +08:00
rootandClaude Opus 5.5 89ea68465e feat(web): W5-B file manager page /console/files
Roots + lazy dir tree, virtualized grid with status badges and asset/slot/
download links, breadcrumb, sort, glob search, hidden toggle, filter chips,
paging and truncation notice; multi-select (Shift/Ctrl/all), action bar,
context menu, drag-to-move with dryRun preview, keyboard navigation,
offline (503) and empty/error states, mobile layout with tree drawer.
Rename/move/copy/delete dialogs with dryRun previews and reference checks,
4-step organize wizard, trash view (restore/restore-to/purge, expiry).
DEV-only ?mock=1 in-memory backend; smoke route list includes /console/files.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-27 23:16:35 +08:00
rootandClaude Opus 5.5 2e2d56184c feat(fs): W4-E4 fsproxy hang isolation, partial sweep, replace-with-verify, TIMEOUT retry
- adapters/fs: FsProxy + fsworker run each file op in a killable subprocess;
  progress-stall watchdog (FS_HANG_TIMEOUT_MS) for copy/hash, total timeout for
  quick ops; SIGTERM -> SIGKILL -> FsError('TIMEOUT'); stat/checkRoot timeouts
  never read as missing
- copyWithVerify: onExisting conflict/skip/replace (hardlink backup + atomic
  rename, old file to .umt-trash or deleted), sweep stale partials before write,
  document why permissions/owner are not copied
- filesMatch/filesMatchSha256 throw FsError on read failure instead of
  match=false; crossDeviceMove skips redundant re-hash after sha256 copy
- FsErrorCode TIMEOUT + fsErrorClass; organize executeRecord routes fs ops
  through fsproxy, retries TIMEOUT/IO up to FS_TRANSFER_MAX_ATTEMPTS then opens
  a decision without deleting the record; reconcile errors no longer reported
  as EEXIST
- domain: subtitle .default marker (ORGANIZE_DEFAULT_SUBTITLE_LANG) and
  findOtherVersions (same season/episode/part, video only) as upgrade
  disposal candidates
- scripts/bench/fs-bench.ts and benchmark record in porting doc

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-27 23:15:05 +08:00
rootandClaude Opus 5.5 36dc048e89 feat(parser,sites): W5-D port title/zhconv/site parsing gaps found by MP differential
Title recognition (parseRelease / parseReleasePath):
- anime prefix tags (★N月新番, [国漫], 【22年日剧】), category lead bracket, `A / B` cn aliases
- `Name [01]`, `[TV 04]`, `#13`, `名称 12.mkv`, `S01 13-14`, `E13-14` episodes
- lead bracket as title vs group, trailing [Group], YTS.MX/Hall_of_C style groups, 字幕组 suffix
- `[dot.release.name][…]` unbracketing, `Season 2017` as year, leading date not airDate,
  date-only parent dir does not merge as TV
- original disc: Blu-ray + AVC/HEVC/VC-1/MPEG-2 without x26x/H.26x -> BluRay-Disc
- `{[tmdbid=;type=;s=;e=]}` explicit block, bangumi/anilist ids
- bare [1080]/[5.1], DTS-HD MA5.1, £ multi-group, 合集, pinyin title -> cn from subtitle,
  streaming platform table, CHS/CHT/GB/BIG5 in subtitle
zh-map: add 迴滾魷瑯臥駭; document one-to-many chars kept out.
Sites: tbody branch + header-row tightening via movieclaw-import rowSelector (18 definitions),
row-level case/hr/labels include the row itself, subtitle branch (searchType: "subtitles"),
parseSizeMp banker's rounding.
Differential snapshots regenerated; MP test sample sources registered in ledger.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-27 23:09:14 +08:00
rootandClaude Opus 5.5 8352e5e881 feat(web): W4-F rebuild agent conversation and drawer with agentui components
- Port agentui (MIT, ashish200729/agentui@b2b752b) Message/MessageBubble/MessageScroller,
  StreamingResponse, ToolResult/ToolApproval, TodoList, ApprovalCard, CodeBlock/FileDiff,
  Citations, PromptInput into components/agentui; drop motion/shiki/Next, switch colors,
  type scale, radii, durations and easing to semantic tokens, honour reduced motion
- Conversation: streaming cursor, collapsible thinking, tool cards with kind/scope/risk/
  idempotency badges and audit idempotency key, prominent server-rejection state for both
  whitelist rejections and unauthorized errors, compaction markers, budget meters with
  over-limit state, approval cards (admin session only), two-column final report
  (model said vs system verified with task/record links), follow-scroll with jump-to-bottom
- Composer: Enter send / Shift+Enter newline, stop = abort (confirmed), append,
  execute/plan_only switch, "execute this plan" from finished plan_only runs
- Session list sidebar with status filter and usage; reconnect/error banners with retry
- Drawer: route-derived context (entity/site/task), minimize to a live mini dock
- Fix stream refetch race when the run switches from loading to finished

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-27 23:08:17 +08:00
rootandClaude Opus 5.5 29cd10b27e feat(server): W5-A file manager module (/files)
Roots/list/stat with inline business status, path guard (realpath within
registered roots, symlink escape, offline root 503), mkdir/rename syncing
asset_location and path_binding revisions, two-phase move/copy/organize
(planId + source facts), trash with reference checks and purgeTrash task,
identify/probe/scrape, audit + idempotency keys. Runbook docs/runbook/files.md.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-27 23:02:20 +08:00
rootandClaude Opus 5.5 09f6e3a3e5 feat(db,contracts): trash_item migration and file manager contract refinements
- 0024_trash: trash_item table + unique idempotency index on artifact(files_idem)
- files.ts: TrashItemRow, delete planId/planExpiresAt, organize group warnings,
  scrape returns refreshMetadata taskId
- registry tests list the new table/row schema

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-27 23:02:14 +08:00
rootandClaude Opus 5.5 673cb3920a docs(plan): mark acceptance R2/R4/S5/S6/S8 fixed (W4-E3)
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-27 22:47:25 +08:00
rootandClaude Opus 5.5 ceff9cf51f feat(ao): W4-E3 manual organize guard, series completion, engine retry, v0.1.0
- POST /organization-records: sourcePaths must resolve (realpath) under a
  registered library_root or downloader path-mapping host path; `..` and
  symlink escapes rejected (400), dryRun included. Move requires an admin
  session, or an API key with an automation_grant covering the entity or a
  matching one-time approval (consumed on use), else 403. Manual Move from a
  managed download_task with unsatisfied H&R returns 409 and opens a
  decision; never silently downgraded to Copy.
- Series slot completion: total episode count is unknown while units are
  provisional, so the slot is not satisfied and the subscription keeps
  tracking; coverage is registered per actual file (creating provisional
  episode units), and already_in_library files count as verified presence.
- POST /engine/runs/{id}/retry (admin): re-enqueue by original task name and
  raw input with idempotency key retry:<id>:<n>, audited; retry button on
  the run detail page.
- E7 regular series e2e, E8 AT24 tag removal / task disappearance e2e.
- All workspace members and root set to version 0.1.0; CHANGELOG.md.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-27 22:47:11 +08:00
rootandClaude Opus 5.5 591cc78c7d test(porting): differential tests against MoviePilot Rust-accelerated parsers
Snapshot differential tests (known deviations registered, current state passes):
- title/path recognition: 216 samples vs MP MetaInfo/MetaInfoPath
- filter rules: 42 rules x 28 torrents vs MP FilterModule
- RSS/indexer parsing: 15 feeds, 72 indexer samples
- zhconv: 69 samples
Generator: scripts/mp-sync/gen-differential.py; report: docs/porting/mp-rust-logic-parity.md

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-27 22:44:11 +08:00
rootandClaude Opus 5.5 b86f75c011 feat(contracts): file manager API schemas and /files endpoint registry
Adds packages/contracts/src/files.ts (roots/list/stat, mkdir/rename,
move/copy/organize two-phase dryRun->planId, delete with reference checks
and trash, identify/scrape/probe) and registers Api.files in api.ts.
Implementation lands in a follow-up commit (W5-A).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-27 22:37:04 +08:00
rootandClaude Fable 5.1 3665daaf07 docs: MoviePilot subscription ledger and gap analysis
Co-Authored-By: Claude Fable 5.1 <[email protected]>
2026-09-27 22:36:17 +08:00
rootandClaude Opus 5.5 6e01497b3a docs(plan): mark acceptance R3 (in-grant recovery) done
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-27 22:35:11 +08:00
rootandClaude Opus 5.5 86af723b2a feat(agent): W4-E2 in-grant auto recovery for decisions with verified outcome
- settings.agent.autoInvestigateMode investigate|recover, investigateMaxAttempts, recoverVerifySec
- new capability download.recheck (execute, replay never): qB force recheck / resume, no source swap/delete
- autoInvestigate moves to agent/investigate.ts: recover mode runs execute with a recovery allowlist
  only when an active grant (published policy if bound) covers the recovery actions; otherwise degrades
  to read-only investigation and leaves suggestion + recheck option on the decision
- runAgent verifies recovery against business facts (download_task/task/source_release) before finalize;
  verified -> decision resolved by system:auto-recover, run summary '已恢复(系统核实)'; otherwise stays
  awaiting_user; per-root-cause attempt cap
- e2e E6: missingFiles -> download_failed -> recheck -> verified; no grant degrades; swap rejected;
  dedupe; attempts exhausted; budget exceeded keeps attention

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-27 22:35:03 +08:00
rootandClaude Fable 5.1 23309042dc docs: MoviePilot file manager study and our file manager spec
Co-Authored-By: Claude Fable 5.1 <[email protected]>
2026-09-27 22:34:13 +08:00
rootandClaude Fable 5.1 3a9b6f7f33 docs(design): agentui.pro reference for agent conversation UX
Co-Authored-By: Claude Fable 5.1 <[email protected]>
2026-09-27 22:32:45 +08:00
rootandClaude Fable 5.1 63d4b47fe1 docs(plan): v0.1 additional scope (subscription parity, file manager, agent UI, transfer semantics)
Co-Authored-By: Claude Fable 5.1 <[email protected]>
2026-09-27 22:27:46 +08:00
rootandClaude Opus 5.5 5bb06d641c docs(plan): mark W4-E1 security items fixed in v0.1 acceptance
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-27 22:24:59 +08:00
rootandClaude Opus 5.5 f48e1aac96 fix(security): W4-E1 approvals admin-session only, shared redact table, TMDB key redaction, prod mock gate
- POST /approvals and PATCH /approvals/{id} require a console admin session
  (EndpointDef auth:"session"); API keys incl. admin scope get 403, so an
  organize.execute key can no longer approve its own plan (S1)
- tests for single-use approval checks: expired, revision/payload hash
  mismatch, consumed, revoked, pending/rejected, plan mismatch; re-approve
  after plan change succeeds once and cannot be replayed (S4)
- one redact key table in @umt/contracts shared by server logger and agent
  redactForModel: rsskey, torrent_pass, authkey, downhash, c_secure_pass,
  passkey variants, x-api-key, cookie headers, nested objects/arrays (S2)
- TMDB network errors: message and cause redacted via redactUrl (S3)
- web Agent ?mock=1 only in DEV builds or when pi.provider is fake (S7)
- EndpointDef auth annotations for /auth/*, asserted against
  PUBLIC_AUTH_PATHS (S10); doc drift fixes (S11)

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-27 22:24:44 +08:00
rootandClaude Fable 5.1 79cdd26457 docs(porting): MoviePilot Rust module scope and transfer semantics comparison
Co-Authored-By: Claude Fable 5.1 <[email protected]>
2026-09-27 22:20:01 +08:00
rootandClaude Opus 5.5 b7237391a4 docs(plan): mark W4-D decoupling items done
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-27 22:15:51 +08:00
rootandClaude Opus 5.5 3792868816 build(docker): static ffprobe, --allow-run=ffprobe,sha256sum, three supervised processes
entrypoint runs api + worker (io) + worker:agent; compose/runbooks document
WORKER_CONCURRENCY, WORKER_AGENT_CONCURRENCY, ORGANIZE_WALK_MAX_FILES.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-27 22:15:43 +08:00
rootandClaude Opus 5.5 f6457a29db feat(settings): agent.sessionDir setting shown on settings page
null keeps the deployment default (AGENT_SESSION_DIR / DATA_DIR/agent-sessions).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-27 22:15:43 +08:00
rootandClaude Opus 5.5 f9c20c67dc perf(fs): 1MiB stream chunks, full sha256 via sha256sum subprocess, walk cap
- copy streams use 1MiB highWaterMark
- forced full sha256 uses Deno.Command(sha256sum), falls back to in-process stream;
  method recorded as hashVia and counted
- per-file organize.transfer timing log
- ORGANIZE_WALK_MAX_FILES caps manual path walks; dryRun returns truncated

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-27 22:12:16 +08:00
rootandClaude Opus 5.5 473c5e94a5 feat(server): io/agent worker groups, invoke limits for external IO capabilities, loop lag probe
- WORKER_CONCURRENCY / WORKER_AGENT_CONCURRENCY; --role worker (io), worker:agent, all (both)
- HTTP invoke of release.search/inspect, identity.resolve, catalog.lookup(remote):
  15s timeout + per-upstream semaphore (site 2, TMDB 4)
- worker event-loop lag probe: warn + count when drift > 5s

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-27 22:12:16 +08:00
rootandClaude Opus 5.5 fe9693d4ca refactor(ao): background loops only orchestrate; cleanup/reconcile endpoints enqueue
- separate qB sync timer from the planning timer
- threshold cleanup, reserved-plan and pending-import sweeps, 6h reconcile enqueue
  engine tasks with time-slot idempotency keys instead of running inline
- pending-import sweep selects by completed_at (sync refreshes updated_at every round)
- POST /download-cache/cleanup and /library/reconcile return {taskId, runId} (202);
  web jumps to the engine run page
- test: a 50MB verifyAndImport in progress does not delay qB sync

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-27 22:12:16 +08:00
rootandClaude Opus 5.5 a9cee69bd2 feat(tasks): workers started with versions only claim their own tasks
OpenWorkflow 0.10.1 claims any run regardless of workflow name and fails
unregistered ones with 5s-5m backoff; filter the claim SQL by name@version.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-27 22:12:04 +08:00
rootandClaude Fable 5.1 cda9255083 docs(plan): v0.1 acceptance review (pre W4-D/E)
Co-Authored-By: Claude Fable 5.1 <[email protected]>
2026-09-27 22:01:39 +08:00
rootandClaude Opus 5.5 9e6ff33ef4 test(server): wait for engine run completion in E3 instead of asserting immediately
The business row settles before the engine marks the workflow completed; under CI load the
window is a few hundred ms and the direct assertion flaked.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-27 21:46:37 +08:00
rootandClaude Opus 5.5 effaa32b70 feat(browser): W4-C BrowserProvider contract and camofox-browser adapter skeleton
- contracts/browser.ts: provider kind, per-capability {supported, verified} flags,
  session/tab/control-lease rows, NavigationBudget, redacted BrowserSnapshot,
  DownloadArtifact with blob/secret refs, BrowserErrorKind
- adapters/browser: BrowserProvider interface, camofox client (health, capabilities
  static + /openapi.json probe, openSession/navigate/snapshot/screenshot; rest
  not_implemented for M2), none provider, redactSnapshot, profile serial lock,
  domain allowlist budget; Bearer access key via BrowserSecretResolver
- testkit/browser: mock camofox server (auth, fixtures with secrets, faults)
- db 0023: browser_provider/session/tab/control_lease with one-active-lease and
  one-live-session-per-profile partial unique indexes; types regenerated
- docs/design/browser-provider.md: contract, camofox OpenAPI 1.17.0 mapping,
  unverified items and M2 prototype checklist; Playwright is not a product browser

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-27 21:39:29 +08:00
rootandClaude Opus 5.5 269a2269a1 test(web): Playwright full-route smoke as deno task test:web:smoke
Logs in, opens every console route (detail routes resolved from list endpoints), fails on
console errors, uncaught exceptions or 4xx/5xx API responses, and screenshots each page.
Uses playwright-core with the local Chromium; documented in README.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-27 21:32:18 +08:00
rootandClaude Opus 5.5 1023642ef9 feat(web): W4-A wire console to real endpoints
- Agent page uses contracts (AgentRun/AgentRunDetail/AgentGoalReport) instead of a local
  mirror; ?mock=1 stays as an explicit demo switch; run snapshot refreshes on agent.run_status;
  stream auto-follow only while the user stays near the bottom (abort stays reachable)
- settings: Pi provider select incl. fake, new Agent runtime card (budgets, fakeScript)
- download trace uses /tasks?subjectId= and /organization-records?downloadTaskId= instead of
  time-window engine run matching and path matching; new business-task tab with cancel/retry
- workbench download dialog posts /acquisition-plans and shows per-slot rejection reasons
- preference tag revision history; subscription search by title/kind; identity/alias/subscription
  lists show entity titles; slot cards show current asset summary; policy preview sample titles
- DecisionSummary / IdentityRevisionList / ReleaseIdentityResult / TaskAccepted / PolicyPreviewSummary /
  OrganizePlanArtifactContent taken from contracts
- docs: SSE for console (cookie) vs GET /events?after=&limit= JSON replay for API keys

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-27 21:32:11 +08:00