diff options
| -rw-r--r-- | .gitignore | 7 | ||||
| -rw-r--r-- | .hyperstack-vm-photo-state.json | 93 | ||||
| -rw-r--r-- | .hyperstack-vm1-state.json | 90 | ||||
| -rw-r--r-- | .hyperstack-vm2-state.json | 90 | ||||
| -rw-r--r-- | photo-enhance-review.md | 678 | ||||
| -rw-r--r-- | pi/plans/gt-boolean-numeric-coercion.md | 32 | ||||
| -rw-r--r-- | pi/plans/gt-boolean-operators-both-forms.md | 33 | ||||
| -rw-r--r-- | pi/plans/gt-boolean-operators-rpn-only-example.md | 30 | ||||
| -rw-r--r-- | pi/plans/gt-boolean-operators-rpn-only.md | 31 | ||||
| -rw-r--r-- | pi/plans/gt-boolean-operators-syntax-examples.md | 52 | ||||
| -rw-r--r-- | pi/plans/gt-boolean-operators.md | 37 | ||||
| -rw-r--r-- | pi/plans/gt-plan.md | 29 | ||||
| -rw-r--r-- | pi/plans/gt-rpn-prefix-doc.md | 22 |
13 files changed, 951 insertions, 273 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2fbfa0d --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +# VM state files — ephemeral, contain VM IDs and WireGuard keys +*.state.json +*.state.json.known_hosts + +# Tooling directories +.claude/ +.serena/ diff --git a/.hyperstack-vm-photo-state.json b/.hyperstack-vm-photo-state.json deleted file mode 100644 index 8bf47b2..0000000 --- a/.hyperstack-vm-photo-state.json +++ /dev/null @@ -1,93 +0,0 @@ -{ - "vm_id": 698370, - "vm_name": "hyperstack-photo-20260324164547", - "environment_name": "snonux-ollama", - "region": "CANADA-1", - "flavor_name": "n3-L40x1", - "image_name": "Ubuntu Server 24.04 LTS R570 CUDA 12.8 with Docker", - "key_name": "earth", - "public_ip": "69.19.136.63", - "created_at": "2026-03-24T16:45:48Z", - "services": { - "vllm_enabled": false, - "ollama_enabled": false, - "comfyui_enabled": true - }, - "security_rules": [ - { - "direction": "ingress", - "ethertype": "IPv4", - "protocol": "tcp", - "port_range_min": 22, - "port_range_max": 22, - "remote_ip_prefix": "79.100.218.77/32" - }, - { - "direction": "ingress", - "ethertype": "IPv4", - "protocol": "udp", - "port_range_min": 56710, - "port_range_max": 56710, - "remote_ip_prefix": "79.100.218.77/32" - }, - { - "direction": "ingress", - "ethertype": "IPv4", - "protocol": "tcp", - "port_range_min": 8188, - "port_range_max": 8188, - "remote_ip_prefix": "192.168.3.0/24" - }, - { - "direction": "ingress", - "ethertype": "IPv4", - "protocol": "tcp", - "port_range_min": 22, - "port_range_max": 22, - "remote_ip_prefix": "79.100.218.77/32" - }, - { - "direction": "ingress", - "ethertype": "IPv4", - "protocol": "udp", - "port_range_min": 56710, - "port_range_max": 56710, - "remote_ip_prefix": "79.100.218.77/32" - }, - { - "direction": "egress", - "ethertype": "IPv4", - "protocol": "any", - "port_range_min": 1, - "port_range_max": 65535, - "remote_ip_prefix": "0.0.0.0/0" - }, - { - "direction": "ingress", - "ethertype": "IPv4", - "protocol": "tcp", - "port_range_min": 8188, - "port_range_max": 8188, - "remote_ip_prefix": "192.168.3.0/24" - }, - { - "direction": "egress", - "ethertype": "IPv6", - "protocol": "any", - "port_range_min": 1, - "port_range_max": 65535, - "remote_ip_prefix": "0.0.0.0/0" - } - ], - "bootstrapped_at": "2026-03-24T16:48:36Z", - "wireguard_setup_at": "2026-03-24T16:48:54Z", - "comfyui_setup_at": "2026-03-24T16:52:16Z", - "comfyui_container_name": "comfyui_photo", - "comfyui_models": [ - "RealESRGAN_x4plus", - "SUPIR-v0Q" - ], - "status": "ACTIVE", - "vm_state": "active", - "provisioned_at": "2026-03-24T16:52:30Z" -}
\ No newline at end of file diff --git a/.hyperstack-vm1-state.json b/.hyperstack-vm1-state.json deleted file mode 100644 index 896bf15..0000000 --- a/.hyperstack-vm1-state.json +++ /dev/null @@ -1,90 +0,0 @@ -{ - "vm_id": 698908, - "vm_name": "hyperstack1-20260324205516", - "environment_name": "snonux-ollama", - "region": "CANADA-1", - "flavor_name": "n3-A100x1", - "image_name": "Ubuntu Server 24.04 LTS R570 CUDA 12.8 with Docker", - "key_name": "earth", - "public_ip": "69.19.136.193", - "created_at": "2026-03-24T20:55:17Z", - "services": { - "vllm_enabled": true, - "ollama_enabled": false, - "comfyui_enabled": false - }, - "security_rules": [ - { - "direction": "ingress", - "ethertype": "IPv4", - "protocol": "tcp", - "port_range_min": 22, - "port_range_max": 22, - "remote_ip_prefix": "79.100.218.77/32" - }, - { - "direction": "ingress", - "ethertype": "IPv4", - "protocol": "udp", - "port_range_min": 56710, - "port_range_max": 56710, - "remote_ip_prefix": "79.100.218.77/32" - }, - { - "direction": "ingress", - "ethertype": "IPv4", - "protocol": "tcp", - "port_range_min": 11434, - "port_range_max": 11434, - "remote_ip_prefix": "192.168.3.0/24" - }, - { - "direction": "egress", - "ethertype": "IPv6", - "protocol": "any", - "port_range_min": 1, - "port_range_max": 65535, - "remote_ip_prefix": "0.0.0.0/0" - }, - { - "direction": "ingress", - "ethertype": "IPv4", - "protocol": "udp", - "port_range_min": 56710, - "port_range_max": 56710, - "remote_ip_prefix": "79.100.218.77/32" - }, - { - "direction": "ingress", - "ethertype": "IPv4", - "protocol": "tcp", - "port_range_min": 22, - "port_range_max": 22, - "remote_ip_prefix": "79.100.218.77/32" - }, - { - "direction": "egress", - "ethertype": "IPv4", - "protocol": "any", - "port_range_min": 1, - "port_range_max": 65535, - "remote_ip_prefix": "0.0.0.0/0" - }, - { - "direction": "ingress", - "ethertype": "IPv4", - "protocol": "tcp", - "port_range_min": 11434, - "port_range_max": 11434, - "remote_ip_prefix": "192.168.3.0/24" - } - ], - "bootstrapped_at": "2026-03-24T20:57:32Z", - "vllm_setup_at": "2026-03-24T21:55:53Z", - "vllm_model": "openai/gpt-oss-120b", - "vllm_container_name": "vllm_gpt_oss_120b", - "vllm_preset": "gpt-oss-120b", - "status": "ACTIVE", - "vm_state": "active", - "provisioned_at": "2026-03-24T21:13:43Z" -}
\ No newline at end of file diff --git a/.hyperstack-vm2-state.json b/.hyperstack-vm2-state.json deleted file mode 100644 index 8480b29..0000000 --- a/.hyperstack-vm2-state.json +++ /dev/null @@ -1,90 +0,0 @@ -{ - "vm_id": 698909, - "vm_name": "hyperstack2-20260324205518", - "environment_name": "snonux-ollama", - "region": "CANADA-1", - "flavor_name": "n3-A100x1", - "image_name": "Ubuntu Server 24.04 LTS R570 CUDA 12.8 with Docker", - "key_name": "earth", - "public_ip": "69.19.136.171", - "created_at": "2026-03-24T20:55:19Z", - "services": { - "vllm_enabled": true, - "ollama_enabled": false, - "comfyui_enabled": false - }, - "security_rules": [ - { - "direction": "ingress", - "ethertype": "IPv4", - "protocol": "tcp", - "port_range_min": 22, - "port_range_max": 22, - "remote_ip_prefix": "79.100.218.77/32" - }, - { - "direction": "ingress", - "ethertype": "IPv4", - "protocol": "udp", - "port_range_min": 56710, - "port_range_max": 56710, - "remote_ip_prefix": "79.100.218.77/32" - }, - { - "direction": "ingress", - "ethertype": "IPv4", - "protocol": "tcp", - "port_range_min": 11434, - "port_range_max": 11434, - "remote_ip_prefix": "192.168.3.0/24" - }, - { - "direction": "egress", - "ethertype": "IPv4", - "protocol": "any", - "port_range_min": 1, - "port_range_max": 65535, - "remote_ip_prefix": "0.0.0.0/0" - }, - { - "direction": "ingress", - "ethertype": "IPv4", - "protocol": "tcp", - "port_range_min": 22, - "port_range_max": 22, - "remote_ip_prefix": "79.100.218.77/32" - }, - { - "direction": "egress", - "ethertype": "IPv6", - "protocol": "any", - "port_range_min": 1, - "port_range_max": 65535, - "remote_ip_prefix": "0.0.0.0/0" - }, - { - "direction": "ingress", - "ethertype": "IPv4", - "protocol": "tcp", - "port_range_min": 11434, - "port_range_max": 11434, - "remote_ip_prefix": "192.168.3.0/24" - }, - { - "direction": "ingress", - "ethertype": "IPv4", - "protocol": "udp", - "port_range_min": 56710, - "port_range_max": 56710, - "remote_ip_prefix": "79.100.218.77/32" - } - ], - "bootstrapped_at": "2026-03-24T20:57:46Z", - "vllm_setup_at": "2026-03-24T21:30:54Z", - "vllm_model": "bullpoint/Qwen3-Coder-Next-AWQ-4bit", - "vllm_container_name": "vllm_qwen3", - "vllm_preset": null, - "status": "ACTIVE", - "vm_state": "active", - "provisioned_at": "2026-03-24T21:30:54Z" -}
\ No newline at end of file diff --git a/photo-enhance-review.md b/photo-enhance-review.md new file mode 100644 index 0000000..935c0b2 --- /dev/null +++ b/photo-enhance-review.md @@ -0,0 +1,678 @@ +Main technical risks +1. Real-ESRGAN first, on every image, is your biggest quality risk + +Running every image through: + +4× ESRGAN +then downscale back to original size + +can definitely improve some photos, but it can also introduce: + +hallucinated texture +crispy foliage +waxy skin after interaction with later steps +fake edge detail +zippering around fine geometry +over-defined JPEG blocks on already compressed Fuji JPEGs + +This is the part I would treat as conditionally applied, not universal. + +My recommendation: + +gate ESRGAN based on image characteristics +or at least use different strength paths for portrait vs landscape vs night + +Examples: + +portraits: maybe skip global ESRGAN or use a weaker path +night/high-ISO: be careful, because ESRGAN can turn noise into invented detail +landscapes/architecture: often benefit the most + +Right now the pipeline assumes “seen at 16K then downscaled” is always a win. It often is not. + +2. CodeFormer after global enhancement can amplify inconsistency + +CodeFormer is useful, but it can produce faces that look slightly detached from the rest of the frame if the global pipeline has already altered texture and local contrast. + +Potential issues: + +face crops look cleaner than surrounding skin/neck/hair +restored face sharpness conflicts with depth blur/sharpen later +multiple faces in one frame may get uneven treatment + +Things to consider: + +apply CodeFormer only when face size exceeds a threshold +use a lower-strength/fidelity profile depending on scene +skip CodeFormer for distant faces +log face count and face bounding-box size into metadata + +That would make the workflow easier to debug when faces look “too AI.” + +3. Scene classification using 8 CLIP prompts is clever but brittle + +This is a nice lightweight idea, but it is likely the weakest decision point in the pipeline because eight prompts force coarse categorization. + +Possible failure cases: + +beach sunset might oscillate between beach, golden_hour, and landscape +indoor portraits near a window may flip to portrait or indoor +urban night scenes may misclassify between street and night +cloudy mountain lake might be overcast vs landscape + +Because your grade profile changes exposure/contrast/saturation/detail/denoise, a wrong label can materially alter the image. + +Better approach: + +store the full prompt score distribution, not just argmax +use top-2 or top-3 labels +blend profiles based on confidence instead of hard-switching + +For example: + +60% landscape + 40% golden_hour +instead of forcing one profile + +That would reduce sudden profile mistakes. + +4. CPU image ops at 4K are fine, but not yet optimized as a pipeline + +Your CPU-bound stages are sensible, but there are some efficiency concerns: + +guidedFilter and morphology/blur passes at full 4K are not trivial +ImageScaleBy 16K → 4K on CPU may be heavier than it looks +repeated color-space conversions and full-frame copies can become memory-bandwidth bound +if you later parallelize multiple photos, CPU becomes the bottleneck before GPU memory does + +This matters because your throughput is already 40–50s/photo, and if you batch more aggressively you may saturate host CPU. + +I would especially watch: + +OpenCV allocations +Python ↔ tensor conversion overhead inside custom nodes +whether large intermediate tensors are duplicated unnecessarily +5. Polling /history/<prompt_id> every 2s is workable but not ideal + +It is acceptable, but it is a weak point operationally. + +Risks: + +stale/incomplete history states +long-run prompt ambiguity if ComfyUI restarts +polling delay adds latency +harder recovery when output partially exists but metadata doesn’t + +If ComfyUI or your wrapper supports websocket progress or event-driven status, that would be better. If not, I would at least strengthen state validation: + +ensure expected output files exist and are complete +ensure metadata JSON corresponds to the same prefix +distinguish timeout from partial success +Biggest architectural improvement opportunities +1. Add conditional routing, not one fixed pipeline for every photo + +Right now the graph is elegant, but it is still mostly single-path. + +A more robust system would route based on detected attributes: + +no faces → skip CodeFormer +little/no sky → skip SkyEnhance +low confidence scene label → use default conservative grade +low-detail or noisy photo → reduce or skip ESRGAN +already high-contrast/high-saturation image → apply weaker grade + +That would reduce over-processing and save time. + +2. Move from hardcoded profiles to measured image statistics + +Your scene profiles are sensible, but they are still hand-tuned guesses. + +A stronger next step would be to incorporate measured stats such as: + +luminance histogram +highlight clipping ratio +shadow floor occupancy +saturation percentile +edge density +noise estimate +face area percentage +sky coverage + +Then use those stats to modulate: + +exposure +saturation +detail multiplier +denoise +background blur + +That would make the pipeline more adaptive and less prompt-dependent. + +3. Preserve and restore metadata more deliberately + +You correctly bake orientation before upload because ComfyUI strips EXIF. Good. + +But converting final PNG to JPEG without explicit metadata handling means you may be losing: + +original EXIF fields +capture time +lens/camera info +ICC profile +GPS if present +copyright/author data + +That may be fine, but if the intent is “enhanced derivative of original photo,” I would consider: + +copying selected EXIF fields from source to final JPEG +preserving or explicitly assigning ICC profile +adding software tag / processing note +optionally stripping privacy-sensitive fields by choice, not by accident + +Color profile handling is especially important. “No colour corrections” is not the same as “color managed.” + +4. Add resumability per stage, not just per photo + +Your manifest marks a photo done after full completion, which is good, but partial reruns still require redoing all remote processing for failed photos. + +You could get stronger resilience with stage-aware artifacts: + +oriented temp exists +upload completed +prompt submitted +output downloaded +JPEG written +metadata written + +That might be too much overhead for a personal workflow, but even just logging prompt_id per source photo would help a lot with crash recovery. + +5. Treat JPEG as an output format decision, not a fixed end state + +JPEG quality 92 is reasonable, but for some images: + +foliage +gradients in skies +deep edits after enhancement + +JPEG may reintroduce artifacts after all that expensive work. + +Consider: + +archival output as PNG or TIFF +delivery output as JPEG +optional WebP/AVIF for web usage + +Even if you keep JPEG as primary, having a “master enhanced output” option would be useful. + +Specific comments on the custom stages +AdaptivePhotoGrade + +This is the most promising custom logic in the workflow. + +Good: + +exposure in linear light +contrast and saturation as explicit steps +detail/base decomposition +per-scene profiles + +Concerns: + +gamma 2.2 approximation is simple, but true sRGB transfer is not exactly 2.2 +clipping highlights at 1.0 can lose recoverable rolloff smoothness +HSV saturation edits can behave poorly in skin tones and near highlights +fixed midpoint contrast around 0.5 is simple but not content-aware + +If you keep evolving it, the next quality wins will likely come from: + +proper sRGB transfer functions +luminance-aware saturation +highlight/shadow selective controls +local contrast constrained by noise estimate +SkyEnhance + +Clever and cheap. Good for a CPU stage. + +Risks: + +blue clothing, windows, water, reflective buildings, and tinted glass can get caught +sunset banding or haloing near trees/buildings +vertical prior helps, but can still fail on mountains or upside-weighted compositions + +I would recommend logging: + +sky coverage % +mean mask confidence +whether sky enhancement was effectively skipped + +And maybe auto-disable when coverage is too low or too fragmented. + +DepthSelectiveSharpen + +This is an interesting stage, but also easy to overdo. + +Pros: + +more photographic than simple global sharpening +can add subject separation + +Risks: + +relative depth is not segmentation +hair, glasses, transparent objects, fences, and fine branches can create messy transitions +background blur on an already naturally focused image may look synthetic +blur-plus-sharpen in one stage can produce “smartphone portrait mode” artifacts + +I would strongly consider making this more conservative: + +lower default blur +maybe sharpen foreground only, without explicit background blur +or gate blur by scene type and depth confidence + +For many photos, foreground sharpening alone may be enough. + +Performance review + +Your breakdown is believable. + +The biggest performance cost drivers are probably: + +ESRGAN 4× inference +memory movement around the 16K intermediate +downscale from 16K to 4K +Depth Anything inference + +This means the obvious speed/quality tradeoff lever is: + +reducing or conditionally skipping the 4× path + +That one decision could cut runtime materially. + +If you want better throughput later, likely gains are: + +batch submission queue with bounded concurrency +reuse loaded models across jobs, which ComfyUI already helps with +avoid oversized intermediates when not needed +possibly move some CPU image ops to GPU if they become limiting + +But honestly, for 45 photos, the current runtime is already acceptable. + +Operational review + +This is better than average for reliability, but I would still tighten a few things: + +Add stronger failure modes + +Include distinct handling for: + +upload success but prompt submission failure +prompt accepted but no output file +PNG written but metadata JSON missing +metadata JSON malformed +partial download +ComfyUI restart mid-run +Record more run provenance + +In the metadata or manifest, store: + +prompt_id +workflow hash +custom node git commit or file hash +model file hashes +processing duration per stage if possible + +That will make future tuning much easier. + +Be careful with cache busting + +The random prefix solves ComfyUI cache problems, which is practical. But it also removes some chance of safe reuse. A better long-term version is: + +cache key derived from source hash + workflow hash + relevant params + +Then you can intentionally reuse identical results. + +Best improvements to do next + +If I were prioritizing, I would do these in order: + +make ESRGAN conditional +store CLIP confidence distribution and blend scene profiles +make depth stage more conservative +preserve ICC/selected EXIF metadata +improve failure recovery and provenance logging + +Those would give the best quality/reliability gains without rewriting the whole system. + +Bottom line + +This is a well-designed, thoughtful workflow with a good systems mindset behind it. The main weakness is not architecture — it is over-processing risk from always-on enhancement stages, especially: + +full-image ESRGAN +hard scene-class selection +depth-based blur/sharpen + +So my verdict is: + +architecture: strong +operational design: strong +quality strategy: promising, but should become more conditional and confidence-aware +performance: acceptable for the workload +next maturity step: adaptive routing and stronger provenance + +If you want, I can turn this into a more formal engineering review with sections for “keep / change / risks / recommended roadmap,” or I can propose a v2 pipeline that should improve both quality and speed. + +yes: + +# Photo Enhancement Workflow Review + +## Executive summary + +This workflow is well designed. It has a strong separation between orchestration, inference, deterministic image processing, and human review. The system is practical, understandable, and already close to a small production pipeline for batch photo enhancement. + +The main issue is not the infrastructure or code shape. The main issue is **quality control under an always-on enhancement strategy**. Several expensive stages are applied to every image, even though their benefit is scene-dependent and sometimes negative. The biggest gains now will come from making the workflow **conditional, confidence-aware, and slightly more conservative**. + +--- + +# What should stay + +## 1. Ruby as the control plane + +This is a good choice. + +It gives you: + +* clean batch orchestration +* simple manifest handling +* file lifecycle control +* easy VM lifecycle integration +* a place to keep business logic out of ComfyUI + +## 2. ComfyUI as the execution graph + +Also a good choice. + +It gives you: + +* model reuse +* visual graph structure +* easy injection of runtime parameters +* modular custom node expansion + +## 3. Metadata sidecar generation + +This is one of the strongest parts of the system. + +The `_e.md` and JSON sidecars make the workflow: + +* debuggable +* reviewable +* reproducible +* easier to tune later + +## 4. Human review tool + +The comparison tool is exactly the right final step. Enhancement pipelines often fail because they assume “processed” means “better.” Yours does not. + +## 5. EXIF orientation bake before upload + +Correct and necessary. Good defensive engineering. + +--- + +# What should change + +## 1. Stop treating enhancement as a single fixed path + +Right now the graph is elegant, but too uniform. The workflow should become a **decision tree**, not a single mandatory sequence. + +Some stages should be optional: + +* Real-ESRGAN +* CodeFormer +* SkyEnhance +* DepthSelectiveSharpen +* grading strength inside AdaptivePhotoGrade + +## 2. Make Real-ESRGAN conditional + +This is the highest-priority change. + +Current risks: + +* synthetic texture +* over-crisp foliage +* JPEG artifact amplification +* invented microdetail +* unnatural skin/hair + +### Recommendation + +Use ESRGAN only when: + +* high detail scenes (landscape, architecture) +* strong edge density +* visible softness or compression + +Avoid or weaken for: + +* portraits +* night/high ISO +* already sharp JPEGs + +## 3. Replace hard scene labels with blended grading + +Current approach uses argmax from CLIP. + +Problem: scenes are often mixed. + +### Recommendation + +* keep top 2–3 scene scores +* normalize +* blend profile parameters + +Example: + +* 0.55 landscape +* 0.35 golden_hour +* 0.10 overcast + +Blend exposure, contrast, saturation, detail, denoise. + +## 4. Make depth processing more conservative + +Default behavior should be: + +* foreground sharpening only +* no background blur by default + +Enable blur only when: + +* strong subject separation +* portrait-like composition + +## 5. Preserve metadata intentionally + +Current pipeline likely loses: + +* EXIF +* ICC profile + +### Recommendation + +Preserve or explicitly manage: + +* capture timestamp +* camera/lens info +* ICC profile +* add processing metadata + +--- + +# Main risks + +## Quality risks + +### Over-processing + +Stacked enhancements may lead to synthetic look. + +### Face inconsistency + +CodeFormer may produce mismatch with surrounding regions. + +### Masking errors + +Sky and depth masks may: + +* misclassify regions +* create halos + +## Operational risks + +### Partial success ambiguity + +Need stronger validation for: + +* missing metadata +* partial downloads + +### Weak provenance + +Should log: + +* prompt_id +* workflow hash +* model versions + +### CPU bottleneck + +Potential hotspots: + +* large rescaling +* guided filtering +* morphology operations + +--- + +# Performance review + +## Current state + +~40–50s/photo is acceptable. + +## Main optimization lever + +Make ESRGAN conditional. + +## Secondary lever + +Skip unnecessary stages when not needed. + +--- + +# Recommended v2 architecture + +## Goal + +Make workflow adaptive. + +## Pipeline + +### Stage 0 — Preflight analysis + +Compute: + +* brightness histogram +* saturation +* edge density +* noise estimate +* face stats +* sky coverage +* CLIP scores + +### Stage 1 — Policy selection + +Decide: + +* ESRGAN mode +* CodeFormer usage +* grading blend +* sky enhance on/off +* depth mode + +### Stage 2 — Enhancement + +Run only selected stages. + +### Stage 3 — Output + metadata + +Include: + +* policy decisions +* confidence scores +* timings + +--- + +# Example metadata (v2) + +```json +{ + "workflow_version": "photo-enhance-v2", + "analysis": { + "scene_scores": { + "landscape": 0.51, + "golden_hour": 0.28 + }, + "face_count": 1, + "sky_coverage_pct": 23.4 + }, + "policy": { + "esrgan_mode": "weak", + "depth_mode": "sharpen_only" + } +} +``` + +--- + +# Roadmap + +## Phase 1 + +* conditional ESRGAN +* blended scene grading +* disable background blur default +* preserve metadata + +## Phase 2 + +* preflight analysis +* gating logic for faces and sky +* improved logging + +## Phase 3 + +* better color handling (true sRGB) +* noise-aware detail +* improved saturation logic + +--- + +# Final verdict + +## Strengths + +* strong architecture +* practical workflow +* good separation of concerns + +## Weakness + +* over-processing risk from always-on stages + +## Key improvement + +Move from fixed pipeline → adaptive pipeline + +This will improve both quality and performance significantly. + diff --git a/pi/plans/gt-boolean-numeric-coercion.md b/pi/plans/gt-boolean-numeric-coercion.md new file mode 100644 index 0000000..3263302 --- /dev/null +++ b/pi/plans/gt-boolean-numeric-coercion.md @@ -0,0 +1,32 @@ +# GT – Boolean‑to‑Number Coercion (RPN) Implementation Plan + +## Overview +The GT REPL will support arithmetic operations that involve booleans by automatically converting `true` → `1` and `false` → `0`. This allows expressions such as `5 3 == 1 +` to evaluate correctly without explicit conversion steps. + +--- + +## Examples +The following REPL interactions illustrate how booleans are automatically coerced to numbers (`true` → 1, `false` → 0) and can participate in arithmetic operations. + +``` +> 5 3 == 1 + # → 2 +> 5 3 > 10 + # → 11 +> 0 false + # → 0 +> true 2 * # → 2 +> 9 3 > 4 5 < + # → 2 +``` + +In each case the boolean result is shown as `true`/`false` when printed, but when used as an operand it behaves as the corresponding numeric value. + +## Plan +1. Extend the internal stack/value type to store a variant that can be either a `float64` or a `bool`. +2. Add a helper `toNumber(v Value) float64` that returns `1` for `true`, `0` for `false`, or the numeric value otherwise. +3. Update each arithmetic operator implementation (`Add`, `Subtract`, `Multiply`, `Divide`, `Modulo`, `Power`) to call `toNumber` on both operands before performing the calculation. +4. Implement Boolean operators (`gt`, `lt`, `gte`, `lte`, `eq`, `neq`) to push a boolean `Value` onto the stack. +5. Modify `Show` to display boolean values as `true`/`false` while still allowing them to be used in arithmetic via the coercion helper. +6. Write unit tests covering mixed boolean‑numeric expressions, e.g. `5 3 == 1 +` → `2`, `0 false +` → `0`, `true 2 *` → `2`. +7. Update `README.md` and godoc comments to document the automatic coercion rule and provide usage examples. +8. Add the new test suite to CI, ensure it runs on every build, and bump the project version (e.g., to `v0.2.2`). + +--- +*This plan is stored at* `/home/paul/.pi/plans/gt-boolean-numeric-coercion.md` *and serves as the reference for any upcoming tasks.*
\ No newline at end of file diff --git a/pi/plans/gt-boolean-operators-both-forms.md b/pi/plans/gt-boolean-operators-both-forms.md new file mode 100644 index 0000000..d8c287b --- /dev/null +++ b/pi/plans/gt-boolean-operators-both-forms.md @@ -0,0 +1,33 @@ +# GT – Boolean Operators (RPN) – Support Symbolic Forms + +## Rationale +- The original design used the word tokens `gt`, `lt`, `gte`, `lte`, `eq`, `neq` because they are unambiguous when typed after the `rpn` command and avoid any shell‑level redirection issues (e.g., `>` can be interpreted by the shell if the user does not quote the expression). +- Users coming from other RPN calculators or from infix languages naturally expect the symbolic forms (`>`, `<`, `>=`, `<=`, `==`, `!=`). Providing both forms improves discoverability and ergonomics without breaking existing scripts that already use the word forms. +- Adding symbolic aliases is straightforward: the `OperatorRegistry` already maps token strings to handler functions. We can register the symbols as synonyms for the same implementation used by the word tokens. + +--- +## Example REPL syntax (both word and symbol forms) +```text +# Word forms +> rpn 5 3 gt # → true +> rpn 7 7 eq # → true +> rpn a 5 3 gt = # store true in variable "a" + +# Symbolic forms (quoted to avoid shell redirection if needed) +> rpn 5 3 > # → true +> rpn 7 7 == # → true +> rpn a 5 3 > = # store true in variable "a" +``` +Both `gt` and `>` (as well as the other operators) evaluate to the same result. + +--- +## Plan: +1. Extend `OperatorRegistry` to register symbolic aliases: map `>` to the same handler as `gt`, `<` to `lt`, `>=` to `gte`, `<=` to `lte`, `==` to `eq`, and `!=` to `neq`. +2. Implement the six Boolean operator handlers (`gt`, `lt`, `gte`, `lte`, `eq`, `neq`) if not already present, using the existing `Number` comparison methods. +3. Ensure the RPN parser treats both word and symbol tokens as standard operators (no changes to tokenization needed). +4. Add unit tests covering both forms for each operator, checking numeric and mixed‑type comparisons. +5. Update documentation (`README.md` and godoc comments) to list both the word and symbolic tokens with usage examples. +6. Update the CI pipeline to run the new tests and bump the project version (e.g., `v0.2.1`). + +--- +*This plan is stored at* `/home/paul/.pi/plans/gt-boolean-operators-both-forms.md` *and serves as the reference for any upcoming tasks.*
\ No newline at end of file diff --git a/pi/plans/gt-boolean-operators-rpn-only-example.md b/pi/plans/gt-boolean-operators-rpn-only-example.md new file mode 100644 index 0000000..4b55a75 --- /dev/null +++ b/pi/plans/gt-boolean-operators-rpn-only-example.md @@ -0,0 +1,30 @@ +# GT – Boolean Operators (RPN‑Only) – Example Syntax + +## Overview +This plan adds a full set of Boolean comparison operators to the **gt** REPL, **exclusively** in RPN (postfix) form. The operators will be registered in the RPN handler, the RPN value system will be extended to hold booleans, and the change will be documented with usage examples. + +--- +## Example REPL syntax +```text +> rpn 5 3 gt # → true (5 > 3) +> rpn 3 5 lt # → true (3 < 5) +> rpn 4 4 gte # → true (4 >= 4) +> rpn 2 2 lte # → true (2 <= 2) +> rpn 7 7 eq # → true (7 == 7) +> rpn 5 7 neq # → true (5 != 7) +> rpn 10 0 gt # → false (10 > 0 is false) + +# Variable assignment with a Boolean result +> rpn a 5 3 gt = # stores true in variable "a" +> rpn a # → true +``` +The operators `gt`, `lt`, `gte`, `lte`, `eq`, and `neq` are the only new tokens; all other REPL functionality remains unchanged. + +--- +## Plan +1. Extend the internal RPN value type to represent booleans alongside numbers. +2. Implement the six postfix Boolean operators (`gt`, `lt`, `gte`, `lte`, `eq`, `neq`) and register them in the RPN operator registry. +3. Add unit tests and update documentation (godoc and README) with the example syntax above. + +--- +*This plan is stored at* `/home/paul/.pi/plans/gt-boolean-operators-rpn-only-example.md` *and serves as the reference for any future tasks.*
\ No newline at end of file diff --git a/pi/plans/gt-boolean-operators-rpn-only.md b/pi/plans/gt-boolean-operators-rpn-only.md new file mode 100644 index 0000000..9d9f641 --- /dev/null +++ b/pi/plans/gt-boolean-operators-rpn-only.md @@ -0,0 +1,31 @@ +# GT – Boolean Operators (RPN Only) Implementation Plan + +## Overview +The **gt** project currently evaluates arithmetic and percentage expressions via a REPL that supports RPN (postfix) syntax. To make the language more expressive we will add a full set of Boolean comparison operators, but **only** in the existing RPN form. No infix parsing will be introduced. + +## Goals +- Provide the six common comparison operators as postfix tokens: + - `gt` → `>` (greater than) + - `lt` → `<` (less than) + - `gte` → `>=` (greater‑than‑or‑equal) + - `lte` → `<=` (less‑than‑or‑equal) + - `eq` → `==` (equal) + - `neq` → `!=` (not equal) +- Extend the RPN stack to store boolean values alongside numbers. +- Ensure the new operators work with all numeric types supported by the existing calculator (int, float, unsigned) and handle edge cases (NaN, Inf, division‑by‑zero). +- Add thorough unit tests and update documentation. +- Integrate the changes into the CI pipeline and bump the project version. + +## Plan: +1. Extend the REPL value system to support a boolean type for RPN stack values. +2. Implement the postfix operator `gt` (greater‑than) as an RPN operator. +3. Implement the postfix operator `lt` (less‑than) as an RPN operator. +4. Implement the postfix operator `gte` (greater‑than‑or‑equal) as an RPN operator. +5. Implement the postfix operator `lte` (less‑than‑or‑equal) as an RPN operator. +6. Implement the postfix operator `eq` (equal) as an RPN operator. +7. Implement the postfix operator `neq` (not‑equal) as an RPN operator. +8. Register all new operators in the RPN operator registry. +9. Update the existing `RPNHandler` to recognize and dispatch the new operator symbols. +10. Add unit tests for each new operator covering numeric types, mixed‑type comparisons, and edge cases (NaN, Inf, zero divisor). +11. Update godoc comments for each operator and extend `README.md` with a table of Boolean operators and RPN usage examples. +12. Modify the CI pipeline to run the new tests, bump the module version to the next minor (e.g., `v0.2.0`), and add a changelog entry documenting the new Boolean operators. diff --git a/pi/plans/gt-boolean-operators-syntax-examples.md b/pi/plans/gt-boolean-operators-syntax-examples.md new file mode 100644 index 0000000..9751bb2 --- /dev/null +++ b/pi/plans/gt-boolean-operators-syntax-examples.md @@ -0,0 +1,52 @@ +# GT – Boolean Operators (RPN) – Syntax Examples + +## Overview +We are extending the **gt** REPL with a full set of Boolean comparison operators, usable **only** in RPN (postfix) form. The operators will be available in two token styles: +- **Word form** – `gt`, `lt`, `gte`, `lte`, `eq`, `neq` +- **Symbolic form** – `>`, `<`, `>=`, `<=`, `==`, `!=` + +Both forms map to the same underlying implementation, allowing users to pick the style they prefer while keeping backward compatibility. + +--- +## Example REPL syntax +```text +# Word forms +> rpn 5 3 gt # → true (5 > 3) +> rpn 7 7 eq # → true (7 == 7) +> rpn a 10 2 lt = # store true in variable "a" +> rpn a # → true + +# Symbolic forms (quote the expression if your shell would interpret the symbols) +> rpn 5 3 > # → true +> rpn 7 7 == # → true +> rpn a 10 2 < = # store true in variable "a" +> rpn a # → true + +# Mixed usage across the same session +> rpn 8 4 gte # → true +> rpn 8 4 >= # → true +> rpn 8 4 neq # → false +> rpn 8 4 != # → false +``` +All operators push a **boolean** (`true`/`false`) onto the stack, which can be stored in variables or inspected with `show`. + +--- +## Goals +1. Provide the six Boolean operators in both word and symbolic token forms. +2. Extend the RPN value system to store booleans alongside numbers. +3. Ensure existing REPL behavior (stack, variables, commands) stays unchanged. +4. Document the syntax with clear examples (as shown above). +5. Add comprehensive unit tests and CI verification. + +--- +## Plan +1. Implement the Boolean operator handlers (`gt`, `lt`, `gte`, `lte`, `eq`, `neq`) using the `Number.Compare` method and push a boolean onto the stack. +2. Register symbolic aliases (`>`, `<`, `>=`, `<=`, `==`, `!=`) in the `OperatorRegistry` as synonyms for the word forms. +3. Extend the `Stack` (or introduce a new stack type) to hold a `Value` that can represent either a `float64` or a `bool`. +4. Update `Show` to display booleans as `true`/`false` while preserving numeric formatting. +5. Write unit tests for each operator, covering numeric, mixed‑type, and edge cases (NaN, Inf, zero). +6. Add documentation to `README.md` and godoc comments, including the example syntax block above. +7. Update the CI pipeline to run the new tests, bump the module version (e.g., `v0.2.1`), and generate a changelog entry. + +--- +*This plan is stored at* `/home/paul/.pi/plans/gt-boolean-operators-syntax-examples.md` *and serves as the reference for any upcoming tasks.*
\ No newline at end of file diff --git a/pi/plans/gt-boolean-operators.md b/pi/plans/gt-boolean-operators.md new file mode 100644 index 0000000..6518599 --- /dev/null +++ b/pi/plans/gt-boolean-operators.md @@ -0,0 +1,37 @@ +# GT – Boolean Operators Implementation Plan + +## Overview +The **gt** project currently provides the `>` (greater‑than) operator for numeric comparisons. To make the language richer and more expressive, we want to add a full suite of boolean comparison operators (e.g. `<`, `>=`, `<=`, `==`, `!=`). These operators will be usable both from the REPL and in RPN scripts, and will follow the same design patterns as the existing `gt` implementation. + +## Goals +1. **Feature completeness** – support the most common boolean operators: + - `>` (greater than) – already present + - `<` (less than) + - `>=` (greater‑than‑or‑equal) + - `<=` (less‑than‑or‑equal) + - `==` (equal) + - `!=` (not equal) +2. **Unified operator model** – introduce an interface/registry so that new operators can be added with minimal friction. +3. **REPL integration** – allow infix notation for all operators, with helpful auto‑completion and syntax highlighting. +4. **RPN integration** – provide postfix forms (e.g. `gt`, `lt`, `gte`, `lte`, `eq`, `neq`). +5. **Documentation** – update godoc, README, and example snippets for each operator. +6. **Testing & quality** – comprehensive unit tests, property‑based tests for edge cases (different numeric types, nil handling, overflow), and benchmarks. +7. **CI/Release** – ensure the CI pipeline verifies the new operators and bump the module version appropriately. + +## Plan +1. **Design a generic Operator interface** and a registry that maps symbols (`>`, `<`, `>=`, …) and RPN names (`gt`, `lt`, …) to concrete implementations. +2. **Implement operator structs** (`LessThan`, `GreaterThanOrEqual`, `LessThanOrEqual`, `Equal`, `NotEqual`) that satisfy the interface, reusing existing comparison logic where possible. +3. **Update the REPL parser** to recognise the new symbols, perform tokenisation, and dispatch to the registry. +4. **Extend the RPN parser** to support the new postfix operator tokens and map them to the same implementations. +5. **Add unit tests** for each operator covering: + - Various numeric types (int, float, unsigned). + - Mixed‑type comparisons. + - Edge cases (NaN, overflow, nil values). + - Error handling for unsupported types. +6. **Write benchmarks** comparing the performance of the existing `gt` operator with the new implementations. +7. **Document the operators** in Godoc comments, update `README.md` with a comparison table, and add usage examples for REPL and RPN. +8. **Integrate with CI** – add linting, run the new test suite, and verify that the binary builds correctly. +9. **Version bump** – plan a minor version bump (e.g., `v0.2.0`) and prepare a changelog entry summarising the new boolean operators. + +--- +*This plan is stored at* `/home/paul/.pi/plans/gt-boolean-operators.md` *and serves as the reference for upcoming task creation.*
\ No newline at end of file diff --git a/pi/plans/gt-plan.md b/pi/plans/gt-plan.md new file mode 100644 index 0000000..7cf5a38 --- /dev/null +++ b/pi/plans/gt-plan.md @@ -0,0 +1,29 @@ +# Project gt – Gap Analysis and Improvement Plan + +## Overall Picture & Goals + +- Provide a reliable, well‑documented command‑line percentage calculator with RPN and rational number support. +- Deliver a smooth developer experience: clear contribution guidelines, automated CI/CD, and proper versioning. +- Ensure the codebase follows Go best practices, has comprehensive tests, and ships a stable binary. + +Plan: + +1. **Fix CI build step** – Update GitHub Actions workflow to build the correct binary path (`./cmd/gt` instead of `./cmd/perc`). +2. **Update `go.mod` Go version** – Change the `go` directive to a supported version (e.g. `go 1.22`) to match the CI Go version. +3. **Add `CONTRIBUTING.md`** – Provide guidelines for building, testing, using `mage`, and submitting pull requests. +4. **Expand README** – Include concrete examples for rational‑mode (`rat on/off/toggle`) and hyper‑operators (`[+]`, `[*]`, etc.). +5. **Add badges to README** – CI status, test coverage, and Go Report Card badges. +6. **Add end‑to‑end CLI tests** – Test the built binary for commands like `gt version`, `gt 20% of 150`, and `gt help`. +7. **Add REPL command tests** – Cover built‑in commands (`help`, `clear`, `quit`, `rat`) and variable management (`vars`, `clear`, `name d`). +8. **Add `.goreleaser.yml`** – Set up automated release builds and GitHub releases. +9. **Implement version bump workflow** – Use the `increment-version-and-push` skill to bump the version, tag, and push. +10. **Document variable management** – Add a dedicated README section describing `vars`, `clear`, and variable deletion commands. +11. **Update Magefile** – Add shortcuts for build, test, lint, and release. +12. **Add missing Go documentation** – Ensure all exported functions in the REPL package (`NewREPL`, `RunREPL`, `executor`, `defaultExecutor`, `defaultCompleter`, `defaultGetCommandDescription`) have godoc comments. +13. **Add go vet step to CI workflow** – Include a `go vet ./...` step in the GitHub Actions CI configuration to catch static analysis issues. +14. **Add godoc comments for exported TTYChecker methods (IsTTY, EnsureTTY)**. +15. **Add godoc comments for exported SignalHandler methods (Start, Stop)**. +16. **Add SPDX license headers to all .go source files**. +17. **Wrap errors with %w where appropriate for better error chaining**. +18. **Design a nice logo for the gt project (e.g., stylized 'gt' with calculator motif)**. + diff --git a/pi/plans/gt-rpn-prefix-doc.md b/pi/plans/gt-rpn-prefix-doc.md new file mode 100644 index 0000000..4af608e --- /dev/null +++ b/pi/plans/gt-rpn-prefix-doc.md @@ -0,0 +1,22 @@ +# GT – RPN Prefix Optional – Documentation & Tests Plan + +## Background +The REPL currently supports evaluating RPN expressions in three ways: +1. Explicit `rpn` (or `calc`) prefix – `rpn 3 4 +` +2. Implicit RPN when the input contains spaces – `3 4 +` +3. Incremental operator handling – entering a single operator after previous tokens. + +Because of the second case, users can omit the `rpn` prefix entirely and still get RPN evaluation. This behavior is not clearly documented, which can lead to confusion. + +## Goal +Make it explicit in the user‑facing documentation that the `rpn` prefix is optional and that any space‑separated expression is treated as RPN. Add unit tests to guard against regression. + +## Plan +1. **Update README.md** – add a section titled *"RPN usage (prefix optional)"* with clear examples showing both prefixed and unprefixed forms. +2. **Update godoc for `RPNHandler`** – clarify in the handler comment that it treats space‑separated inputs as RPN when no built‑in command matches. +3. **Add unit tests** in `internal/repl/handlers_test.go` (or a new test file) that verify expressions like `"3 4 +"` and `"rpn 3 4 +"` produce the same result. +4. **Ensure CI runs the new tests** – modify any test scripts if needed to include the new test file. +5. **Add a changelog entry** indicating the documentation update and added tests (e.g., `v0.2.2 – clarified RPN prefix optional`). + +--- +*Plan file stored at* `/home/paul/.pi/plans/gt-rpn-prefix-doc.md` *for reference.*
\ No newline at end of file |
