Skip to content

Merge dev → main (automated) - #2088

Merged
SorraTheOrc merged 72 commits into
mainfrom
release/dev-to-main-20260924084723
Sep 24, 2026
Merged

SorraTheOrc merged 72 commits into
mainfrom
release/dev-to-main-20260924084723

Conversation

@SorraTheOrc

Copy link
Copy Markdown
Member

Automated release created by ship skill.\n\nIncludes CHANGELOG.md with work-item summaries from this release.

pi and others added 30 commits September 9, 2026 22:18
…50S9JW001DHME)

Extend buildDowntimeSpawnOptions with optional DowntimeSpawnConfig that
allows the downtime dispatcher to select AUDIT_PHASE2_PARALLELISM based
on the current operating mode (cheap/fast) and the available dispatch
budget:

- PARALLELISM=1 (default): fast mode, cheap mode with full budget, or
  config absent. Children run sequentially.
- PARALLELISM=2: cheap mode AND a second slot free AND dispatch cap ≤ 1.
  Up to 2 Phase 2 children run in parallel, fitting the 2-slot cheap
  mode pool (parent already done Phase 1, max 2 concurrent streams).

Backward compatibility: callers without config default to '1'.

Changes scoped to packages/herdr/src/downtime-worker.ts (types, function
logic, and defaultDowntimeSpawn update), packages/herdr/src/downtime-
worker.test.ts (7 new tests), and packages/herdr/README.md (documented).

AC1: buildDowntimeSpawnOptions returns mode-aware spawn options ✓
AC2: Parent+children never exceeds cheap-mode slot budget (2) ✓
AC3: No audit-skill changes ✓
AC4: Tests cover all mode/budget combinations + backward compat ✓
AC5: Measured outcome documented (wall-clock drops, busy% rises) ✓
…003JY1Z)

The previous header truncation fix used JavaScript .length to measure
visible width, but emoji characters like ⏳ render as 2 terminal cells
while .length counts them as 1. A header that measured as exactly
cols characters could occupy cols+1 visual columns, wrapping onto a
second physical row and scrolling the first line off the top.

Add visibleLength() helper that counts Unicode ranges U+2300–U+23FF
(misc technical, includes ⏳), U+2600–U+26FF (misc symbols, includes
⚠ and ⛔), and U+1F000+ (emoji) as 2 cells. truncateLine now uses this
for both the fits-check and the truncation loop, ensuring multi-width
characters can never push the header past cols visual columns.

Add 3 unit tests covering ⏳ emoji headers at 40 cols and 30 cols
(visual-width assertions and rows-1 invariant).

Root cause of 'still disappears sometimes': bug only manifested when
the downtime idle timer was active (⏳ present in header) — with
[Downtime Off] (no emoji) the character-count happened to match visual
width. The intermittent timing explains the operator's report.
Add the optional `time` field (HH:MM wall-clock) to the scheduled-prompts
README documentation, including:

- The `time` field in the entry schema (with backward-compat note)
- Dual due-check semantics: interval-only (no time) vs. interval + at-or-after
  time (with time), including calendar-day interval counting
- The canonical standup entry (intervalDays: 1, time: "06:05") in the base set
- Once-per-calendar-day firing guarantee even with late dispatches

(WL-0MTMN7W63001FCQR)
…d tolerance constant

- Define AUDIT_FRESHNESS_AT_NEAR_TOLERANCE_MS = 60000 in packages/shared/src/icons.ts
- Replace magic 60000 literal in isAuditFresh() with the named constant
- Update doc comments to reference the at-or-near semantics
- Add tests for milliseconds-near freshness (AC3) and genuinely stale (AC4)
- Update consumer comments in downtime-worker.ts, grouping.ts, and test files
- All consumers import isAuditFresh from the shared module — single source of truth

Renames:
- packages/shared/src/icons.ts: AUDIT_FRESHNESS_AT_NEAR_TOLERANCE_MS constant + updated docs
- packages/herdr/src/icons.test.ts: new at-or-near and genuinely stale test suites
- packages/herdr/src/downtime-worker.ts: updated JSDoc comment
- packages/herdr/src/grouping.ts: updated inline comment
- src/commands/grouping.ts: updated inline comment
- packages/herdr/src/grouping.test.ts: updated test comment
- tests/grouping-utility.test.ts: updated test comment
…(WL-0MSNI6TQ5003JY1Z)

