Skip to content

feat(harness): Phase 1 — management foundation, fork & duplicate, drift detection#249

Merged
eyelock merged 3 commits into
developfrom
feat/harness-management
May 2, 2026
Merged

feat(harness): Phase 1 — management foundation, fork & duplicate, drift detection#249
eyelock merged 3 commits into
developfrom
feat/harness-management

Conversation

@eyelock
Copy link
Copy Markdown
Owner

@eyelock eyelock commented Apr 29, 2026

First slice of the harness-as-first-class-citizen rework. Establishes the
architecture, surfaces, and YNH coordination model that Phase 2 (YND tools)
and Phase 3 (LLM authoring) will build on. Headed for 0.10 beta.


What's in

Foundation

  • CommandRunner — streamed-output shell-out with cancellation; single seam for all ynh/ynd callers (replaces ad-hoc Process/Pipe).
  • YNH 0.3+ envelope decodingHarnessListResponse/HarnessInfoResponse parse capabilities, ynh_version, and the new --check-updates fields (version_available, ref_available, sha_available).
  • YnhVersionProbe — capability-based gate (≥ 0.3.0). Phase 1 features hidden silently on older binaries.
  • Tolerant Harness decoder — accepts null for includes/delegates_to (which YNH emits for broken-install error rows). One bad row no longer collapses the sidebar.

Detail pane

  • HarnessDetailViewModel extracted from the view — pure types own source classification, editability, and update signals, each with their own test coverage. Old feature-flagged badge retired.
  • Source badges: registry name / short Git URL / Local / Forked from <X>. Read-only pill on registry installs.
  • Vendor override picker — per-harness vendor (claude/codex/cursor) persists across launches, surfaces in the detail header.

Update detection — three-state drift signal

  • Versioned (version_installed != version_available) — orange dot, info banner, single-click Update.
  • Unversioned drift (content drift without a version bump) — amber warning triangle, warning banner, confirmation step listing each drifted include installed → available SHA. Surfaces the supply-chain signal explicitly so users review before pulling.
  • None — clean.

Sidebar dots/triangles, header global-probe spinner, and the dependency-view per-include warning triangle all read from the same HarnessUpdateSignal.

Fork & Duplicate (pointer-model YNH)

Phase 1 lands alongside YNH's pointer-model rewrite (ynh fork --to <path> self-registers via ~/.ynh/installed/<name>.json).

  • Fork to local — single ynh fork call. One editable working tree. No copy under ~/.ynh/harnesses/. installed_from.forked_from preserved for the ghost-origin display.
  • Duplicate — single ynh fork --to <path> --name <newname> call. Local-only renamed copies. Hidden for registry harnesses (Fork covers that intent).
  • Update menu hidden for forks (YNH refuses).

Action menu parity

Sidebar context menu and detail action menu share a canonical five-group layout. Sidebar drops Help and Export-as-Marketplace (advanced/help-only); detail keeps everything.

Group Sidebar Detail
Run Launch / Copy Run Command Copy Run Command
Location Reveal in Finder, Reveal in Terminal, Open in…, Open in browser*, Copy as Pathname same
Actions Update*, Fork to local*, Duplicate* + Export as Marketplace…
Help YNH Documentation
Destructive Uninstall, Delete Harness* same

* denotes context-gated visibility (URL-only, source-kind, fork-state, etc.)

Editable-path resolution

For forked-locals, Reveal in Finder/Terminal, Open in…, Copy as Pathname, and the Path field all target installed_from.source (the editable working tree), not the YNH install slot. Single canonical "where this lives on disk."

Sheet first-paint fix

All six sheets (Fork, Update, Duplicate, Add Marketplace, Session Recovery, Install) now apply .frame() at the .sheet content closure rather than inside the sheet body. Eliminates the rounded-rect placeholder that flashed before content resolved — a long-standing issue caused by NSWindow racing the SwiftUI layout pass on switch-based bodies.


Coordinated YNH changes (already merged)

YNH change Why TermQ needs it
Structured-output envelope (capabilities, ynh_version, --check-updates fields) Capability gating + drift detection
installed_from.forked_from provenance Forked-local source badge
ynh fork self-registers via pointer model Single-call fork; live-edit workflow
ynh fork --name flag Single-call Duplicate
Plugin-only update (ynh update <selfcontained>) Drift on harnesses with no includes (gitflow case)
Tolerant null arrays in error rows Documented; TermQ also defensive

Testing

  • Quality gate clean from swift package clean baseline — 1593 tests pass (17 pre-existing skips), 0 failures, 0 lint violations, format clean.
  • End-to-end manual — Fork registry → editable copy. Edit .ynh-plugin/plugin.json description in source tree. Refresh. Detail pane shows the change without reinstall step. Uninstall preserves source tree on disk.
  • Drift round-trip — manufacture drift in installed.json, refresh, click Update from warning banner, drift clears.

Manual checklist sits in .claude/sessions/manual-test-checklist.md (gitignored).


Out of scope (queued for follow-ups)

  • Inline include editor on the detail pane — backend (HarnessAuthor, marketplace include picker) is in place; UI not wired. Next focused branch.
  • Phase 1.5 — Delegate editor — waits on ynh delegate add/remove/update.
  • Phase 2 — Tools menu (Validate / Lint / Format / Preview / Diff vendors / Export / Migrate). YND-driven, no YNH coordination needed.
  • Phase 3 — LLM authoring (Compress / Inspect / Create).

Commit shape

Three logical commits:

  1. feat(harness) — code (foundation, detail pane, fork & duplicate, drift detection, sheet sizing, tolerant decoder, action menus, editable path).
  2. feat(localization) — 40 languages translated for the new UI surface.
  3. test(harness) — coverage for fork, badges, decoder, drift signals.

