From f8e5548b465cb2f6d1ed35b2c2be25d0cd2c3c07 Mon Sep 17 00:00:00 2001 From: Behzad Date: Sun, 26 Jul 2026 23:18:25 +0200 Subject: [PATCH] Drop internal plan references from code comments The pack cited internal planning-doc items (plan P3-7, decision D1, plan risk 9.2) that aren't public, leaving outside contributors with pointers they can't follow. Each comment already states its reason; only the dangling citation is removed. Co-Authored-By: Claude Sonnet 5 --- scripts/build_workflows.py | 31 +++++++++++++++---------------- server_routes.py | 6 +++--- styleref_api.py | 6 +++--- styleref_auth.py | 6 +++--- styleref_nodes/apply.py | 6 +++--- styleref_nodes/load.py | 15 +++++++-------- styleref_nodes/login.py | 2 +- styleref_style.py | 8 ++++---- tests/test_api.py | 8 ++++---- tests/test_auth.py | 4 ++-- tests/test_nodes.py | 28 ++++++++++++++-------------- tests/test_style.py | 4 ++-- tests/test_workflows.py | 24 ++++++++++++------------ web/styleref.js | 18 +++++++++--------- 14 files changed, 82 insertions(+), 84 deletions(-) diff --git a/scripts/build_workflows.py b/scripts/build_workflows.py index a7d4fb7..46f177e 100644 --- a/scripts/build_workflows.py +++ b/scripts/build_workflows.py @@ -7,12 +7,12 @@ link ids, and slot indices across all of them — the kind of bookkeeping that i silently wrong until someone drags the file onto a canvas. This builds them from a description instead, so the ids are correct by construction. -Layout policy (plan P2-1): node positions are never guessed. Every node's height +Layout policy: node positions are never guessed. Every node's height is estimated from its widget count, and nodes stack per column with a fixed vertical gap — so no template can ship with overlapping nodes at default sizes. A test asserts that invariant on the committed files. -Instruction policy (plan P2-2): user-facing instructions live in visible core +Instruction policy: user-facing instructions live in visible core `Note` nodes on the canvas. `extra.styleref.notes` carries only a one-line provenance string — ComfyUI never renders it, so it must not carry anything a user needs to read. @@ -35,7 +35,7 @@ _PACK_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) if _PACK_ROOT not in sys.path: sys.path.insert(0, _PACK_ROOT) -# Single-sourced from the node itself (D4: the Facets output list is data-driven +# Single-sourced from the node itself (the Facets output list is data-driven # and long — duplicating it here would guarantee drift). from styleref_nodes.facets import StyleRefFacets # noqa: E402 @@ -89,7 +89,7 @@ INPUTS = { "PreviewAny": [("source", "*")], } -# ── layout constants (plan P2-1) ───────────────────────────────────────────── +# ── layout constants ───────────────────────────────────────────────────────── NODE_WIDTH = 320 HEADER_H = 60 # title bar @@ -106,10 +106,10 @@ MULTILINE_WIDGETS = { "Note": {0}, } -# Node titles longer than this truncate in both frontends (plan P2-2). +# Node titles longer than this truncate in both frontends. MAX_TITLE = 28 -# Frontend model-download metadata (plan P2-7): a missing checkpoint becomes a +# Frontend model-download metadata: a missing checkpoint becomes a # guided download instead of a red error. # Placeholder ref for the "your own style" templates. Refs are opaque ids now # (no name lookup), so the templates ship an obvious placeholder the user swaps @@ -159,7 +159,7 @@ MODELS_ZIMAGE = [MODEL_ZIMAGE_UNET, MODEL_ZIMAGE_CLIP, MODEL_ZIMAGE_VAE] def node_height(node_type: str, widgets: list[Any]) -> int: """ - Estimated on-canvas height (plan P2-1): header + one row per input/output + Estimated on-canvas height: header + one row per input/output slot + one row per widget. The slot term matters for wide-output nodes — Facets alone has dozens of outputs. """ @@ -231,7 +231,7 @@ class Graph: return self._node_id def note(self, col: int, text: str, title: str = "Read me") -> int: - """A visible core Note node — the instruction channel (plan P2-2).""" + """A visible core Note node — the instruction channel.""" # Height scales with the text so long notes don't clip at default size. h = HEADER_H + 30 + 18 * (text.count("\n") + len(text) // 55) return self.place("Note", col, [text], title=title, height=h) @@ -280,7 +280,7 @@ def apply_widgets(subject: str, target: str) -> list[Any]: def sampler_widgets(cfg: float) -> list[Any]: - # Seeds randomize (plan P2-4): a fixed seed makes the second queue a silent + # Seeds randomize: a fixed seed makes the second queue a silent # cache no-op — deadly in a demo. return [0, "randomize", 25, cfg, "euler", "normal", 1.0] @@ -332,10 +332,9 @@ def _facet_board(graph: Graph, load: int, col: int) -> int: def _preview(graph: Graph, apply_node: int, col: int, suffix: str = "") -> None: """ - Compiled prompts made visible (plan P2-3, extended to every template by - owner decision): Preview Any on Apply's positive and negative kills the - "empty text box on the encoder looks broken" perception and teaches what - StyleRef actually produces. + Compiled prompts made visible, in every template: Preview Any on Apply's + positive and negative kills the "empty text box on the encoder looks + broken" perception and teaches what StyleRef actually produces. """ pos = graph.place("PreviewAny", col, [], title=f"Compiled positive{suffix}") neg = graph.place("PreviewAny", col, [], title=f"Compiled negative{suffix}") @@ -442,7 +441,7 @@ def workflow_zimage_01_quickstart() -> dict[str, Any]: def workflow_zimage_02_consistency() -> dict[str, Any]: - """One style across three subjects on Z-Image (plan P2-5).""" + """One style across three subjects on Z-Image.""" g = Graph() g.note( 0, @@ -567,7 +566,7 @@ def workflow_01_quickstart() -> dict[str, Any]: def workflow_02_consistency() -> dict[str, Any]: """ - One style across three subjects, side by side (plan P2-5). + One style across three subjects, side by side. Consistency is the claim this demonstrates, and it is scoped precisely: the same style applied within this one model produces a coherent set. It is not @@ -603,7 +602,7 @@ def workflow_02_consistency() -> dict[str, Any]: def workflow_03_your_own_style() -> dict[str, Any]: - """Your own style, made on the web, loaded here (plan P0-6's template 03).""" + """Your own style, made on the web, loaded here (template 03).""" g = Graph() g.note( 0, diff --git a/server_routes.py b/server_routes.py index 3cc1d8b..36c7570 100644 --- a/server_routes.py +++ b/server_routes.py @@ -9,7 +9,7 @@ Everything here is optional. If ComfyUI's server module isn't importable — a headless test run, an API-only embed, a future frontend rewrite — importing this fails, `__init__` catches it, and the nodes carry on with the plain text field. The JS side probes /styleref/search once at startup and hides its button when -these routes are absent (plan P3-7), so both halves degrade together. +these routes are absent, so both halves degrade together. """ from __future__ import annotations @@ -27,7 +27,7 @@ from styleref_nodes.load import bump_refresh def _card(entry: dict) -> dict: - """The picker-row shape. heroImage feeds the row thumbnail (plan P3-1).""" + """The picker-row shape. heroImage feeds the row thumbnail.""" return { "slug": entry.get("slug"), "name": entry.get("name"), @@ -143,7 +143,7 @@ async def styleref_my_styles(request: web.Request) -> web.Response: } for s in (payload.get("styles") or []) ], - # Passed back as ?cursor= for the dialog's Next button (plan P3-6). + # Passed back as ?cursor= for the dialog's Next button. "nextCursor": payload.get("nextCursor"), } ) diff --git a/styleref_api.py b/styleref_api.py index 57b7b77..870b625 100644 --- a/styleref_api.py +++ b/styleref_api.py @@ -418,6 +418,6 @@ def list_saved_styles( # Note: this client deliberately has no extraction endpoints. Extraction is a -# web-app experience (preview, per-block editing, history, free re-apply) — -# plugin decision D1. The REST /extractions tier itself remains available for -# CLI and agent surfaces. +# web-app experience (preview, per-block editing, history, free re-apply), so +# the pack loads styles rather than making them. The REST /extractions tier +# itself remains available for CLI and agent surfaces. diff --git a/styleref_auth.py b/styleref_auth.py index 9f3ee50..6f41246 100644 --- a/styleref_auth.py +++ b/styleref_auth.py @@ -143,7 +143,7 @@ def is_headless(env: dict[str, str] | None = None) -> bool: """ True when we almost certainly cannot open a browser on this machine. - Plan risk 9.2: a large share of ComfyUI installs are remote GPU boxes where + a large share of ComfyUI installs are remote GPU boxes where the loopback flow cannot work *at all* — localhost is the wrong machine. Detecting that up front lets the Login node print the STYLEREF_TOKEN instructions instead of hanging on a callback that will never arrive. @@ -231,7 +231,7 @@ class _CallbackHandler(BaseHTTPRequestHandler): code = (params.get("code") or [None])[0] state = (params.get("state") or [None])[0] - # Validate BEFORE choosing the page (plan P0-4): the browser must never + # Validate BEFORE choosing the page: the browser must never # claim success while the node reports a failed sign-in. if not code or state != type(self).expected_state: # A state mismatch is the CSRF case: discard the code entirely. @@ -387,7 +387,7 @@ def bearer_token() -> str | None: The token to send, or None for anonymous. STYLEREF_TOKEN wins over stored credentials — it is the documented path for - headless installs (plan risk 9.2), so it must not be second-guessed. + headless installs, so it must not be second-guessed. """ env_token = (os.environ.get("STYLEREF_TOKEN") or "").strip() if env_token: diff --git a/styleref_nodes/apply.py b/styleref_nodes/apply.py index 1404e66..89b4893 100644 --- a/styleref_nodes/apply.py +++ b/styleref_nodes/apply.py @@ -22,7 +22,7 @@ CATEGORY = "StyleRef" # Node-facing target → the server's `format` parameter. # # The list is EXACTLY the web app's copy-box format list (owner decision -# 2026-07-22, superseding D2's midjourney removal), in the same order: +# 2026-07-22, superseding the earlier midjourney removal), in the same order: # AI Tools, STYLE.md, Flux, Midjourney, Diffusion, JSON. The style means the # same thing here as on styleref.io, format for format. # @@ -158,7 +158,7 @@ def estimate_tokens(text: str) -> int: def preview_text(positive: str, target: str, compact: bool) -> str: - """The node-body summary (P0-2/P1-8): prompt preview + token estimate.""" + """The node-body summary: prompt preview + token estimate.""" shown = positive if len(positive) <= PREVIEW_CHARS else positive[:PREVIEW_CHARS] + "…" tokens = estimate_tokens(positive) line = f"≈{tokens} tokens ({target})" @@ -279,7 +279,7 @@ class StyleRefApply: positive = compose_prompt(subject, style_text, subject_first) negative = compose_negative(style, extra_negative) - # ui.text (P0-2): show what was actually composed, in the node body — + # ui.text: show what was actually composed, in the node body — # otherwise the first visible evidence of the prompt is the final image. return { "ui": {"text": [preview_text(positive, target, compact)]}, diff --git a/styleref_nodes/load.py b/styleref_nodes/load.py index 31b309d..8158a9a 100644 --- a/styleref_nodes/load.py +++ b/styleref_nodes/load.py @@ -1,14 +1,14 @@ """ StyleRef Load — fetch a style into the graph. -Widget policy (plan risk 9.1): every widget here is vanilla — a text field, a +Widget policy: every widget here is vanilla — a text field, a combo, a toggle. The live search dialog is a *progressive enhancement* shipped in web/styleref.js. When that JS fails to load, or a ComfyUI frontend release breaks it, this node still works exactly as written: type or paste a ref. The search path is additionally available headlessly via the `search` widget, whose results land on the `search_results` output and in the node body. -Guidance policy (plan P1-2): Nodes 2.0 does not render STRING placeholders, so +Guidance policy: Nodes 2.0 does not render STRING placeholders, so every input's contract must survive on tooltip + default alone. Placeholders are kept (harmless where supported) but never as the only channel. @@ -64,7 +64,7 @@ SEARCH_CATEGORIES = [ # ComfyUI re-runs a node whenever anything upstream changes, and re-fetching an # unchanged style on every queue would burn the anonymous rate limit for no # benefit. When the node does re-execute, a stored ETag turns the re-fetch into -# a cheap conditional GET (P5-8): the server answers 304 and the cached style — +# a cheap conditional GET: the server answers 304 and the cached style — # including its compiled-prompt cache — is kept. _CACHE: dict[str, dict[str, Any]] = {} @@ -110,7 +110,7 @@ def fetch_style(ref: str, use_cache: bool = True) -> dict[str, Any]: # With use_cache off (or after a refresh) we still send the stored ETag: # "re-download every run" becomes "revalidate every run" — a bodyless 304 - # when nothing changed, the full spec when it did (P5-8). + # when nothing changed, the full spec when it did. etag = cached.get("etag") if cached else None spec, canonical_url, new_etag = api.get_style_spec(ref, etag=etag) if spec is None and cached is not None: @@ -265,8 +265,7 @@ class StyleRefLoad: summary = f"Loaded {summary_line(style)}" # The search card carries no palette data, so the node body is where the - # palette shows up (plan P3-2's fallback) — as text, the only channel - # ui.text has. + # palette shows up — as text, the only channel ui.text has. hexes = palette_hexes(style)[:5] if hexes: summary += f"\nPalette: {' '.join(hexes)}" @@ -274,7 +273,7 @@ class StyleRefLoad: if save_to_library: summary += f"\n{self._save_to_library(style)}" elif style.get("url"): - # Passive contribution nudge (plan P6-3): the style's public page is + # Passive contribution nudge: the style's public page is # where renders made with it can be shared. summary += f"\nMade something good with it? Share it on {style['url']}" @@ -302,7 +301,7 @@ class StyleRefLoad: @staticmethod def _result(style: dict[str, Any], results: str, body: str): - # ui.text renders in the node body (P0-2): the load confirmation and any + # ui.text renders in the node body: the load confirmation and any # search results are visible without wiring the STRING output anywhere. return {"ui": {"text": [body]}, "result": (style, results)} diff --git a/styleref_nodes/login.py b/styleref_nodes/login.py index 9026eed..e8c8386 100644 --- a/styleref_nodes/login.py +++ b/styleref_nodes/login.py @@ -14,7 +14,7 @@ without a frontend goes through `npx styleref login` (the CLI shares this pack's credentials file) or STYLEREF_TOKEN; sign-out without a frontend is deleting the credentials file, which the status text names. -Remote installs (plan risk 9.2): the loopback flow cannot work when ComfyUI +Remote installs: the loopback flow cannot work when ComfyUI runs on a rented GPU box — there is no browser to open and `localhost` is the wrong machine. The sign-in path detects that case up front and returns the STYLEREF_TOKEN instructions instead of hanging on a callback that will never diff --git a/styleref_style.py b/styleref_style.py index 82e1c8b..e27a75d 100644 --- a/styleref_style.py +++ b/styleref_style.py @@ -32,10 +32,10 @@ from typing import Any PALETTE = ("colors", "color_palette") MOOD = ("mood_personality", "mood_personality") -# Every guardrail field that belongs in an image model's NEGATIVE channel -# (plan P1-9 + the 2026-07-23 negation pass), in render order. avoided_words is -# deliberately absent: it constrains text output (buzzwords, brand voice) and -# stays in the text formats — the same split as voice_language. +# Every guardrail field that belongs in an image model's NEGATIVE channel, in +# render order. avoided_words is deliberately absent: it constrains text output +# (buzzwords, brand voice) and stays in the text formats — the same split as +# voice_language. GUARDRAIL_ARTIFACTS = ("guardrails", "common_artifacts_to_avoid") GUARDRAILS = ("guardrails", "avoided_visuals") GUARDRAIL_COLORS = ("guardrails", "avoided_colors") diff --git a/tests/test_api.py b/tests/test_api.py index 5677a79..6e9aad7 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -160,7 +160,7 @@ def test_401_flags_needs_login(monkeypatch): def test_401_with_env_token_hints_at_expiry(monkeypatch): """ - Plan P0-5: the env token never refreshes itself, so a headless install's + The env token never refreshes itself, so a headless install's 401 hours later needs to say the likely cause — an expired STYLEREF_TOKEN. """ monkeypatch.setenv("STYLEREF_TOKEN", "stale-token") @@ -213,7 +213,7 @@ def test_get_style_spec_reads_the_canonical_url_header(monkeypatch): assert url == "https://styleref.io/share/real-slug" -# ── extraction stays out of this client (plan P0-6 / decision D1) ──────────── +# ── extraction stays out of this client ────────────────────────────────────── def test_client_has_no_extraction_endpoints(): @@ -306,7 +306,7 @@ def test_client_tag_header_is_sent(monkeypatch): assert captured.get("X-styleref-client") == "comfyui" -# ── save (P5-6) ────────────────────────────────────────────────────────────── +# ── save ───────────────────────────────────────────────────────────────────── def test_save_style_posts_to_the_save_endpoint(monkeypatch): @@ -322,7 +322,7 @@ def test_save_style_posts_to_the_save_endpoint(monkeypatch): assert seen["url"].endswith("/styles/%40ada%2FWarm%20Editorial/save") -# ── conditional GET (P5-8) ─────────────────────────────────────────────────── +# ── conditional GET ────────────────────────────────────────────────────────── def test_304_is_success_not_error(monkeypatch): diff --git a/tests/test_auth.py b/tests/test_auth.py index d0f0039..e9757fe 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -138,7 +138,7 @@ def test_dead_session_degrades_to_anonymous(tmp_path, monkeypatch): assert auth.bearer_token() is None -# ── headless detection (plan risk 9.2) ─────────────────────────────────────── +# ── headless detection ─────────────────────────────────────────────────────── def test_ssh_session_is_headless(): @@ -174,7 +174,7 @@ def test_headless_help_leads_with_the_credentials_file_then_the_env_var(): assert help_text.index("credentials.json") < help_text.index("STYLEREF_TOKEN") -# ── OAuth callback page (plan P0-4) ────────────────────────────────────────── +# ── OAuth callback page ────────────────────────────────────────────────────── class _FakeWFile: diff --git a/tests/test_nodes.py b/tests/test_nodes.py index 96b3411..bc556d2 100644 --- a/tests/test_nodes.py +++ b/tests/test_nodes.py @@ -36,12 +36,12 @@ def clear_cache(): load_node._GENERATION.clear() -# ── pack registration (plan P0-6) ──────────────────────────────────────────── +# ── pack registration ──────────────────────────────────────────────────────── def test_pack_registers_exactly_the_five_nodes(): """ - Extraction moved to the web app (decision D1): the pack registers + Extraction moved to the web app: the pack registers Load/Apply/Facets/ReferenceImages/Login and nothing else — an Extract node here means the removal regressed. """ @@ -65,7 +65,7 @@ def test_pack_registers_exactly_the_five_nodes(): def test_targets_are_exactly_the_web_apps_copy_list_in_order(): """ - Owner decision 2026-07-22 (supersedes D2): the target list mirrors the web + Owner decision 2026-07-22: the target list mirrors the web app's copy-box format list exactly — same entries, same order — so the style means the same thing here as on styleref.io. Source of truth: PROMPT_FORMAT_OPTIONS in src/components/ui/PromptFormatDropdown.tsx. @@ -246,7 +246,7 @@ def test_apply_rejects_an_unloaded_style(): node.apply(make_style(ref="", name="(none)"), "subject", "flux") -# ── Apply: node-body feedback (plan P0-2 / P1-8) ───────────────────────────── +# ── Apply: node-body feedback ──────────────────────────────────────────────── def test_apply_returns_ui_text_and_unchanged_result_tuple(monkeypatch): @@ -370,7 +370,7 @@ def test_private_refs_are_tagged_as_library(monkeypatch): def test_ungenerated_style_error_reaches_the_user_verbatim(monkeypatch): """ - Plan P0-7: when the server refuses a never-generated own-style ref (409), + When the server refuses a never-generated own-style ref (409), its message — which tells the user to Generate on styleref.io — must pass through unreworded. """ @@ -390,7 +390,7 @@ def test_ungenerated_style_error_reaches_the_user_verbatim(monkeypatch): def test_load_returns_ui_text_and_result_tuple(monkeypatch): - """P0-2: the load confirmation renders in the node body.""" + """The load confirmation renders in the node body.""" monkeypatch.setattr( api, "get_style_spec", lambda ref, etag=None: ({"name": "Warm", "sections": {}}, None, None) ) @@ -422,7 +422,7 @@ def test_load_never_fetches_style_text(monkeypatch): def test_load_is_an_output_node(): - """A search-only Load must be queueable alone and still display (P0-2).""" + """A search-only Load must be queueable alone and still display.""" assert load_node.StyleRefLoad.OUTPUT_NODE is True @@ -456,7 +456,7 @@ def test_search_failure_does_not_sink_the_run(monkeypatch): def test_search_category_is_forwarded(monkeypatch): - """The vanilla category combo (P3-4) must reach the API; `any` must not.""" + """The vanilla category combo must reach the API; `any` must not.""" seen = {} def fake_search(query, category=None, sort=None, limit=12): @@ -474,7 +474,7 @@ def test_search_category_is_forwarded(monkeypatch): assert seen["category"] is None -# ── IS_CHANGED contracts (plan P0-1's regression class) ────────────────────── +# ── IS_CHANGED contracts ───────────────────────────────────────────────────── def test_load_is_changed_is_stable_when_cached(): @@ -497,13 +497,13 @@ def test_login_is_always_dirty(): def test_apply_has_no_is_changed_override(): """ Apply's dirtiness must come from its inputs alone. An IS_CHANGED override - returning NaN here is the credit-burn/api-hammer class of bug (plan P0-1) — + returning NaN here is the credit-burn/api-hammer class of bug — the node would re-run on every queue. """ assert "IS_CHANGED" not in vars(apply_node.StyleRefApply) -# ── Apply: sections filter (P5-3) ──────────────────────────────────────────── +# ── Apply: sections filter ─────────────────────────────────────────────────── def test_sections_filter_reaches_the_api_and_the_cache_key(monkeypatch): @@ -527,7 +527,7 @@ def test_sections_filter_reaches_the_api_and_the_cache_key(monkeypatch): assert calls[-1] is None -# ── Facets: full schema coverage (P5-2 / D4) ───────────────────────────────── +# ── Facets: full schema coverage ───────────────────────────────────────────── def test_facets_outputs_are_exactly_the_schema_sections_plus_custom_items(): @@ -636,7 +636,7 @@ def test_reference_images_errors_clearly_without_images(): ri.StyleRefReferenceImages().fetch(make_style(ref="x", name="Bare")) -# ── Load: save_to_library (P5-6) ───────────────────────────────────────────── +# ── Load: save_to_library ──────────────────────────────────────────────────── def test_save_to_library_saves_once_per_session(monkeypatch): @@ -690,7 +690,7 @@ def test_own_styles_are_not_re_saved(monkeypatch): assert "Already your own style" in out["ui"]["text"][0] -# ── Load: ETag revalidation (P5-8) ─────────────────────────────────────────── +# ── Load: ETag revalidation ────────────────────────────────────────────────── def test_cache_off_revalidates_with_the_stored_etag(monkeypatch): diff --git a/tests/test_style.py b/tests/test_style.py index 78a7beb..39e62d3 100644 --- a/tests/test_style.py +++ b/tests/test_style.py @@ -128,7 +128,7 @@ def test_negatives_are_normalized_comma_terms(style): def test_negatives_cover_artifacts_and_avoided_colors(): """ - Plan P1-9: guardrails carry more than avoided_visuals — artifacts to avoid + Guardrails carry more than avoided_visuals — artifacts to avoid and avoided colors are user-authored constraints and belong in the negative. """ style = make_style( @@ -241,7 +241,7 @@ def test_is_style_rejects_arbitrary_dicts(): assert is_style(make_style(ref="x", name="ok")) is True -# ── dimensions (P5-2: width/height from the style) ─────────────────────────── +# ── dimensions (width/height from the style) ───────────────────────────────── def _fmt_style(aspect: str | None = None, resolution: str | None = None): diff --git a/tests/test_workflows.py b/tests/test_workflows.py index 7fe8aa4..d5c9d87 100644 --- a/tests/test_workflows.py +++ b/tests/test_workflows.py @@ -4,8 +4,8 @@ Workflow template tests. A broken template is only discovered when a user drags it onto a canvas and it fails silently, so the structural invariants are checked here instead: every link points at a node that exists, at a slot that exists, carrying a type both -ends agree on — and the layout invariants of plan P2-1/P2-2: no overlapping -nodes, instructions in visible Note nodes, titles short enough to render. +ends agree on — plus the layout invariants: no overlapping nodes, instructions +in visible Note nodes, titles short enough to render. """ from __future__ import annotations @@ -36,7 +36,7 @@ def _load(path: str) -> dict: def _note_text(graph: dict) -> str: - """All visible Note-node text — the instruction channel (plan P2-2).""" + """All visible Note-node text — the instruction channel.""" return "\n".join( str(n["widgets_values"][0]) for n in graph["nodes"] @@ -50,7 +50,7 @@ def test_every_declared_workflow_is_committed(): def test_extraction_template_is_gone(): - """Plan P0-6: extraction lives on the web; template 03 tells that story.""" + """Extraction lives on the web; template 03 tells that story.""" assert "03-extract-and-reuse.json" not in {os.path.basename(p) for p in FILES} assert "03-your-own-style.json" in {os.path.basename(p) for p in FILES} @@ -78,7 +78,7 @@ def test_committed_file_matches_the_generator(path): @pytest.mark.parametrize("path", FILES, ids=[_relpath(p) for p in FILES]) def test_only_the_shipped_styleref_nodes_appear(path): - """Plan P0-6: a template referencing a removed node fails on the canvas.""" + """A template referencing a removed node fails on the canvas.""" allowed = { "StyleRefLoad", "StyleRefApply", @@ -128,7 +128,7 @@ def test_link_ids_are_unique_and_registered_on_both_ends(path): @pytest.mark.parametrize("path", FILES, ids=[_relpath(p) for p in FILES]) def test_no_nodes_overlap_at_default_sizes(path): - """Plan P2-1: overlapping nodes read as a broken template — layout is math, + """Overlapping nodes read as a broken template — layout is math, not guesses, so this must hold for every template.""" nodes = _load(path)["nodes"] boxes = [(n["id"], *n["pos"], *n["size"]) for n in nodes] @@ -142,7 +142,7 @@ def test_no_nodes_overlap_at_default_sizes(path): def test_every_workflow_explains_itself_in_a_visible_note(path): """ Templates are documentation — and ComfyUI never renders extra.styleref, so - the instructions must live in a visible core Note node (plan P2-2). + the instructions must live in a visible core Note node. """ graph = _load(path) assert len(_note_text(graph)) > 60, "no substantial Note node found" @@ -168,14 +168,14 @@ def test_auth_requirements_are_stated(path): needs_auth = any(n["type"] == "StyleRefLogin" for n in graph["nodes"]) if needs_auth: assert "sign-in" in notes or "sign in" in notes - # The sign-in path ships in the template (plan P2-6), not just in prose. + # The sign-in path ships in the template, not just in prose. assert any(n["type"] == "StyleRefLogin" for n in graph["nodes"]) @pytest.mark.parametrize("path", FILES, ids=[_relpath(p) for p in FILES]) def test_seeds_randomize(path): """ - Plan P2-4: a fixed seed makes the second queue a silent cache no-op — + A fixed seed makes the second queue a silent cache no-op — deadly in a demo. """ for node in _load(path)["nodes"]: @@ -190,7 +190,7 @@ _MODEL_DIRECTORIES = {"checkpoints", "diffusion_models", "text_encoders", "vae"} @pytest.mark.parametrize("path", FILES, ids=[_relpath(p) for p in FILES]) def test_model_loaders_carry_download_metadata(path): - """Plan P2-7: a missing model should be a guided download, not a red error — + """A missing model should be a guided download, not a red error — for every loader type (checkpoints and the Z-Image UNET/CLIP/VAE stack).""" graph = _load(path) loader_files = { @@ -288,7 +288,7 @@ def test_zimage_templates_have_no_negative_encoder(name): def test_consistency_template_shows_one_style_many_subjects(): - """Plan P2-5: three Apply nodes with three different subjects, one Load.""" + """Three Apply nodes with three different subjects, one Load.""" graph = _load(os.path.join(WORKFLOW_DIR, "02-consistency-grid.json")) applies = [n for n in graph["nodes"] if n["type"] == "StyleRefApply"] loads = [n for n in graph["nodes"] if n["type"] == "StyleRefLoad"] @@ -299,7 +299,7 @@ def test_consistency_template_shows_one_style_many_subjects(): def test_prompt_previews_exist_where_promised(): - """Plan P2-3: templates 01 and 04 make the compiled prompts visible.""" + """Templates 01 and 04 make the compiled prompts visible.""" for name in ("01-quickstart.json", "04-facets.json"): graph = _load(os.path.join(WORKFLOW_DIR, name)) assert any(n["type"] == "PreviewAny" for n in graph["nodes"]), name diff --git a/web/styleref.js b/web/styleref.js index 56906dd..097968e 100644 --- a/web/styleref.js +++ b/web/styleref.js @@ -53,7 +53,7 @@ const CATEGORIES = [ // ‹ Prev / Next ›, so the dialog stays a fixed height instead of growing. const PAGE_SIZE = 8; -// Resolved by the availability probe (plan P3-7). `null` = probe still running. +// Resolved by the availability probe. `null` = probe still running. let routesAvailable = null; async function probeRoutes() { @@ -101,7 +101,7 @@ function el(tag, css, text) { } /** - * The picker dialog (plan P3-3/P3-5): owns its query, filters, and result + * The picker dialog: owns its query, filters, and result * list. Resolves with the chosen slug/ref, or null when dismissed. */ function openPicker(initialQuery) { @@ -124,7 +124,7 @@ function openPicker(initialQuery) { resolve(value); }; const onKey = (e) => { - // Esc-to-close (plan P3-5), capturing so the canvas never sees it. + // Esc-to-close, capturing so the canvas never sees it. if (e.key === "Escape") { e.stopPropagation(); close(null); @@ -213,7 +213,7 @@ function openPicker(initialQuery) { button.onmouseenter = () => (button.style.background = "#32323a"); button.onmouseleave = () => (button.style.background = "#26262a"); - // Thumbnail (plan P3-1) — a fixed box so rows align with or without one. + // Thumbnail — a fixed box so rows align with or without one. const thumb = el( "div", "width:44px;height:44px;border-radius:6px;background:#1a1a1d;flex:none;overflow:hidden;", @@ -410,7 +410,7 @@ function openPicker(initialQuery) { return; } if (gallery.error) { - // Inline message row, never alert() (plan P3-5). + // Inline message row, never alert(). out.append(message(gallery.error)); return; } @@ -593,7 +593,7 @@ async function refreshLoginStatus(node, statusWidget) { } } -/** True when Apply's `positive` output feeds a CLIPTextEncode (plan P1-3). */ +/** True when Apply's `positive` output feeds a CLIPTextEncode. */ function positiveFeedsClipEncode(node) { const graph = node.graph; const output = node.outputs?.find((o) => o.name === "positive"); @@ -619,7 +619,7 @@ app.registerExtension({ const result = onCreated?.apply(this, arguments); // Only add the search button when the backend routes exist - // (plan P3-7) — otherwise it could only 404. + // — otherwise it could only 404. if (routesAvailable !== false) { this.addWidget("button", "Search styles…", null, async () => { const refWidget = this.widgets?.find((w) => w.name === "style_ref"); @@ -635,7 +635,7 @@ app.registerExtension({ }); } - // Refresh affordance (plan P1-6): the backend drops its cached + // Refresh affordance: the backend drops its cached // copy and dirties the node, so the next queue re-downloads — // no need to toggle use_cache off and back on. if (routesAvailable !== false) { @@ -662,7 +662,7 @@ app.registerExtension({ } if (nodeData?.name === APPLY_NODE) { - // Warning badge (plan P1-3): `natural`/`style_md` are copy-out + // Warning badge: `natural`/`style_md` are copy-out // documents; wiring one into a CLIP encoder is almost certainly a // mistake. Additive drawing only — nothing else is touched. const onDrawForeground = nodeType.prototype.onDrawForeground;