The header truncation (9284144) and emoji fix (71374ac) were correct
but incomplete. formatItemLine() had its own truncation that used
String.length and always counted visLen += 1, never handling multi-width
characters. When work items had CJK/Hangul/fullwidth titles, item lines
underestimated visual width, wrapped onto extra rows, and pushed the
header off-screen — explaining 'still disappears sometimes'.

Fix:
+ Expanded visibleLength() to handle 15 double-width Unicode ranges
  (CJK unified ideographs, CJK extensions, Hangul, fullwidth forms,
  enclosed CJK/alphanumeric, bopomofo, dingbats, emoji)
+ Updated formatItemLine() to use visibleLength() and multi-width
  truncation loop (matching truncateLine behaviour)
+ Updated formatTooltipOverlay() and dialog padLine() to use
  visibleLength()
+ Added 3 tests: CJK title truncation, CJK rows-1 invariant,
  fullwidth ASCII truncation

All 365 worklist tests pass. Pre-existing worklist-visibility test
failure confirmed unrelated (timing-based, pre-existing).
Run 'herdr server reload-config' (best-effort) after inserting, migrating,
or finding an existing prefix+l keybinding so a running herdr server
activates it without a manual reload. Missing herdr or a failed reload
only warns; the installer still exits 0.
…cted

When ~/.pi/agent/AGENTS.md is a symlink to AGENTS_GLOBAL.md (the canonical
SorraAgents install), wl init now delegates agent-guidance/workflow setup:
the N/B/M workflow prompt and --workflow-inline are skipped (the flag is a
no-op) and the canonical global-reference structure is kept in the project
AGENTS.md. Standalone environments keep the existing workflow behaviour.

- Add isSorraAgentsInstalled() with WL_SORRA_AGENTS_OVERRIDE=0/1 override
- Guard all four workflow-inline code paths (JSON + interactive, existing +
  fresh config) on SorraAgents detection
- Report sorraAgentsDetected in JSON output; print delegation notice in
  interactive output
- Document the delegation in `wl init` help, CLI.md and docs/AGENTS-INSTALL.md
- Add 7 tests covering the SorraAgents path, JSON output, idempotence and the
  unchanged standalone path
…e paths

The /\binit\b/ substring test matched the worktree path (e.g.
...-align-wl-init-with-sorraagents-install-d), classifying every CLI
invocation as the interactive `init` command and spawning a subprocess
instead of running in-process. Tests asserting on stderr with `2>&1`
(sync-divergence-detection) then saw empty stderr. Detect `init` as a
standalone argument token after stripping the cliPath from the command.
- Add null guard for 'initial' in dispatcher-anchor.ts (TS18047)
- Cast candidate.stage to string in retired-stage check (TS2367)

Fixes: WL-0MSNXXA6O001ESB5
WL-0MU3U1AMP0044WUX — Herdr extension selection list: icons sometimes
render as error (?).

The truncation loops in formatItemLine and truncateLine appended only
the LOW surrogate of a supplementary-plane emoji (🔓, 📋, 🔍, …) when the
truncation point landed on one. The unpaired surrogate written to stdout
encodes as U+FFFD (EF BF BD), which terminals render as a white
diamond/question-mark "error" glyph. The bug is intermittent because it
only fires when a row's line width exceeds the pane and the truncation
point lands inside an emoji.

Two spots fixed (same defect):
- formatItemLine inline truncation loop
- truncateLine (used by the detail view, metadata panel and headers)

Both now append the full character (both surrogate halves) and advance
the index by two code units for pairs.

Regression tests: packages/herdr/src/worklist-icon-truncation.test.ts
asserts no lone surrogates and no U+FFFD after UTF-8 round-tripping for
formatItemLine / formatMetadataPanel / formatDetailContent across
truncating widths, including the exact reported row shape (status open +
stage plan_complete + critical + long title).
pi added 28 commits September 22, 2026 00:22
…on_id (WL-0MU8807BI008C9ME)

Fix the downtime dispatcher's owner-lease gate to be per-slot-aware:
- In per-slot mode: slotOwned = true only when countFreeUnownedSlots === 0
- In count-based mode: preserve original conservative gate

