commit() is async but was called without await from sync handlers
(clone_next, clone_end, clone_sub, delete, copy_source, del_custom,
add_param, _sync_entry, _randomize) — causing saves and UI refreshes
to silently never run. Made all handlers async and added await.
Also fixed for i,entry loop shadowing the card's i parameter,
which was causing _render_vace_settings to receive the wrong index.
Removed unawaited render-time commit() in resolutions init block.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
_render_preview_fields was only rendering hardcoded known keys.
Now adds a Resolutions section (W/H/Seed per slot) and a Custom Fields
catch-all for any other keys not in the standard set.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
_get_data and _get_keys were querying the SQLite DB which only gets
populated when db_enabled is on. JSON file is always the source of
truth, so read from it directly — fixes missing keys (e.g. resolutions)
when DB hasn't been synced.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Implements ProjectResolution with TDD: fetches a [width, height] pair
from a resolution series by loop index, clamping out-of-bounds indices
to the last entry and returning (512, 512) defaults on error or missing key.
Also registers the node in mappings and updates TestNodeMappings count to 4.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace HistoryTree (DAG with branches, Graphviz rendering) with a flat
chronological SnapshotTimeline. New UI features: split-view layout,
snapshot compare/diff, cherry-pick restore of individual sequences or
fields, auto-snapshots with debounce, and pin/filter support.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Hidden widget sync passes sequence_number as string, causing format
code errors downstream. Cast to int before use.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
API returns {"files": [{"name": "...", "data_type": "..."}]}, not a
plain array. Extract file names from the nested structure.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- file_name is now a combo dropdown populated from the API when
manager_url and project_name are set
- ProjectSource outputs sequence_number (INT) for downstream use
- Refreshes file list when project_name or manager_url changes
- Updated tests for new output and error-default behavior
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When ProjectKey configures before ProjectSource, _getSourceLabels
returns empty. replaceWithCombo now always keeps the saved value in
the options list so it survives the race condition.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The key_name combo now only updates its dropdown options from the API
but never changes the user's selected value. Only the output value
refreshes on execution.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The async _refreshKeys call on every mouse click caused a race condition
where clicking the key_name dropdown would trigger a re-fetch that
overwrote the user's selection. Keys are now only refreshed on source
label change and workflow load.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
ProjectKey.fetch_key now returns empty defaults instead of raising
RuntimeError on API errors. Added logging to _syncFromSource and
fetch_key to trace the seq=4001 vs seq=4 mismatch.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
ProjectKey onMouseDown now triggers _syncFromSource + _refreshKeys so
clicking a relay always picks up source config changes. Added console
logs to notifyRelays and _refreshKeys for diagnosing sync issues.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Reverses the previous merge migration. Lora data is now stored as
separate keys: 'lora 1 high' (STRING name) and 'lora 1 high strength'
(FLOAT). This allows ProjectKey relay nodes to output name and strength
as properly typed separate values.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When ProjectSource widgets (url, project, file, sequence_number)
change, all ProjectKey nodes referencing that source now re-sync
and refresh their key dropdown immediately.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Combo widgets show "undefined" when values list is empty. Now ensures
at least one entry (empty string placeholder) and picks a valid default.
Also populates source labels immediately on node creation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- INT widgets (sequence_number) now properly hidden using origType +
hidden flag pattern from fast_saver.js
- source_label and key_name are now replaced with real combo widgets
via addWidget("combo") instead of just setting type="combo" on
STRING widgets, which didn't produce working dropdowns
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
ProjectKey fetches live API data, so it must re-execute on every queue.
Added comment explaining why source_label exists but is unused in Python.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The history_tree_backup (created by _delete_nodes) was storing full
snapshot data in every backed-up node — 185MB+ per backup entry.
This caused the JSON file to re-bloat to 300MB on every save.
Now:
- _delete_nodes backs up tree metadata only (no snapshot data)
- Load paths strip snapshot data from existing backup entries
- Prevents both disk and RAM bloat from backup accumulation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The JSON file was storing full snapshot data in every history node,
causing files to grow to multi-GB. Now when DB is enabled:
- sync_to_db receives full tree (extracts snapshots to DB)
- save_json receives slim tree (no snapshot data)
- JSON file stays small, DB is authoritative for snapshots
When DB is disabled, JSON still stores full snapshots (only store).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add load_json to tab_timeline_ng imports (NameError on disk fallback)
- Wrap save_history_tree in BEGIN/COMMIT transaction (was autocommitting
each statement, risking partial writes on failure)
- Clean up orphaned history_snapshots in sync_to_db when nodes are
removed from the tree
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- _auto_change_note now loads previous snapshot from DB instead of
reading stripped in-memory node (was producing wrong commit messages)
- _render_mass_update now strips snapshots after save (was leaking RAM)
- Only strip snapshots when DB is enabled (preview/restore still works
without DB via in-memory or disk fallback)
- _render_data_preview adds disk fallback matching _restore_node
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
History tree nodes stored full data snapshots in memory (5-50MB each),
accumulating with every save. Now:
- New `history_snapshots` DB table stores node data separately
- `save_history_tree` and `sync_to_db` extract snapshots before saving
- In-memory tree nodes only hold metadata (id, parent, note, timestamp)
- Restore and preview load snapshots from DB on demand
- `save_and_snap` uses json roundtrip instead of deepcopy (1 copy not 2)
- `_src_cache` moved to AppState, cleared on file switch
- `strip_snapshots()` method on HistoryTree for explicit cleanup
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
json.dump in a background thread would crash with "dictionary changed
size during iteration" when the UI mutated data concurrently. Now all
save_json and sync_to_db calls receive a json.loads(json.dumps(data))
snapshot, isolating the serialization from live UI mutations.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
ORDER BY sequence_number put all subs (>=1000) at the end. Now groups
by parent (seq/1000), main first, then subs in order.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replaces slow JSON file parsing with fast DB queries for file loading.
Returns the same dict structure as load_json (top-level + batch_data +
history_tree).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- load_file and on_select try db.load_full_data first (~0.01s),
fall back to load_json only when DB has no data
- Fix unawaited coroutine warning for auto-load (asyncio.ensure_future)
- Fix radio on_change to properly await async load_file
- Reuse current data cache when source file matches current file,
eliminating a redundant 1.3s JSON parse during render
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The COMMIT without BEGIN failed in autocommit mode, crashing ProjectDB
init and leaving _shared_db as None ("Database not initialized").
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Runs at DB startup, only updates rows that have stale separate strength
keys. No-op once all data is migrated.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>