Skip to content

chore: release 0.6.1 - #217

Merged
wjduenow merged 14 commits into
mainfrom
release/0.6.1
Jun 11, 2026
Merged

chore: release 0.6.1#217
wjduenow merged 14 commits into
mainfrom
release/0.6.1

Conversation

@wjduenow

@wjduenow wjduenow commented Jun 11, 2026

Copy link
Copy Markdown
Owner

Cuts v0.6.1 to PyPI — the brand Design-System CLI styling (#208 epic: #209 truecolor tier palette, #210 ◆ glyphed progress, #211 done+cost footer, #212 table decision + no-emoji gate).

Dev-ahead-of-main release: release/0.6.1 is cut from dev HEAD (10 commits ahead of main with the v0.6.1 content), diff vs origin/dev is only the 4 release-prep files.

Pre-flight passed: ruff / ruff format / pyright / pytest (3809 passed, 0 type errors). uv build + uvx twine check PASSED on wheel and sdist. CHANGELOG promoted from [Unreleased][0.6.1] — 2026-06-11. Verified end-to-end via the v0.6.1rc1 TestPyPI dry-run.

Post-merge: tag v0.6.1 → non-prerelease GitHub Release → publish-pypi. dev stays on 0.7.0.dev0 (0.6.1 is an interim patch; the 0.7 line continues toward the Airflow operator).

Summary by CodeRabbit

Release Notes – v0.6.1

  • New Features

    • Added colored progress indicators with spark glyph in terminal output.
    • Introduced end-of-run footer showing written artifacts, elapsed time, and API costs.
    • Enabled truecolor (24-bit) palette support for diff verdict tiers with design-system colors.
  • Improvements

    • Color output now respects FORCE_COLOR, NO_COLOR, and COLORTERM environment variables.
    • Enhanced brand compliance with automated emoji detection and enforcement.

wjduenow added 14 commits June 10, 2026 09:47
…erge

chore: begin 0.7.0.dev0 + backmerge main into dev (post-0.6.0)
Replace the stale v0.1/v0.2 scope framing with the current release (v0.6.0 on
PyPI; dev on 0.7.0.dev0) and the v0.7–v1.0 next-scope, keeping it a scope anchor
rather than a feature list (CHANGELOG owns shipped-work detail).
…209)

AnsiRenderer now paints the four verdict tiers (kept / kept-uncertain /
dropped / flagged) in the SignalForge Design-System hues when the
terminal advertises 24-bit colour, falling back to the existing
16-colour SGR codes otherwise.

