You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Milestone: #179 (M5: TUI completion). Spec for the /to-tickets cut. ADRs at HEAD and the spine amendments control where this text differs.
Problem Statement
Secant's terminal client stops short of the information architecture settled in #23. Workspace Home offers three entries and no way to see which coding Harnesses are installed, qualified, or able to run a Run. Start a Run checks a launch only at the moment of submission, returns the first failing Problem, and offers no model choice even though Codex already reports its models during qualification. The Run Workbench claims (live) from scroll position rather than stream health, so a lost update stream shows frozen content as current, and its optional details omit the requested and effective model, recovery evidence, and the secondary lifecycle actions. The Bundle screens are two flat full-screen dumps with no search, no scrolling, and a Workflow shown as a joined list of step ids. Previous Runs works but has not been checked against the deferred keymap, empty-state, and small-terminal items. Headless has no Harness command at all, so a script cannot learn what Harnesses exist.
Underneath all of this, the evidence architecture is wrong. Every orchestration assertion in the Application, headless, Run execution, and Run Store suites spawns real children, and the #177 investigation proved that Bun's isolated test-worker machinery can lose completed child-process evidence under pressure. A runtime flake therefore turns unrelated semantic assertions red, there is no Process Module Interface to inject a deterministic double through, and the one gate that runs the whole tree cannot say whether a failure belongs to product logic, to Bun and the operating system, or to packaging.
Solution
M5 lands the #177 evidence-architecture prefactor first. The Process Module gains an owned Interface with a deterministic fake and a fake-versus-real parity suite, mirroring what the Harness Seam already has. Every orchestration transition, error, race, retry, ordering rule, and resting state is then proven through injected Process and Harness doubles inside the test runner, while real spawn, byte ordering, exit, signal, cancellation, escalation, tree cleanup, Git, and recorded-Harness behaviour move to a standalone runtime-conformance runner that executes in an ordinary Bun process on all three operating systems. Compiled-binary acceptance keeps at least one copied-binary path through Command, Claude Code, Codex, interruption, recovery, and Git. A migration ledger maps every subprocess-backed test to its replacement before anything is deleted, and ADR 0027 is amended to record the three-layer gate. No behavioural coverage is deleted, and no flake is masked.
On that footing, M5 completes the #23 screens in user order and in both clients over the Projection Port. Two new Projection families land first: launch-preparation, a live read-only assessment of one complete client-owned launch draft, and harness-catalog, bounded discovery and qualification of installed Harnesses with optional exact focus. The Harness profile gains the supported-model declaration that ADR 0022's amendment already promised, and a launch carries an optional requested model that the Adapter forwards and the Run stores. Start a Run gains a model choice and a Review step that assesses the whole draft before submission, returns to the correcting step with a precise finding, and creates no Run on failure. The Run Workbench separates view freshness from Run state, handles snapshot loss on the follow and settle paths, and completes its details surface. The Bundle catalog becomes a searchable list-and-inspector screen with scrollable content and the declared Workflow step list. A new Harness catalog screen and a new headless harness command expose the same normalized Harness facts with no Action Offers. Workspace Home gains its Harnesses entry. Every TUI slice retires the applicable #23 deferred items and states which do not apply.
User Stories
Test maintainer and reviewer (evidence architecture)
As a test maintainer, I want every orchestration state transition, error, race, retry, ordering rule, and resting-state result proven through deterministic injected Process and Harness doubles, so that a runtime flake cannot turn unrelated semantic assertions red.
As a test maintainer, I want a Process Module Interface with a deterministic fake that scripts spawn acknowledgement, ordered stdout and stderr bytes, exit and signal outcomes, cancellation, and escalation, so that Command steps, Preflight, and Git probes are exercisable without a child.
As a test maintainer, I want one parity suite that runs the same observable Process contract against the fake and the real implementation, so that the fake earns trust only by matching production.
As a test maintainer, I want the existing Harness conformance suite kept running against the fake, the Claude Code replayer, and the Codex replayer, so that Harness parity is preserved through the prefactor.
As a reviewer, I want real spawn, byte ordering, exit and close status, signals, cancellation, escalation, tree cleanup, Git, and recorded-Harness behaviour kept in a standalone runtime-conformance runner that executes as an ordinary Bun process, so that the Prove where Bun loses child-process lifecycle evidence under runner stress #177 defect cannot reach it.
As a reviewer, I want the runtime-conformance runner to block on its own on Windows x64, macOS arm64, and Linux x64, so that a red result is attributable to Bun, the operating system, or process integration.
As a reviewer, I want at least one copied compiled-binary path through Command, Claude Code, Codex, interruption, recovery, and Git kept in the compiled-binary acceptance, so that the user path is proven from the artifact users receive.
As a reviewer, I want a checked-in migration ledger mapping every subprocess-backed test to its exact replacement assertion, evidence layer, and replacement test before any deletion, so that no coverage disappears because the old test was flaky.
As a reviewer, I want no retries, sleeps, timeout increases, or silent assertion removal anywhere in M5, so that failures stay attributable rather than hidden.
As a reviewer, I want ADR 0027 amended to record the process-free semantic suite, the standalone runtime conformance, and the compiled-binary acceptance as separately blocking layers, so that the gate the ADR describes matches the gate CI runs.
As a test maintainer, I want the Process Module itself unchanged as a workaround for the Bun defect, so that a test-runner-confined problem does not alter production spawning.
Run operator, Start a Run (TUI)
As a TUI user, I want Start a Run to be the first and default Home entry, so that the primary task is one keypress away.
As a TUI user, I want the launch steps numbered as N of M with the inputs step omitted when the Bundle declares no launch inputs, so that I know how far I am from starting.
As a TUI user, I want the Bundle step's side panel to show what the Bundle can do, including its source and Workflow summary, so that I choose with the facts in view.
As a TUI user, I want a View Bundle Details jump from the Bundle step into the Bundle catalog focused on that Bundle, with back returning to Start a Run, so that inspection does not lose my draft.
As a TUI user, I want the Harness step to show each Harness with worded qualification and availability, such as Qualified or Unavailable · authenticate with Codex first, so that I never read a raw enum.
As a TUI user, I want the Harness step to offer a model choice drawn from the selected Harness's supported models when it declares a list, free-text entry when it declares free text, and Harness default always, so that I decide the model or leave it to the Harness's own configuration.
As a TUI user, I want a Command-only Bundle to skip both Harness and model choice, so that Secant asks nothing it will not use.
As a TUI user, I want the Review step to show Workflow, Bundle digest, Workspace, Harness with model, every launch input, and the trust posture, so that I confirm the complete draft before creating a Run.
As a TUI user, I want the Review step to assess the complete draft live through launch-preparation and show Checking launch while it does, so that I see findings before I submit.
As a TUI user, I want a launch to revalidate every check at submission, so that a draft assessed as ready cannot start a Run against changed truth.
As a TUI user, I want a failed launch to create no Run, keep every unaffected draft choice, return me to the step that can correct it, focus the finding, and clear only the invalidated field, so that one stale fact does not discard my work.
As a TUI user, I want findings named precisely, such as This Bundle can no longer start, Workspace prerequisite not met, <Bundle> is no longer installed, <Harness> is no longer ready, and The selected model is no longer available, each with remediation, so that I know what to fix.
As a TUI user, I want a Run not started notice that I can dismiss, so that failure is visible without trapping me.
As a TUI user, I want trust acknowledgement to remain part of Start a Run and never a catalog action, so that trust is granted only against the exact digest I am about to run.
As a TUI user, I want Start a Run keyboard-operable, readable at small terminal sizes, and understandable without colour, so that the settled terminal experience holds.
Run operator, Run Workbench (TUI)
As a TUI user, I want the Workbench header to show a view-freshness token, View current, View loading, View disconnected, or View catching up, separate from the Run state, so that a stale view can never masquerade as a live Run.
As a TUI user, I want the freshness token derived from update-stream health rather than scroll position, so that a lost stream is reported as lost.
As a TUI user, I want Run controls unavailable while the view is not current, with the dock saying why, so that I cannot act on last-known state.
As a TUI user, I want a disconnected view to name the last confirmed time and offer Reconnect, so that I can recover the view without leaving the Run.
As a TUI user, I want a lost snapshot on the follow path to reopen the Projection and show loading then catching-up until durable catch-up reaches the live edge, so that recovery is visible and truthful.
As a TUI user, I want a lost snapshot on the settle path, while an Operation is pending, to keep the receipt visible and resolve it from the reopened Projection, so that a submitted action is never reported as vanished.
As a TUI user, I want a Run that no longer exists to return me to Previous Runs with a dismissible <name> was deleted notice, so that a missing subject is explained.
As a TUI user, I want the optional details panel to show identity, Workspace, Bundle, selected Harness, observed Harness, requested model, and effective model, so that requested and observed facts stay distinguishable.
As a TUI user, I want the details panel to show recovery evidence, including the resting reason, the latest durable activity, a Materialization conflict, an indeterminate Attempt, or a lost Session, so that I understand why a Run rests and whether resume is safe.
As a TUI user, I want the secondary lifecycle actions, cancel and delete, in the details panel rather than the main rail, so that the main surface stays focused on the timeline and the primary action.
As a TUI user, I want every resting state to carry short prose, such as Workflow completed, This Run has ended, You stopped at the Review checkpoint, or Execution stopped outside the Workflow, so that the state word and its colour are never the only signal.
As a TUI user, I want a resume whose evidence shows an indeterminate Command Attempt to require an explicit acknowledgement that effects may repeat, so that I consent knowingly.
As a TUI user, I want a resume that the Port reports unavailable, such as a lost required Session, shown as unavailable with the reason, so that the control is truthful rather than hidden.
As a TUI user, I want the timeline to mark where its bounded window begins, so that I know no older activity is hidden by scrolling.
As a TUI user, I want the jump control labelled with the count of new activities and Jump to latest, so that returning to the live edge is discoverable.
As a TUI user, I want a failed older-page read in the inspection overlay to show a visible notice, so that the TUI surfaces the Problem the headless client already prints.
As a TUI user, I want large content truncation marked consistently in the timeline and the inspection overlay, so that I know when I am seeing a bounded view.
As a TUI user, I want Operation receipts, such as Checking resume becoming Resume applied, shown transiently and dismissible, so that success is as visible as failure.
As a TUI user, I want the Workbench's modal precedence, two-press interrupt, and confirm-armed destructive actions preserved through these changes, so that settled interaction rules are not regressed.
Run operator, Previous Runs (TUI)
As a TUI user, I want the All and Resumable filters, day grouping, live-Run markers, bounded older pages, and direct open into the Workbench kept as they are, so that M5 verifies rather than rewrites them.
As a TUI user, I want empty states worded as No previous Runs and No resumable Runs with a one-line explanation, so that an empty list is not mistaken for an error.
As a TUI user, I want an explicit end-of-history marker, so that I know when paging has reached the beginning.
As a TUI user, I want the Previous Runs keymap, focus glyph, and small-terminal layout verified against the deferred items, so that the screen is checked, not assumed.
As a TUI user, I want quit confirmation while a live Run exists to keep working from Previous Runs, so that a keypress cannot abandon a Run silently.
Run operator, Bundle catalog (TUI)
As a TUI user, I want one Workflow Bundles screen with a search field, a result list, and an inspector pane, so that I find and read a Bundle without leaving the screen.
As a TUI user, I want search to match name, id, description, and origin as I type, so that any fact I remember finds the Bundle.
As a TUI user, I want No matching Workflow Bundles with a hint when nothing matches, so that an empty result is explained.
As a TUI user, I want the header to state how many Bundles are installed, so that the list size is visible without counting.
As a TUI user, I want the inspector to show identity, source with origin detail, platforms, requirements, digest, and Trust, so that it exposes exactly what ADR 0021 allows.
As a TUI user, I want the Workflow section to list the declared steps numbered, with Repeat groups nested and Command steps shown as commands, so that I see the routing rather than a joined list of ids.
As a TUI user, I want the Launch inputs section to list each declared input, or explain that Start a Run proceeds from Harness to Review when there are none, so that I know what launch will ask.
As a TUI user, I want long inspector content to scroll with the keyboard, so that a large Bundle is readable rather than clipped.
As a TUI user, I want the back action to return to wherever I came from, Home or Start a Run, so that the catalog works as an inspection detour.
As a TUI user, I want the Bundle catalog to offer no actions of its own, so that install, trust, and launch remain where they are.
Run operator, Harness catalog (TUI)
As a TUI user, I want a Harnesses entry on Workspace Home, so that installed Harnesses are inspectable without starting a Run.
As a TUI user, I want the Harnesses screen to state how many Harnesses are discovered and how many qualified on this system, so that readiness is visible at a glance.
As a TUI user, I want each row to show the Harness name, a worded qualification chip, a one-line summary, and how many models were observed, so that I can compare Harnesses without opening each.
As a TUI user, I want to search by name, model, or capability, with No matching Harnesses and a hint when nothing matches, so that the screen stays useful as the set grows.
As a TUI user, I want the inspector to show the Harness, executable, version, platform, when it was checked, and authentication posture, so that observed evidence is distinguishable from the semantic identity.
As a TUI user, I want an unavailable Harness to show its reason and remediation, including external login instructions, so that I know what to do outside Secant.
As a TUI user, I want a Supported models section listing each model as available for Run selection, or stating that models are not available yet or that the Harness accepts free-text entry, so that the model choice at launch is explained.
As a TUI user, I want a Capabilities section over six fixed capabilities, Session recovery, Same-Turn steering, Turn interruption, Tool approvals, Structured questions, and Effective model, each Available, Available with limits, Unavailable, or Not checked, with limits viewable, so that I read what the Harness truthfully exposes.
As a TUI user, I want a Configuration section that says Harness-owned settings stay with the Harness, so that I do not look for them in Secant.
As a TUI user, I want the Harness catalog to offer no actions and to expose no Adapter, native payload, credential, or native capability structure, so that the Seam stays truthful.
As a TUI user, I want opening the Harnesses list to spawn nothing, with qualification running only when I focus a Harness, so that browsing does not launch two coding agents.
Headless user
As a headless user, I want harness list and harness inspect <id> with --json, so that scripts learn the same normalized Harness facts the TUI shows.
As a headless user, I want harness inspect to run bounded qualification and report supported models and the six capabilities, so that automation can decide before launching.
As a headless user, I want a --model option on run launch accepted only for an Agent-bearing Bundle, so that scripts select the same requested model as the TUI.
As a headless user, I want a --model on a Command-only Bundle rejected as irrelevant, so that a script cannot appear to select a model that was never used.
As a headless user, I want run launch to read the same launch-preparation assessment first and, when the draft is not ready, print every finding in text and JSON and exit without submitting, so that I see all problems in one invocation.
As a headless user, I want a ready assessment followed by a launch that reruns every check, so that headless and TUI create Runs under identical rules.
As a headless user, I want run resume to reuse the Run's durable requested model without another flag, so that recovery cannot switch models.
As a headless user, I want run show --json to carry the requested model additively, so that scripts can compare requested and effective models.
As a headless user, I want existing exit codes and frozen JSON fields unchanged, with only additive fields, so that current scripts remain valid.
As a headless user, I want run list and run resume to stay in parity with Previous Runs, so that filters and resume mean the same thing in both clients.
As a headless user, I want an Interactive agent Bundle still refused with the remediation to run it in the TUI, so that the sole v1 both-client exception stays explicit.
As a headless user, I want no trust-revocation command, so that neither client exposes an action the domain rejects.
Bundle author
As a Bundle author, I want my Bundle neither to select nor constrain a model, so that the user's requested model and the Harness's own default remain authoritative.
As a Bundle author, I want my declared Workflow, launch inputs, and prerequisites rendered in the catalog exactly as declared, so that authoring mistakes are visible before a Run.
As a Bundle author, I want no Secant source path to inspect my Bundle id, name, or Asset path to choose behaviour, so that catalog and launch behaviour stay generic.
Harness maintainer
As a Harness maintainer, I want the profile to supply the supported-model list when the Harness exposes one and to declare free-text entry otherwise, so that ADR 0022's amendment is built rather than promised.
As a Harness maintainer, I want an optional requested model accepted at prepare and applied at the Harness's native point, so that the choice reaches the coding agent without a second protocol.
As a Harness maintainer, I want the requested model and the effective model kept as separate facts, so that a Harness substitution is visible.
As a Harness maintainer, I want the Harness Interface otherwise unchanged and no third Harness added, so that M5 stays TUI completion.
As a Harness maintainer, I want qualification performed for the catalog through the existing prepare-and-close path with the prepared Harness released immediately, so that inspection never leaves a child running.
Release and evidence
As a release reviewer, I want the OpenTUI pin unchanged and every copied or rebuilt presentation path recorded in the provenance ledger, so that the vendor boundary stays truthful.
As a release reviewer, I want the Windows Terminal human check re-run only when the renderer or the pin changes, with each TUI slice stating whether it applies, so that evidence tracks its trigger.
As a release reviewer, I want the support matrix current after M5, so that no row claims what the evidence does not prove.
As a distributor, I want no new runtime dependency, so that third-party notices stay unchanged.
As a contributor, I want the canonical check, standalone runtime conformance, terminal lifecycle, and compiled-binary smoke green on all three operating systems before M5 closes, so that G3 opens on a proven baseline.
Implementation Decisions
Scope and ordering
The Prove where Bun loses child-process lifecycle evidence under runner stress #177 evidence-architecture prefactor lands first. No screen slice widens the test tree before the Process Interface, its fake, the parity suite, the runtime-conformance runner, the migration ledger, and the ADR 0027 amendment are at HEAD. Ticket dependencies encode that order.
The two Projection families land before the screens and commands that consume them: harness-catalog before the Harness catalog screen, the headless harness command, and the Start a Run Harness step rewording; launch-preparation before the Review step and the headless pre-launch assessment.
Screen slices follow user order: Start a Run, Run Workbench, Previous Runs, Bundle catalog, Harness catalog, then Workspace Home's fourth entry. Each is one ticket in the TUI and headless together where a headless surface exists.
M5 adds no Harness, makes no public release, and does not touch the OpenTUI pin or the release channel. The first release candidate remains M6.
Evidence-architecture prefactor
The Process Module gains an owned Interface covering executable resolution, spawn, ordered stdout and stderr delivery, exit and signal outcome, cancellation, the two-stage shared-bound shutdown, and tree cleanup. Run execution's Command steps, Application Preflight's executable resolution and Workspace-prerequisite probe, and the bare-name Git spawns consume that Interface. Composition wires the real implementation; tests inject either.
A deterministic fake Process implementation is script-driven with no timers: scripted resolution results, ordered byte chunks, exit codes, signals, cancellation and escalation outcomes. It follows the Harness fake's discipline, including refusing to emit after a terminal result.
One parity suite drives the observable Process contract, ordering, terminal-once, cancellation, escalation, and failure typing, against the fake and the real implementation. The fake run lives in the semantic suite; the real run lives in the runtime-conformance runner.
The Harness side keeps its existing fake, shared conformance suite, and recorded replayers. Conformance gains groups for the model declaration and requested-model forwarding.
The semantic suite is every test under the test runner. It uses injected Process and Harness doubles and never spawns. Bundles remain exercised rather than stubbed: they are built and installed through the Bundle and Catalog Modules in process, and their Command steps resolve and run through the fake Process.
Standalone runtime conformance is an ordinary Bun program under the tests tree with no test framework, following the terminal-lifecycle suite. It carries the real Process parity run, real Harness replayer runs, Run Store ownership and crash-recovery scenarios that kill and restart children, Git worktree behaviour, and the composition wiring check. It exits non-zero on the first failure and names the scenario. It is invoked by its own package script and its own named step in the three-OS check job, runs even when the canonical step failed, and blocks on its own.
Compiled-binary acceptance keeps the compiled-binary smoke and the consumer scenarios. The smoke is checked against the six required paths, Command, Claude Code, Codex, interruption, recovery, and Git, and any missing path is added there rather than in a new script.
The migration ledger is a checked-in table with one row per subprocess-backed test file today: the assertion it carried, the evidence layer it moves to, and the replacement test. A row's old test is deleted only after its replacement is green on all three operating systems. Rows may split when one file carried assertions at two layers.
ADR 0027 gains an amendment recording three separately blocking layers: the process-free semantic suite in the test runner, the standalone runtime conformance outside it, and the compiled-binary acceptance. It rewrites the sentence that describes the deterministic suite as the spawning suite, keeps the rejection of an in-process fake as the only end-to-end double, and records the terminal-lifecycle suite's actual standing as a step made blocking by the consumer aggregator.
Runner settings, isolation, and per-test timeouts are unchanged. Nothing in M5 adds a retry, a sleep, a larger timeout, or removes an assertion without a ledger row.
The Process Module's production behaviour is not changed to work around the Bun defect. Runtime code under the tests tree may use Bun-specific APIs; target source stays under the ADR 0030 allowlist.
Projection Port: launch-preparation
The selector is one complete client-owned launch draft: Bundle identity and version, selected Harness id when the routing needs one, optional requested model, typed launch inputs, and the trust digest when acknowledged. Changing any draft field opens a new Projection; the family rebases rather than preserving identity.
The snapshot carries a status of assessing, ready, or not-ready; the normalized draft; the ordered findings; the generated Execution summary; and current Action Offers. Each finding names a correction target, bundle, harness, model, inputs, trust, workspace, or command, a code, an explanation, and a remediation, reusing the existing Problem vocabulary.
Assessment reruns the ordered Preflight checks that launch runs today, without creating a Run, Session, Turn, or durable draft: exact Installed Bundle still present and its bytes valid and composed, Workspace approval, Interactive agent refusal for a client without interactive turns, selected-Harness discovery and served capabilities, launch-input presence and type, Workspace prerequisites, Command executables, and Trust. It additionally qualifies only the selected Harness through the registration's bounded qualify path to check the requested model against the declared model list, and releases the prepared Harness immediately.
When ready, the Projection offers launch-run carrying the assessed draft and the trust requirement evidence. Trust remains an acknowledgement submitted with the launch; there is no separate grant Operation, and the Trust-grant order after Run creation is unchanged.
Launch itself reruns every authoritative check. A refused launch returns one Problem carrying the same correction target so both clients route to the same step.
Projection Port: harness-catalog
The selector is optional exact focus on one semantic Harness id. The list view carries one summary per registered Harness: id, name, discovery state with the sources searched, last qualification state, and observed executable, version, platform, and checked-at evidence when a qualification result is held in this process.
Qualification states are qualified, qualified-with-limits, not-ready, and not-checked. A list open performs discovery only and spawns nothing. A focus open performs bounded qualification through the Application Harness registration's qualify path, which composition implements as prepare then immediate close, and caches the result for this process keyed the same way M4 keys Codex qualification.
The focus view adds the supported-model declaration, the six normalized capabilities each with a state of available, available-with-limits, unavailable, or not-checked and optional limits, the configuration posture, external authentication instructions when the failure is authentication, and a diagnostic reference. The six capabilities map from the profile's existing evidence-bearing fields: Session recovery from recovery, Same-Turn steering from steer, Turn interruption from interruption, Tool approvals from approvals, Structured questions from clarifications, and Effective model from the model observation capability.
The family carries no Action Offers. Adapter objects, native clients and payloads, credentials, executable spawn targets, and native capability structures never cross the Port.
The Application Harness registration, the normalized view composition already hands Application, gains a qualify operation next to discover. It returns the normalized profile or a typed unavailable result. Application receives no Adapter object. Tests fake qualification at this seam with a literal registration array.
Harness Seam: supported models and requested model
This completes ADR 0022's 2026-09-07 amendment, which decided that the profile supplies the model list when the Harness exposes one and declares free-text entry otherwise. The profile's model-selection capability gains that declaration. Codex supplies the list it already reads during qualification; Claude Code declares free-text entry. Both fields are additive, and the Interface is otherwise unchanged.
Prepare accepts an optional requested model. Each Adapter applies it at its native point and keeps the mechanism private. An unknown requested model against a declared list is a typed unavailable result, not a substitution.
launch-run carries the optional requested model only when the routing contains an Agent or Interactive agent Step, and it participates in idempotent replay identity. The Run stores it durably beside the selected Harness before the first Attempt, reuses it on reopen and resume, and never changes it. Requested model and effective model remain separate facts; the Run view exposes both.
Harness default is a valid choice meaning no requested model, so the Harness's user-owned configuration stays authoritative as M4 decided. Resume-time model change and per-Turn selection are not built.
Start a Run
Steps are Bundle, Harness, Inputs, and Review, numbered N of M, with Inputs omitted when the Bundle declares none and Harness omitted for a Command-only Bundle.
The Harness step reads the harness-catalog list view for its rows and wording, and shows a model field below the selected Harness: a choice list when the profile declares a list, a text field when it declares free text, with Harness default first in both cases. Choosing a Harness whose focus has not been qualified in this process triggers the bounded qualification for that Harness only.
Review opens a launch-preparation Projection over the complete draft and renders Workflow, Bundle digest, Workspace name and path, Harness with model, each launch input, and trust posture, with findings inline while assessing becomes ready or not-ready. Start Run is available only when ready and shows Checking launch while the launch settles.
A refusal shows a dismissible Run not started notice, moves to the step named by the correction target, focuses the finding, and clears only the invalidated field. A removed Bundle returns to the Bundle step; a Harness or model finding returns to the Harness step; input violations return to Inputs; trust returns to Review.
View Bundle Details opens the Bundle catalog focused on the highlighted Bundle; back returns to the same Start a Run step with the draft intact.
Run Workbench detail and freshness
The follow helper exposes stream health. A closed update, whether from observer lag, subject loss, or shutdown, marks the view disconnected and records the last confirmed time. Reopening moves through loading and catching-up until durable catch-up reaches the live edge, then current. The (live) badge is replaced by the freshness token, and the timeline's live-edge following remains a separate scroll fact.
Controls that dispatch Operations are unavailable while the view is not current; the dock states View freshness · not Run state and the reason. Reconnect reopens the Projection and is a read, like navigation, not an Operation.
On the settle path, a pending Operation receipt survives a snapshot loss; the outcome is resolved from the reopened operation Projection. A subject that no longer exists returns to Previous Runs with a dismissible deleted notice.
The details panel gains Bundle, selected Harness, observed Harness, requested model, effective model, recovery evidence, and the cancel and delete actions with their confirmations. Recovery evidence is rendered only from facts the Run view already exposes or that this milestone adds additively: resting reason, latest durable activity, Materialization conflict, an indeterminate Attempt, and Session availability for resume. No new Run state is introduced.
A resume Offer whose evidence includes an indeterminate Command Attempt arms an acknowledgement before dispatch. A resume Offer the Port marks unavailable renders as unavailable with its reason.
Every resting state gets one line of prose beside the state word. The bounded timeline shows a beginning marker, the jump control shows the count and Jump to latest, truncation markers are uniform across timeline and inspection, and a failed older-page read in the inspection overlay shows a notice. Operation receipts are transient and dismissible.
Previous Runs
Filters, grouping, paging, live markers, quit confirmation, and direct open into the Workbench are unchanged. The slice verifies them against the deferred items and closes wording, keymap, and small-terminal gaps: empty-state titles and explanations, the end-of-history marker, and focus glyph at every width.
No exact-Run detail screen is added; the Workbench details panel is the detail surface. Rows continue to show no Run state.
Headless run list and run resume shapes are unchanged.
Bundle catalog
List and inspect merge into one screen with a search field, a result pane, and an inspector pane. Search is a presentation-only substring match over name, id, description, and origin against the existing bundle-catalog list snapshot; the Port gains no search selector and no fuzzy-matching dependency is added.
The inspector renders identity, source and origin detail, platforms, requirements, digest, Trust wording shared with headless, the numbered Workflow step list with nested Repeat groups and Command steps as commands, the Launch inputs section, and the Execution summary. Large content scrolls with the keyboard inside a vendored scrollbox; movement clamps at the ends as today.
Back is context-aware between Home and Start a Run. The screen offers no actions.
Headless bundle list and bundle inspect shapes are unchanged; the catalog is already listable and inspectable headlessly.
Harness catalog screen and headless command
The screen follows the Bundle catalog's two-pane shape over the harness-catalog family: search over name, model, and capability, rows with name, qualification chip, summary, and observed-model count, and an inspector with facts, unavailable finding, Supported models, Capabilities, and Configuration sections. Focusing a row opens the exact-focus Projection and runs bounded qualification once per process.
Headless gains harness list and harness inspect <id>, each with --json. list prints discovery and last-known qualification; inspect performs the bounded qualification and prints the focus view. Text mirrors the screen's wording; JSON prints the snapshot and is frozen from its first release. Exit codes follow the existing contract: zero on success, one on refusal.
Workspace Home
Four entries in order: Start a Run, Workflow Bundles, Previous Runs, Harnesses, with Start a Run the default focus. A summary line shows installed Bundle count and previous Run count from existing snapshots; it names a qualified Harness only when a qualification result is already held in this process, and otherwise omits that fragment.
Vendor boundary and dependencies
OpenTUI stays at its current pin. New provenance entries record the copied two-pane layout primitives and scroll helper, and the studied-only sources for the picker, freshness, and status-glyph patterns. The existing Bundle list entry is amended to record that scroll is now vendored and clamping is retained.
No new runtime dependency. Search is substring matching; third-party notices are unchanged.
Renderer-directory and pin changes arm the Windows Terminal human check. Screen slices that touch neither state the check as not applicable and rely on in-memory renderer tests plus the terminal-lifecycle CI step.
CI and gates
No new workflow file. The three-OS check job gains one named step for standalone runtime conformance, running after the canonical step and not skipped by its failure. The consumer job and the terminal-lifecycle step are unchanged.
Every slice names its CI scenario: the canonical step, the runtime-conformance step, or a consumer scenario, on the three-OS matrix.
Testing Decisions
A good test drives the highest stable seam and asserts user-visible or durable outcomes: Projection snapshots and Offers, typed Problems and findings, rendered frames, headless text and JSON, exit codes, Run state and stored facts, and ordered Process and Harness observations. It does not assert private filenames, internal reducers, database rows, or Adapter internals.
Projection Port. Tests drive the real Application with injected real Catalog and Run Store over temp directories, a literal Harness registration array whose discover and qualify results are scripted, and the fake Process. They prove launch-preparation status transitions, every finding and its correction target, no Run or Trust grant on not-ready, launch revalidation after truth changes, requested-model admission and durability, and harness-catalog list-without-spawn, focus qualification, cache behaviour, and no Offers.
Process seam. One parity suite runs against the fake in the semantic suite and against the real implementation in the runtime-conformance runner. Run execution and Preflight tests move to the fake and keep every assertion the ledger maps.
Harness Seam. The shared conformance suite gains model-declaration and requested-model groups and continues to run against the fake and both replayers; replayer runs move to the runtime-conformance runner.
TUI. In-memory renderer tests mount the real App and navigate the real way with fake view seams over snapshot literals, asserting captured frames by text: step numbering, worded qualification, model field variants, Review fields, refusal routing and draft preservation, freshness tokens and gated controls, snapshot-loss recovery on follow and settle, details content, resting prose, search results and empty states, scroll clamping, two-pane focus glyphs, and small-terminal layouts. Focus is asserted through the rendered glyph, never colour.
Headless. The in-process harness proves harness list and harness inspect text and JSON, --model acceptance and rejection, the pre-launch assessment printing every finding and exiting without submission, ready-then-launch, resume reuse, and additive JSON fields with frozen existing ones.
Runtime conformance and compiled binary. The standalone runner proves real spawn ordering, exit and signal handling, cancellation, escalation, tree cleanup, Git, replayer behaviour, and Run Store crash recovery on all three operating systems. The compiled-binary smoke keeps the six required paths.
Ledger. Each migrated test's ledger row is the acceptance criterion for its deletion; a reviewer checks the row before the old file goes.
Prior art: the Projection Port launch tests with a literal registration array, the Harness fake and shared conformance suite run against both replayers, the terminal-lifecycle suite as a framework-free Bun program, the Start a Run and Workbench renderer tests, and the headless in-process harness.
Every semantic test runs without children, network, or credentials, waits for observable state rather than sleeping, and has no retries. The named gap is deliberate: the semantic suite proves product logic against doubles, the runtime runner proves integration against real processes, and neither proves compatibility with a currently installed real Harness; human release evidence supplies that.
Out of Scope
Any third Harness, the OpenCode probe and workflow, Gemini, and any Harness Interface change beyond the two additive model fields.
Resume-time model change, per-Turn model selection, Bundle-recommended or Bundle-constrained models.
Bundle trust revocation in either client, built-in Bundle removal, uninstall changes.
New Run states, upward timeline fetching beyond the bounded snapshot, Artifact export, out-of-focus completion notifications.
An exact-Run detail screen in Previous Runs, a Port-level search selector, fuzzy matching, and any new runtime dependency.
A headless dry-run command separate from run launch, headless Interactive agent passthrough, and prompting at a gate on an attached terminal.
An OpenTUI bump, renderer changes, and the Windows Terminal human check unless a slice touches the renderer or pin.
A public release, a release candidate, and G3, which opens after M5 closes.
Further Notes
The milestone text says M5 does not change the Harness Interface and also asks for a model choice drawn from supported models. A choice that is not forwarded is dead UI, and no model list exists on the Interface today. This spec resolves the conflict by completing ADR 0022's existing amendment with two additive fields, with Rohan's agreement on 2026-09-21. The Seam's semantics, opacity, and portfolio assumptions are otherwise untouched.
The Prototype Crucible's launch and Run information architecture #23 prototype is design evidence, not code. Each screen slice follows its layout, states, navigation, and wording and re-verifies keyboard, resize, teardown, and platform behaviour in OpenTUI. The prototype's indeterminate, session-lost, and expired-resource docks are rendered only as far as the Port already exposes those facts; they do not become Run states.
Catalog and Run-list Projections carry no Action Offers, per the Projection Port resolution. Reconnect, search, focus, and navigation are reads, not Operations, and are the only visible controls not backed by an Offer.
Qualification is deliberately on focus, not on list, because prepare spawns the real Harness. A list that qualified every installed Harness on every Home visit would start two coding agents to draw a menu.
Every TUI ticket copies the Prototype Crucible's launch and Run information architecture #23 deferred items into its acceptance criteria and states which do not apply, per slicing rule 7. Every ticket carries Owner:, Ratchet:, Deletes:, Gate:, and Dependencies: and is published without ready-for-agent until its packet is curated.
Milestone: #179 (M5: TUI completion). Spec for the
/to-ticketscut. ADRs atHEADand the spine amendments control where this text differs.Problem Statement
Secant's terminal client stops short of the information architecture settled in #23. Workspace Home offers three entries and no way to see which coding Harnesses are installed, qualified, or able to run a Run. Start a Run checks a launch only at the moment of submission, returns the first failing Problem, and offers no model choice even though Codex already reports its models during qualification. The Run Workbench claims
(live)from scroll position rather than stream health, so a lost update stream shows frozen content as current, and its optional details omit the requested and effective model, recovery evidence, and the secondary lifecycle actions. The Bundle screens are two flat full-screen dumps with no search, no scrolling, and a Workflow shown as a joined list of step ids. Previous Runs works but has not been checked against the deferred keymap, empty-state, and small-terminal items. Headless has no Harness command at all, so a script cannot learn what Harnesses exist.Underneath all of this, the evidence architecture is wrong. Every orchestration assertion in the Application, headless, Run execution, and Run Store suites spawns real children, and the #177 investigation proved that Bun's isolated test-worker machinery can lose completed child-process evidence under pressure. A runtime flake therefore turns unrelated semantic assertions red, there is no Process Module Interface to inject a deterministic double through, and the one gate that runs the whole tree cannot say whether a failure belongs to product logic, to Bun and the operating system, or to packaging.
Solution
M5 lands the #177 evidence-architecture prefactor first. The Process Module gains an owned Interface with a deterministic fake and a fake-versus-real parity suite, mirroring what the Harness Seam already has. Every orchestration transition, error, race, retry, ordering rule, and resting state is then proven through injected Process and Harness doubles inside the test runner, while real spawn, byte ordering, exit, signal, cancellation, escalation, tree cleanup, Git, and recorded-Harness behaviour move to a standalone runtime-conformance runner that executes in an ordinary Bun process on all three operating systems. Compiled-binary acceptance keeps at least one copied-binary path through Command, Claude Code, Codex, interruption, recovery, and Git. A migration ledger maps every subprocess-backed test to its replacement before anything is deleted, and ADR 0027 is amended to record the three-layer gate. No behavioural coverage is deleted, and no flake is masked.
On that footing, M5 completes the #23 screens in user order and in both clients over the Projection Port. Two new Projection families land first:
launch-preparation, a live read-only assessment of one complete client-owned launch draft, andharness-catalog, bounded discovery and qualification of installed Harnesses with optional exact focus. The Harness profile gains the supported-model declaration that ADR 0022's amendment already promised, and a launch carries an optional requested model that the Adapter forwards and the Run stores. Start a Run gains a model choice and a Review step that assesses the whole draft before submission, returns to the correcting step with a precise finding, and creates no Run on failure. The Run Workbench separates view freshness from Run state, handles snapshot loss on the follow and settle paths, and completes its details surface. The Bundle catalog becomes a searchable list-and-inspector screen with scrollable content and the declared Workflow step list. A new Harness catalog screen and a new headlessharnesscommand expose the same normalized Harness facts with no Action Offers. Workspace Home gains its Harnesses entry. Every TUI slice retires the applicable #23 deferred items and states which do not apply.User Stories
Test maintainer and reviewer (evidence architecture)
Run operator, Start a Run (TUI)
N of Mwith the inputs step omitted when the Bundle declares no launch inputs, so that I know how far I am from starting.View Bundle Detailsjump from the Bundle step into the Bundle catalog focused on that Bundle, with back returning to Start a Run, so that inspection does not lose my draft.QualifiedorUnavailable · authenticate with Codex first, so that I never read a raw enum.Harness defaultalways, so that I decide the model or leave it to the Harness's own configuration.launch-preparationand showChecking launchwhile it does, so that I see findings before I submit.This Bundle can no longer start,Workspace prerequisite not met,<Bundle> is no longer installed,<Harness> is no longer ready, andThe selected model is no longer available, each with remediation, so that I know what to fix.Run not startednotice that I can dismiss, so that failure is visible without trapping me.Run operator, Run Workbench (TUI)
View current,View loading,View disconnected, orView catching up, separate from the Run state, so that a stale view can never masquerade as a live Run.Reconnect, so that I can recover the view without leaving the Run.<name> was deletednotice, so that a missing subject is explained.Workflow completed,This Run has ended,You stopped at the Review checkpoint, orExecution stopped outside the Workflow, so that the state word and its colour are never the only signal.Jump to latest, so that returning to the live edge is discoverable.Checking resumebecomingResume applied, shown transiently and dismissible, so that success is as visible as failure.Run operator, Previous Runs (TUI)
No previous RunsandNo resumable Runswith a one-line explanation, so that an empty list is not mistaken for an error.Run operator, Bundle catalog (TUI)
No matching Workflow Bundleswith a hint when nothing matches, so that an empty result is explained.Run operator, Harness catalog (TUI)
No matching Harnessesand a hint when nothing matches, so that the screen stays useful as the set grows.Available,Available with limits,Unavailable, orNot checked, with limits viewable, so that I read what the Harness truthfully exposes.Headless user
harness listandharness inspect <id>with--json, so that scripts learn the same normalized Harness facts the TUI shows.harness inspectto run bounded qualification and report supported models and the six capabilities, so that automation can decide before launching.--modeloption onrun launchaccepted only for an Agent-bearing Bundle, so that scripts select the same requested model as the TUI.--modelon a Command-only Bundle rejected as irrelevant, so that a script cannot appear to select a model that was never used.run launchto read the samelaunch-preparationassessment first and, when the draft is not ready, print every finding in text and JSON and exit without submitting, so that I see all problems in one invocation.run resumeto reuse the Run's durable requested model without another flag, so that recovery cannot switch models.run show --jsonto carry the requested model additively, so that scripts can compare requested and effective models.run listandrun resumeto stay in parity with Previous Runs, so that filters and resume mean the same thing in both clients.Bundle author
Harness maintainer
Release and evidence
Implementation Decisions
Scope and ordering
HEAD. Ticket dependencies encode that order.harness-catalogbefore the Harness catalog screen, the headlessharnesscommand, and the Start a Run Harness step rewording;launch-preparationbefore the Review step and the headless pre-launch assessment.Evidence-architecture prefactor
Projection Port:
launch-preparationassessing,ready, ornot-ready; the normalized draft; the ordered findings; the generated Execution summary; and current Action Offers. Each finding names a correction target,bundle,harness,model,inputs,trust,workspace, orcommand, a code, an explanation, and a remediation, reusing the existing Problem vocabulary.launch-runcarrying the assessed draft and the trust requirement evidence. Trust remains an acknowledgement submitted with the launch; there is no separate grant Operation, and the Trust-grant order after Run creation is unchanged.Projection Port:
harness-catalogqualified,qualified-with-limits,not-ready, andnot-checked. A list open performs discovery only and spawns nothing. A focus open performs bounded qualification through the Application Harness registration's qualify path, which composition implements as prepare then immediate close, and caches the result for this process keyed the same way M4 keys Codex qualification.available,available-with-limits,unavailable, ornot-checkedand optional limits, the configuration posture, external authentication instructions when the failure is authentication, and a diagnostic reference. The six capabilities map from the profile's existing evidence-bearing fields: Session recovery from recovery, Same-Turn steering from steer, Turn interruption from interruption, Tool approvals from approvals, Structured questions from clarifications, and Effective model from the model observation capability.Harness Seam: supported models and requested model
launch-runcarries the optional requested model only when the routing contains an Agent or Interactive agent Step, and it participates in idempotent replay identity. The Run stores it durably beside the selected Harness before the first Attempt, reuses it on reopen and resume, and never changes it. Requested model and effective model remain separate facts; the Run view exposes both.Harness defaultis a valid choice meaning no requested model, so the Harness's user-owned configuration stays authoritative as M4 decided. Resume-time model change and per-Turn selection are not built.Start a Run
N of M, with Inputs omitted when the Bundle declares none and Harness omitted for a Command-only Bundle.harness-cataloglist view for its rows and wording, and shows a model field below the selected Harness: a choice list when the profile declares a list, a text field when it declares free text, withHarness defaultfirst in both cases. Choosing a Harness whose focus has not been qualified in this process triggers the bounded qualification for that Harness only.launch-preparationProjection over the complete draft and renders Workflow, Bundle digest, Workspace name and path, Harness with model, each launch input, and trust posture, with findings inline whileassessingbecomesreadyornot-ready. Start Run is available only when ready and showsChecking launchwhile the launch settles.Run not startednotice, moves to the step named by the correction target, focuses the finding, and clears only the invalidated field. A removed Bundle returns to the Bundle step; a Harness or model finding returns to the Harness step; input violations return to Inputs; trust returns to Review.View Bundle Detailsopens the Bundle catalog focused on the highlighted Bundle; back returns to the same Start a Run step with the draft intact.Run Workbench detail and freshness
(live)badge is replaced by the freshness token, and the timeline's live-edge following remains a separate scroll fact.View freshness · not Run stateand the reason.Reconnectreopens the Projection and is a read, like navigation, not an Operation.operationProjection. A subject that no longer exists returns to Previous Runs with a dismissible deleted notice.Jump to latest, truncation markers are uniform across timeline and inspection, and a failed older-page read in the inspection overlay shows a notice. Operation receipts are transient and dismissible.Previous Runs
run listandrun resumeshapes are unchanged.Bundle catalog
bundle-cataloglist snapshot; the Port gains no search selector and no fuzzy-matching dependency is added.bundle listandbundle inspectshapes are unchanged; the catalog is already listable and inspectable headlessly.Harness catalog screen and headless command
harness-catalogfamily: search over name, model, and capability, rows with name, qualification chip, summary, and observed-model count, and an inspector with facts, unavailable finding, Supported models, Capabilities, and Configuration sections. Focusing a row opens the exact-focus Projection and runs bounded qualification once per process.harness listandharness inspect <id>, each with--json.listprints discovery and last-known qualification;inspectperforms the bounded qualification and prints the focus view. Text mirrors the screen's wording; JSON prints the snapshot and is frozen from its first release. Exit codes follow the existing contract: zero on success, one on refusal.Workspace Home
Vendor boundary and dependencies
CI and gates
Testing Decisions
launch-preparationstatus transitions, every finding and its correction target, no Run or Trust grant onnot-ready, launch revalidation after truth changes, requested-model admission and durability, andharness-cataloglist-without-spawn, focus qualification, cache behaviour, and no Offers.harness listandharness inspecttext and JSON,--modelacceptance and rejection, the pre-launch assessment printing every finding and exiting without submission, ready-then-launch, resume reuse, and additive JSON fields with frozen existing ones.Out of Scope
run launch, headless Interactive agent passthrough, and prompting at a gate on an attached terminal.Further Notes
indeterminate,session-lost, andexpired-resourcedocks are rendered only as far as the Port already exposes those facts; they do not become Run states.Reconnect, search, focus, and navigation are reads, not Operations, and are the only visible controls not backed by an Offer.Owner:,Ratchet:,Deletes:,Gate:, andDependencies:and is published withoutready-for-agentuntil its packet is curated.