🤖 Generated with Claude Code

David Collie and others added 3 commits May 2, 2026 09:26
…uplicate, drift detection

Scope:

CommandRunner foundation. Streamed-output shell-out with cancellation;
migrate ynh callers off ad-hoc Process/Pipe to a single seam.

YNH 0.3+ envelope decoding. HarnessListResponse / HarnessInfoResponse
parse the structured-output envelope with capabilities and ynh_version;
YnhVersionProbe gates Phase 1 affordances on capabilities ≥ 0.3.0.

Detail pane refactor. Extract HarnessDetailViewModel from the view; pure
formatters for source classification (HarnessSourceBadgeViewModel),
editability (HarnessEditabilityResolver), and update signal
(HarnessUpdateBadgeStore). Old feature-flagged badge retired.

Source badges and read-only model. Sidebar rows and detail header show
provenance: registry name, short Git URL, "Local", or "Forked from <X>".
Registry harnesses display a Read-only pill — surfaces that direct edits
will be overwritten by the next ynh update.

Update detection. UpdateAvailabilityService seam +
LiveUpdateAvailabilityService impl wraps ynh ls --check-updates and ynh
info --check-updates. Three-state HarnessUpdateSignal classifies as
versioned (manifest version bumped — orange dot, info banner),
unversionedDrift (content drift without a version bump — amber warning
triangle, warning banner, confirmation step listing each drifted include
SHA), or none. Sidebar dots, header global-probe spinner, dependency-view
warning triangle render the signal.

Fork to local (single-call). ForkHarnessSheet runs ynh fork --to <path>
against the pointer-model YNH; one editable working tree, no copy under
~/.ynh/harnesses/. installed_from.forked_from preserved; ghost origin
shown in detail pane.

Duplicate (single-call with --name). DuplicateHarnessSheet runs ynh fork
--to <path> --name <newname> for local-only renamed copies. Hidden for
registry harnesses (Fork covers that intent).

Action menu parity. Sidebar context menu and detail action menu share a
canonical five-group layout (Run, Location, Actions, Help, Destructive).
"Open in…" submenu, Open in browser (URL sources), Reveal in Terminal,
Copy as Pathname now consistent across both surfaces. Update menu hidden
for forks (YNH refuses).

Editable-path resolution. For forked-locals, Reveal/Open/Copy actions
target installed_from.source (the editable working tree), not the YNH
install slot. Single canonical "where this lives on disk" location.

Tolerant Harness decoder. Custom init(from:) accepts null for includes
and delegates_to (which YNH emits for broken-install error rows). One
bad row no longer collapses the whole sidebar.

Sheet first-paint fix. Fork, Update, Duplicate, Add Marketplace, Session
Recovery, and Install sheets apply their .frame at the .sheet content
closure rather than inside the sheet body. Eliminates the
rounded-rect placeholder flash before content resolves.

Vendor override picker. Per-harness vendor override (claude/codex/cursor)
persists via YNHPersistence; surfaces as a picker badge in the detail
header.

Tutorial 13 updated for fork/duplicate/menu reorganization.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…languages)

Adds and syncs localized strings for the Phase 1 harness management
surface across all 40 supported locales:

- Source badges (Local, Forked from <X>, Read-only pill)
- Update banner copy (versioned vs unversioned-drift wording)
- Update sheet phases (confirm, running, succeeded, failed)
- Unversioned-drift warning banner and confirmation step
- Fork sheet (title, explanation, fork button, progress)
- Duplicate sheet (title, name field, duplicate button)
- Action menu items new in this PR (Reveal in Terminal, Open in…,
  Open in browser, Copy as Pathname, Delete Harness)
- Sidebar tooltips for the global-probe spinner and dependency-view
  warning triangle
- Common error/loading copy used by CommandRunnerSheet

No source-only NEEDS TRANSLATION markers remain.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…gnals

Adds and updates test coverage to match the Phase 1 implementation:

- HarnessUpdateBadgeStoreTests — full coverage of the three-state signal
  classification (none / versioned / unversionedDrift), include-level
  drift, harness-source drift (self-contained plugins), and version-bump
  precedence over drift. Regression test for nil-ref include data shape.
- HarnessSourceBadgeViewModelTests — registry / git / local / forked
  classification from installed_from variants.
- HarnessEditabilityResolverTests — editability decision per source kind
  and capability gate.
- ForkServiceTests — single-call ynh fork --to flow, error mapping,
  invalidate-on-success.
- YnhVersionProbeTests — semver comparison, capability gating.
- YNHDecodingTests — extended for tolerant Harness decoder (null
  includes/delegates_to from broken-install error rows), envelope shape,
  --check-updates fields (version_available, ref_available, sha_available),
  forked_from provenance.
- UpdateCheckStateTests — lifecycle transitions.
- YNHPersistenceProtocolTests — vendor override persistence contract.
- HarnessRepositoryTests — capability surface + selectedDetail wiring.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@eyelock eyelock force-pushed the feat/harness-management branch from 224deb5 to 1a17d95 Compare May 2, 2026 08:28
@eyelock eyelock changed the title feat(harness): Phase 1 management — source badges, update dots, fork-to-local feat(harness): Phase 1 — management foundation, fork & duplicate, drift detection May 2, 2026
@eyelock eyelock marked this pull request as ready for review May 2, 2026 08:32
@eyelock eyelock merged commit 0a56968 into develop May 2, 2026
7 checks passed
@eyelock eyelock deleted the feat/harness-management branch May 2, 2026 08:36
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