- Add brand-hex truecolor palette (#2FCB7F / #4F90F7 / #FB5A60 / #F5A623)
  in one constant block mirroring tokens/colors.css; _truecolor() helper
  emits \x1b[38;2;r;g;bm; _TIER_CODES_16 / _TIER_CODES_TRUECOLOR maps.
- New _should_emit_truecolor() is a SECOND axis below the DEC-021
  colour-on chain: only consulted once colour is on, resolved via an
  explicit truecolor kwarg or COLORTERM in {truecolor,24bit}. NO_COLOR /
  precedence / unconditional ANSI-strip (DEC-007) all unchanged.
- Header counts, table tier cells, and the proposed-test-files +++ header
  all read the same palette map for cross-surface consistency.
- 16-colour output is byte-identical to pre-#209: every existing *.ansi
  golden regenerates unchanged. New truecolor_tiers.ansi golden pins the
  brand-hex bytes (snapshot case count 13 -> 14).
- Deterministic tests: snapshot recipes pass truecolor explicitly;
  test_renderers.py autouse-clears COLORTERM so 16-colour assertions are
  env-independent; new test section covers detection + both kwarg
  overrides + colour-off short-circuit.
- Docs + rule parity: docs/diff-ops.md colour section + tier table;
  .claude/rules/diff-renderer.md new palette section.

No CLI flag / DiffConfig field — detection is automatic via COLORTERM;
the truecolor kwarg is the test seam + future --color-mode wiring point.
feat(diff): brand-hex truecolor tier palette with 16-color fallback (#209)
On a colour TTY, 'signalforge generate' progress lines now carry the brand
spark-amber ◆ glyph, a dim stage label, and a right-aligned per-stage fact
(model id / kept·dropped / mean grade). Colour-off output is byte-identical
to pre-#210, so piped logs and existing snapshots are unchanged.

- Promote the brand palette + 24-bit primitives + COLORTERM detection to a
  shared signalforge._common.palette module so the CLI progress and the diff
  renderer (#209) read the SAME bytes. diff/_renderers imports them (values
  unchanged -> every diff golden stays byte-identical).
- resolve_progress_style(verbose) decides colour once (stderr-keyed:
  FORCE_COLOR > NO_COLOR > stderr.isatty; --verbose forces progress not
  colour; truecolor via COLORTERM). Threaded through the emit calls like
  progress_on.
- emit_progress_entry/done/batch gain a ProgressStyle: colour-off keeps the
  exact '[N/total] stage: body' / 'done in X' lines; colour-on emits
  '◆ [N/total] stage  body' + right-aligned dim fact. Decisions D3/D4 (#208):
  keep the safety line AND the [N/total] counter.
- print_stderr gains allow_sgr=True — the narrow #60 strip-at-the-sink
  exception for trusted glyph/dim SGR (the emitter pre-strips user content).
- Facts: draft->model, prune->'N kept · M dropped', grade->'mean X.XX',
  computed from in-scope objects (DEC-026, never hardcoded).
- Tests: shared palette unit tests; resolve_progress_style precedence +
  emit plain/colour/right-align/glyph unit tests; rewrote the TTY progress
  tests palette-robustly (strip SGR, assert structure) + a spark-amber SGR
  pin + a plain-path byte-stability pin; autouse fixture isolates the colour
  env per test (the --no-color os.environ mutation leaks across in-process
  main() runs).
- Docs/rules: cli-layer.md progress section, diff-renderer.md palette section
  (now _common.palette), docs/cli-ops.md progress example.

prune-existing progress stays plain (passes no style) — scoped to generate.
feat(cli): ◆ glyphed progress UX for signalforge generate (#210)
A successful single-model 'signalforge generate' run now closes with a
two-line stderr footer below the diff: a 'wrote …' line naming the
artifacts actually written, and a '✓ done in <X> · $cost' line with the
per-provider LLM cost.

- build_run_footer / format_cost_clause / _format_usd / _check_glyph in
  _helpers.py. ✓ is signal-green (palette.SIGNAL/GREEN); glyph + colour only
  when style.color (reuses the #210 ProgressStyle); plain path is glyph-free.
- Footer built in _run_single_model (single-model + progress_on only),
  stored on _SingleModelOutcome.footer_text, emitted by the dispatcher AFTER
  sys.stdout.write(diff) + flush so it reads below the table and > diffs.txt
  stays clean. Batch closes with format_batch_summary (per-model cost would be
  cumulative across the append-only audit JSONLs) — footer_text="" in batch.
- Cost from signalforge.llm.cost.rollup_audit_dir, SUPPLEMENTARY: a rollup
  failure degrades to no cost clause, never fails the run (cli-layer.md
  DEC-005). Sub-cent renders <$0.01. Warehouse cost omitted (no actual-bytes
  figure at end-of-run; --estimate is the planner preview).
- wrote line is honest: schema.yml (N kept) only under --write, diff.json
  unless --dry-run, grade.json when graded; 'dry run — no files written'
  under --dry-run.
- Tests: format_cost_clause + build_run_footer units (color/plain/dry-run/
  sub-cent/sorted/zero-skip); integration tests for footer-in-TTY (on stderr,
  not stdout) + --quiet suppression.
- Docs/rules: cli-layer.md footer section, docs/cli-ops.md footer subsection.
- format_cost_clause strips ANSI from the unknown-provider fallback (the
  raw audit-derived key) before it reaches print_stderr(allow_sgr=True) —
  consistency with the #210 'emitter pre-strips user content' rule.
- Footer gates .signalforge/grade.json on 'not dry_run' so --dry-run reports
  'dry run — no files written' (honours the dry-run contract) instead of
  claiming a deliverable; added an integration test pinning it.
- docs: add 'text' language specifier to the cli-layer.md footer fence.
feat(cli): end-of-run footer — wrote … + ✓ done in <X> · $cost (#211)
#212)

Closes the brand-CLI epic's table-polish child. No production change — the
em-dash N/A score and the 6-column table were already correct; this pins the
brand-voice invariants and records the column-layout decision.

- tests/test_brand_no_emoji.py: a rendered-output 'no emoji' gate over every
  diff snapshot case + the CLI progress/footer surfaces. Keyed on emoji/
  pictographic codepoint ranges that exclude the BMP glyphs the brand uses
  (✓ → ◆ — … └─ ↳) and accented Latin user text. Planted-violation self-check
  (predicate must catch 🐰/✨ and pass ✓/◆/café) per testing-signal.md.
- D2 decision recorded in diff-renderer.md: KEEP the 6-column table
  (TIER · ARTIFACT · TEST · REASON · SCORE · WHY). The Design-System mockup's
  5-column fold (REASON into WHY) is NOT adopted — REASON carries the
  load-bearing DropReason literal, distinct reviewer signal from the prose WHY.
- diff-renderer.md also pins the em-dash N/A score (already implemented +
  tested by test_score_none_renders_em_dash) and the no-emoji gate.

Em-dash work item was already complete (src + test_score_none_renders_em_dash);
this ticket reduced to the glyph audit + the D2 decision.
test(diff): brand glyph audit (no emoji) + record D2 6-column decision (#212)
@coderabbitai

coderabbitai Bot commented Jun 11, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

Pull request was closed or merged during review

📝 Walkthrough

Walkthrough

This PR delivers v0.6.1 with unified terminal output styling: a shared ANSI/truecolor palette module, CLI progress rendering with spark glyphs and right-aligned facts, end-of-run footers with cost rollup, brand-hex tier colors in diff output, and enforcement of a "no emoji" brand gate across all surfaces.

Changes

CLI and Diff Output Branding

Layer / File(s) Summary
Shared ANSI/truecolor palette primitives
src/signalforge/_common/palette.py, tests/_common/test_palette.py
New module centralizes SGR controls, 16-color codes, truecolor_sgr() formatter, brand palette constants (SIGNAL, STEEL, NOISE, FLAG, SPARK, FORGE), and colorterm_is_truecolor() detection. Tests validate escape-sequence bytes and COLORTERM precedence.
CLI progress styling infrastructure and footer helpers
src/signalforge/cli/_helpers.py, tests/cli/test_progress_style.py
ProgressStyle dataclass and resolve_progress_style() track color/truecolor state from env/TTY. Extended emit_progress_entry(), emit_progress_done(), emit_batch_progress_entry() accept optional style and render spark glyphs, right-aligned facts, and styled output. New format_cost_clause() and build_run_footer() format footers with success glyphs and cost clauses. print_stderr() gains allow_sgr parameter. Tests cover color precedence, plain/color paths, glyph/fact formatting, and footer composition.
Generate CLI: progress styling and footer text construction
src/signalforge/cli/generate.py, tests/cli/test_generate.py
Resolves progress_style once and threads through all five stage emissions. Constructs footer_text on successful single-model runs with cost rollup (fail-soft). Emits footer to stderr after diff output. Stage progress includes factual strings (model id, kept/dropped, mean score). Tests validate color/TTY interactions, progress output, and footer rules.
ANSI diff renderer: truecolor detection and brand-hex tier colors
src/signalforge/diff/_renderers.py, tests/diff/test_renderers.py, tests/diff/_snapshot_inputs.py
Added truecolor kwarg override, _should_emit_truecolor() detection via COLORTERM/kwarg, and _tier_codes(truecolor) mapping for 16-color ↔ brand-hex selection. Threads truecolor through render pipeline so tier counts/cells use palette-appropriate colors. Extended tests validate detection, override precedence, fallback behavior, and header/cell consistency. Snapshot fixture infrastructure adds deterministic truecolor_tiers.ansi case.
Brand validation: emoji detection and enforcement
tests/test_brand_no_emoji.py
New module implements emoji-codepoint predicate, validates predicate against brand glyphs and accented text, scans all diff/CLI renders for emoji violations. Ensures brand voice consistency.
Documentation, rules, and version metadata
.claude/rules/*, docs/cli-ops.md, docs/diff-ops.md, CHANGELOG.md, CLAUDE.md, src/signalforge/__init__.py
Rule documents formalize CLI progress UX and diff renderer contract. User docs describe glyph/fact progress, footer behavior, truecolor tier colors. Metadata reflects v0.6.1 shipping and roadmap.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • wjduenow/SignalForge#215: Direct overlap on end-of-run footer implementation (wrote … + ✓ done in … · $cost in _helpers.py and generate.py).
  • wjduenow/SignalForge#216: Aligns on brand-glyph "no emoji" audit enforcement and diff table contract (6 columns / distinct REASON).
  • wjduenow/SignalForge#213: Builds on brand-hex truecolor tier palette work for diff renderer (_renderers.py tier-color mapping and palette sourcing).

Suggested labels

enhancement, cli

Poem

A palette shared, tier colors bright,
Progress spark glyphs shining right,
Footers bold with and cost,
Brand-hex colors—not a bit lost! 🐇

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 63.11% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'chore: release 0.6.1' directly and clearly describes the primary purpose of the PR: cutting and releasing version 0.6.1 to PyPI.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

Comment @coderabbitai help to get the list of available commands and usage tips.

@wjduenow
wjduenow merged commit db5def7 into main Jun 11, 2026
10 of 11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant