Clean up project to professional software engineering standards #26
Labels
No labels
bug
duplicate
enhancement
help wanted
invalid
question
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
cmoriarty/trog#26
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
We have been doing a good job of breaking large tasks into smaller ones, and building/testing incrementally as we go. I just haven't been scrutinizing the latest code changes as well as I should have. This ticket is to do a complete code review with the mission for this to be a first-class open source project.
First begin with an audit of the code to create a prioritized list updates. Both a line-by-line granular look (to find irrelevant/dead code and comments, syntax problems, etc), but also a high-level design audit. One goal is for this to be a self-hostable project for other people, although right now it is very specific to my Trogdor server. There are many things that should be considered to make that a reality. Another goal is for me to learn and leverage modern AI tools as much as possible, so if there are any strategies and processes that the TROG project should adopt (graphify, etc), that should be part of the audit.
Then create a plan to address the most critical and high priority things, and allow me to specify which medium/low tasks to take on.
Implement the planned tasks. Possibly create spin off child tickets for large jobs, or keep all work contained in this ticket.
Code audit (#26) — full-repo review, 2026-07-26
Scope: every source file in
server/,cli/,studio/src/,audio-server/,playtest/,scripts/,brain/, both compose files, all Dockerfiles, CI workflows, and the test suite (~12k lines). Two lenses per the ticket: line-by-line (dead code, stale comments, bugs) and design-level (self-hostability, process/AI tooling).Overall: the core is in better shape than the ticket feared. The orchestrator/drain/seat machinery is coherent, comments overwhelmingly explain why (many encode live-caught lessons), the studio is clean idiomatic React, and the test suite is real (118 tests, contracts not mocks-of-mocks). The problems cluster in three places: the repo lies about its portability, conductor-era references that no longer exist, and one genuinely broken thing nobody noticed.
P0 — Critical
1. CI has been red on main for the last 5 commits
tests/test_production.pyimportsserver/graphs/production.py, which doesfrom langchain_deepseek import ChatDeepSeekat module level.langchain-deepseekis pinned inserver/requirements.txtbut missing fromrequirements-dev.txt— every CI run since the ChatDeepSeek switch fails at collection withModuleNotFoundError. Reproduced in a clean venv; the local.venvmasked it because the package was installed there manually at some point (pip showconfirms nothing requires it).Fix: add
langchain-deepseek==1.1.0to requirements-dev.Process fix (the more important half): red CI sat unnoticed while
make deploykept shipping. Options: (a)make redeployqueries the latest Actions run for HEAD and refuses on red (same spirit as its dirty-tree guard), (b) a Forgejo Actions failure notification. Recommend (a) — it's ~15 lines in the existing guard chain.2. No LICENSE file
README says "TBD — an OSI-approved license before anything ships." For "first-class open source project" this is item zero: without a license file the repo is legally all-rights-reserved regardless of intent. Everything trog builds on is MIT/Apache-2.0, so either works. Needs your call: MIT (maximally simple) or Apache-2.0 (patent grant, matches LangGraph/Aegra).
P1 — High (self-hostability + real bugs)
3. Personal-site values baked in as code defaults
.env.exampleclaims "Nothing site-specific is hardcoded in the repo." Currently false:server/trog_lib/config.py:7—FORGEJO_URLdefaults tohttps://forgejo.underthere.xyzserver/trog_lib/seats.py:29-32—COMFY_IMAGE/AUDIO_IMAGEdefault toforgejo.underthere.xyz/cmoriarty/...FILES_URLdefaults tohttp://trogdor:3923in orchestrator.py, drain.py, playtest.py, cli/main.pycli/main.py:45—TROG_URLdefaults tohttp://trogdor:8200;TROG_AEGRA_URLtotrogdor:2026studio/vite.config.ts— dev proxy targets default totrogdordocker-compose.yml—FORGEJO_URLdefault repeated 4×;FORGEJO_USERdefaults tocmoriartyFix: one pass. Server-side settings fail fast when required and unset (the
FORGEJO_TOKENpattern already does this); laptop-side (CLI) defaults becomelocalhost; compose defaults become:?set in stack envor neutral examples. Route everything throughconfig.pyso there's exactly one place to look.4. Two parallel Forgejo clients
trog_lib/forgejo.py(httpx, token auth,FORGEJO_URL/FORGEJO_TOKEN) andcomfy_item.py'sforgejo_commit/forgejo_fetch(urllib, basic auth,TROG_FORGEJO_URL/TROG_FORGEJO_AUTH) — the second is the vendored conductor contract, which is why compose has to synthesizeTROG_FORGEJO_AUTH: user:tokenbeside the token it already passes. The retry/stale-HEAD hardening inforgejo_commitis valuable and should survive the merge; the duplicate env contract should not. Also foldforgejo.commit_file/commit_binary(near-identical bodies) into one.5. Mock seat has no
/vocalrouteaudio_item.route_for("vocal")→/vocal, butmock_seat.pyhandles only/musicand/sfx— aSEAT_MODE=mockortrog test asset --mockrun with a vocal item 404s. Untested becauseCYCLE_SPEChas no vocal entry, so the plumbing tier never exercises the vocal path. Fix: add the route + a vocal entry (withExpected:) to the cycle spec.6. Orchestrator shutdown can skip brain restore
lifespandoestask.cancel()without awaiting the task, so the worker'sCancelledErrorcleanup (cancel drain, release seats, restore brain) races process exit. Boot-timereconcile()covers the next start, but a plaindocker stopof a busy orchestrator can leave the brain down until then. Related:restore_brain()clears_brain_takeneven when the container start fails, so no later release path retries. Two small fixes:awaitthe cancelled task with suppress; only clear the flag on successful start.7. GPU topology is Trogdor's, hardcoded
SEAT_GPUS = {"image": {0,1,2,3}, "animate": {0,2,3}, "audio": {1}}, the seat definitions,BRAIN_CPUSETdefault, and the brain roster all encode 4× RTX 5000. A stranger with one 24GB card can't run a drain without editing source. Full generalization (hardware profiles) is a real project → propose a child ticket; the P1-sized slice now is: liftSEAT_GPUS/seat defs into env-overridable config and writedocs/self-hosting.mdstating the actual hardware assumptions (GPU count/VRAM,/mnt/modelslayout, Forgejo+Portainer, what to edit for other rigs).P2 — Medium (pick which to take)
a. Conductor-era truth pass (docs/comments only, zero behavior). Stale references to retired machinery:
assetq.pydocstring (module CLI described as "the conductor talks to it", "exec'd inside the aegra container"),comfy_item.py/audio_item.py("the conductor's contract", "audio.sh owns ports"),critics.pyCLI docstring,assets.py:244referencing deletedscripts/asset-profiles/,comfyui/workflows/README.md(documents workflows that now live inserver/trog_lib/workflows/, references the deleted profile driver),audio-server/server.pyheader ("GPU3 / NUMA node 1", "the gateway's detect_speech tool" — no gateway exists),mock_seat.pydocstring (tests/fixtures/mock-clip.mp4→ actuallytrog_lib/fixtures/),phasewalk.pycurl examples usingtrogdor, README test-tier table (quick suite now includes the playtest tier the code runs).b.
.env.examplerefresh. Stale:BRAIN_MODEL_DIR/BRAIN_GGUF/BRAIN_CTX/BRAIN_KV/BRAIN_THREADS(dead since llama-swap — roster lives inbrain/llama-swap.yaml). Missing:BRAIN_MODEL,FILES_URL,FORGEJO_USER,ORCH_SEAT_MODE,WEBSEARCH_MCP_URL,PLAYTEST_MAX_SECONDS, and the CLI-sideTROG_URL/TROG_FILES_URL/TROG_AEGRA_URL.c. Dead
__main__CLIs decision.assetq._cli,critics._cli,comfy_item.main,audio_item.mainwere the conductor's exec contract; nothing invokes them now (grep-verified). Keepreview/playtestCLIs (useful by hand), delete or explicitly bless the rest.d. CI doesn't cover the studio. Add a job:
npm ci && npm run typecheck && npm run build(fast, no GPU). Today atscbreak ships silently.e. Compose consistency.
analyzerpinstrogdor-audio:latestwhile every other image uses${TAG:-latest}— a tagged deploy still floats the analyzer.f. Constant dedupe. SFX suffix exists twice with drifted wording (
orchestrator.SFX_SUFFIXvsassets.SFX_SUFFIX); default brain name exists 3× (compose env, python defaults,studio FeedPane DEFAULT_BRAIN);KIND_TO_PROFILE(orchestrator) overlaps_PROFILE_BY_KIND(assets).g.
assets_phaseignores the brain selector. Every phase/gate node resolves_active_llm(config);assets_phasetakes no config and always uses the module default — a run pinned to a different roster brain silently writes its asset spec with the default one.h. AI-tooling adoption.
.gitignorecurrently ignores it — for a project built by agents, the agent onboarding doc belongs in the repo (also makes it available to CI/cloud agents). Optionally addAGENTS.mdas a pointer for non-Claude tools.graphify-out/(or regenerate on demand) so architecture queries hit the knowledge graph instead of cold greps; re-run per milestone./code-reviewin the local loop before push.P3 — Low (grab-bag; cheap, low risk)
submit_oneoffref race:count(*)+1in a transaction without a lock — concurrent submits can mint duplicate daily refs (cosmetic; multiplayer-studio relevant later).assetq/ledger; the 1s SSE polls make it connection churn. Fine single-host; a tiny pool is the eventual fix.playtest/server.py:293Image.getdatadeprecation (removal: Pillow 14) — two call sites.cli _watch_pollloops forever if the orchestrator dies permanently mid-watch.orchestrator.JobRequest.kinddescription omitsvocal(the 422 hint too).audio-server _resolve_asr_provider(provider, mode)—modeparam unused./tts,/vad,/transcribeare unused by trog (vendored surface); document as extras or prune from the image later.pixel_post._cleanup_orphansis a per-pixel Python loop — fine at 96px, would hurt on large sheets; vectorize only if ever needed.Proposed plan
docs/self-hosting.md).Everything lands as small reviewable commits per item,
trog testgreen between each.#26 implementation — done, CI green
Thirteen commits on main (
f4b59b7..cdf6940). CI is green on HEAD — both jobs (pytest + the new studio job) — for the first time in 8+ runs.What landed
P0
fix(ci):langchain-deepseekadded to requirements-dev — CI had failed at collection since the ChatDeepSeek switch; local venvs masked it.chore: Apache-2.0 LICENSE (README updated).feat:make redeployrefuses when CI is red for HEAD (scripts/check-ci.sh, third guard beside dirty-tree/unpushed;FORCE=1overrides). Tested against the then-red HEAD — refused correctly.P1
FORGEJO_URLfail-fast, seat images required via env, everytrogdor:*fallback now localhost (code, CLI, vite proxies, docs)..env.example's "nothing hardcoded" claim is true now.FORGEJO_URL+token viatrog_lib.config;TROG_FORGEJO_URL/TROG_FORGEJO_AUTH/FORGEJO_USERdeleted from compose;commit_file/commit_binarydeduped./vocal; cycle spec gains ananthemvocal sentinel (Expected: fail) so the mock tier exercises the route.restore_brainretries instead of stranding the brain on a failed start.SEAT_GPUS_IMAGE/_ANIMATE/_AUDIO; the parallelism matrix derives from the same values; compose passes them through. docs/self-hosting.md states the portability contract. Full hardware profiles → #27 (filed).P2 (all four bundles)
.env.examplerewritten (dead pre-llama-swap brain vars out, real knobs in).${TAG}.SFX_SUFFIX; studio brain selector defaults to the resident model from the live roster instead of a hardcoded name (browser-verified against the running stack —/v1/modelsis alphabetical, gemma would have outranked the preloaded qwen);assets_phasehonorsconfigurable.model.graphify-out/: 1050 nodes / 1767 edges / 58 labeled communities —graphify query "<question>"answers architecture questions from the graph). Graph health notes: 292 dangling-endpoint edges (AST refs to externals — normal), 27 multi-relation pairs collapsed by the undirected build.P3 (trivial picks)
getdata()deprecation gone from the playtest runner;JobRequest.kindmentions vocal; unused ASRmodeparam dropped.CI post-mortem (two more Linux-only defects found while turning it green)
tests/conftest.pywas missing —trog_libimports rode on collection-order side effects (green on macOS, ImportError on the runner).opencv-pythonin beside the headless pin; its cv2 needslibGL.so.1, absent in the bare job image — the pytest job now installslibgl1. The server image never sees this (ffmpeg supplies libGL). Verified in a barepython:3.14container before pushing.Deploy state
FORGEJO_URL+COMFY_IMAGEadded (settings-only, no redeploy fired; all containers stayed healthy). Compose fails fast without them since this ticket.~/.zshrcexports set (TROG_URL/TROG_FILES_URL/TROG_AEGRA_URL→ trogdor);trog statusverified green.make deployships the new server/studio images through the normal guarded path.Deferred (documented, not done)
README review + update plan (#26, first-class OSS lens)
Reviewed against the two canonical references — Art of README (cognitive funneling: broadest value first, depth later; "complete when someone can use it without reading the code") and the standard-readme spec (required: title, short description, ToC over 100 lines, install, usage, contributing, license-last) — plus the patterns of large OSS projects.
What's already excellent (keep, don't dilute)
Gaps (ranked)
SEAT_MODE=mockruns the entire pipeline with zero GPUs — compose up, open the studio, feed a line to phasewalk, runtrog test asset --mock. That's a 10-minute GPU-less demo nobody can currently discover.Apache-2.0) + copyright holder per spec.Proposed target structure
Work items (in order)
Item 5 is the one with teeth — if FLUX.2-dev's license genuinely restricts commercial output, the README must say what that means for games people generate, and the principles line softens to "code 100% Apache-2.0; default weights have their own licenses, swappable per seat."
Sources: Art of README, standard-readme spec, README best-practice guides.
Post-deploy verification — all green
Deploy of
cdf6940confirmed: all 9 containers healthy on current images, stack env live in-container.trog test ui), including a live send→stream→reply mid-drainNew in
fa952e4:studio/e2ePlaywright suite (user-level, real browser, real stack;trog test ui --headedto watch) — includes the brain-selector-defaults-to-resident regression test.README review + update plan posted above; awaiting go-ahead on implementation.
README overhaul landed (
bffb255)All 8 plan items done, plus one bug the plan flushed out.
ship, studio e2e smoke+map passed 4/4 against it.studio/e2e/readme-shots.mjs(reproducible — kicks a real phasewalk run, shoots studio + fixture review page).Note for next deploy: the nginx fix is in the studio image — ships with the next
make deploy.Closing — audit executed end to end, follow-on work landed or ticketed
Everything this ticket asked for shipped and was verified live: the prioritized audit (comments above), the approved P0/P1/P2 implementation (Apache-2.0, self-hostability pass, one Forgejo contract, mock /vocal, shutdown fixes, docs truth pass, CI studio job, dedupe, CLAUDE.md/graphify adoption), the README overhaul with a verified GPU-less quick start, and the post-deploy verification + stress campaign.
The ticket also seeded work that outgrew it, all landed separately:
trog update --dependenciesguided bump pipeline — used in anger to bump the llama.cpp engine (kept; drift report fully green)Remaining low-priority hygiene items are parked in #29; studio pane polish in #28. Nothing else outstanding.