Also fix blocking dependency WL-0MU88086A0089US4:
- parseLlamaStatus now accepts array local_owner_session_id
- Extracts session ID from [url, session] array format
- Fail-closed on malformed input (number, object, empty array)

Tests added (12 new):
- AC1: per-slot 3-slots with 1 owned + 2 free unowned dispatches
- AC2: count-based status with owner lease + running panes refused
- AC3: per-slot all-owned status refused
- AC4: audit-tier minimum (2 free) against per-slot count
- AC1b: operator lease with 0 running panes dispatches
- Array parsing: legacy string, current array, malformed inputs, contract
…0MU8807BI008C9ME)

The per-slot owner-lease gate introduced a second, divergent definition of
'per-slot mode' (Array.isArray(status.slots) && length > 0) instead of the
existing predicate used by the idle-capacity gate and evaluateIdle
(Array.isArray(status.slots) && 0 < requiredFreeSlots < total_slots).

Sharing the single definition keeps the ownership gate from ever being
stricter than the capacity gate that admitted the tick, which is the exact
class of stall this RCA fixes. Behaviour is unchanged for all reachable
states (verified by the 594-test downtime-worker suite); this removes a
maintainability hazard and matches the plan's 'same detection as
evaluateIdle'.
…MUDEGBGO00609RV)

Pure, injectable helpers for the Ship It pre-dialog guard:

- parseWorklogWorkItemIds: parses wl list --json → Set<work-item IDs>
- listBlockingPanes: filters panes by project ID + live agent status
- formatBlockedNotice: renders human-readable blocking notice
- runShipGuard: convenience wrapper combining the pure helpers

A pane blocks ship mode when:
- Its label carries a project work-item ID, AND
- Its agent is present AND status is not done/exited

32 unit tests covering: blocking/clear paths, live vs done/exited,
multiple blocking panes, different project IDs not blocking, pure
injectable functions, and blocked notice formatting.

Parent: WL-0MUD6DDZC007ZSIW
…08FFC2)

Extend code-freeze.ts with the plugin-writes-on-confirm contract:

- writeCodeFreezeMarker(): atomic write (temp + rename) of the marker
  with { active, reason, startedAt, pid }; returns null on failure
  (fail-closed so callers surface the error).
- clearCodeFreezeMarker(): idempotent removal; returns true when no
  marker remains.

Updates the module header to document the ownership change: the ship
skill remains the authority that clears the marker on release exit;
the plugin writes on Ship It confirm and best-effort clears on dispatch
failure.

Adds 16 tests covering the documented shape, deterministic overrides,
tri-state integration, atomicity (no temp leftovers), overwrite,
fail-closed on unwritable dir, idempotent clear, and write/clear
round-trip.

Parent: WL-0MUD6DDZC007ZSIW
…L-0MUDEJU9Z004UO2W)

Integrate the Ship Guard and the marker writer into the worklist's
Ship It flow (parent WL-0MUD6DDZC007ZSIW):

- openShipItDialogGuarded(): runs the guard BEFORE openShipItDialog().
  When live agent panes carry project work-item IDs — or the guard query
  is unavailable (fail-safe) — a full-pane blocked notice is shown and
  the dialog is never rendered.
- formatBlockedShipDialog(): bordered modal reusing the Code Freeze dialog
  box style; dismissed with Esc/Enter/q.
- openShipItDialog onConfirm: writes the Code Freeze marker BEFORE
  dispatching /skill:ship release; best-effort clears the marker it wrote
  when the dispatch is a no-op or onCommand throws. An already-active
  freeze is owned by the ship skill and is neither overwritten nor cleared.
- createProductionShipGuardQuery(): production seam running
  wl list --json + herdr pane list; injectable via the new shipGuardQuery
  option for hermetic tests.
- isInputActive() gains the blocked-notice gate so scheduler ticks pause
  while the modal is showing.
- Updates the existing ship-it-dialog TUI tests to inject a clear guard so
  the dialog regression tests stay focused; adds focused unit tests for
  the formatter and the isInputActive third argument.

Parent: WL-0MUD6DDZC007ZSIW
@SorraTheOrc
SorraTheOrc merged commit 399ba29 into main Sep 24, 2026
@SorraTheOrc
SorraTheOrc deleted the release/dev-to-main-20260924084723 branch September 24, 2026 08:51
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