Skip to content

feat(B-0891): determineRunnability discriminator — Scenario → RunnabilityVerdict (zflash lane substantive work; completes 3-lane parallel discriminator pattern with PR #5758 + PR #5760)#5761

Merged
AceHack merged 1 commit into
mainfrom
otto-cli/b-0891-determine-runnability-discriminator-completes-3-lane-parallel-pattern-2026-05-28
May 28, 2026
Merged

feat(B-0891): determineRunnability discriminator — Scenario → RunnabilityVerdict (zflash lane substantive work; completes 3-lane parallel discriminator pattern with PR #5758 + PR #5760)#5761
AceHack merged 1 commit into
mainfrom
otto-cli/b-0891-determine-runnability-discriminator-completes-3-lane-parallel-pattern-2026-05-28

Conversation

@AceHack
Copy link
Copy Markdown
Member

@AceHack AceHack commented May 28, 2026

Summary

Adds determineRunnability discriminator to zflash test-harness. Completes the 3-lane parallel substrate-engineering pattern:

Lane Discriminator PR
Workflow engine determineReviewLevel #5758 (merged)
Encryption determineEncryptionPath #5760 (wait-ci)
zflash determineRunnability this PR

Same substrate-engineering substrate (Result-shaped discriminator that maps substrate-context → typed verdict) operating at 3 different substrate scopes. The 3-lane work isn't 3 independent implementations; it's the same substrate-engineering substrate from monad-propagation + asymmetric-authorship rules operating across lanes producing parallel substrate.

What this adds

  • RunnabilityVerdict discriminated union (6 variants)
  • determineRunnability(scenario, runnableUpstream): RunnabilityVerdict function
  • computeRunnableSet() convenience

Policy

Scenario id Status Verdict
initial-format composes-with-existing can-run-now (qemu-boot-test)
boot-cluster-up composes-with-existing can-run-now (qemu-full-install-test)
reformat-with-retention scaffolded blocked-on-state-preservation (persisted-kv)
reformat-from-scratch scaffolded blocked-on-test-harness-path-fork
cluster-joining scaffolded blocked-on-multi-vm-orchestration

20 tests pass / 0 fail

Composes with substrate

Test plan

  • 8 new tests + 20 total pass
  • Exhaustiveness via TS strict-mode switch on RunnabilityVerdict
  • computeRunnableSet matches composes-with-existing count
  • CI: lint(tsc tools)
  • Auto-merge armed

🤖 Generated with Claude Code

…nabilityVerdict (zflash lane substantive work; completes 3-lane parallel pattern with PR #5758 + PR #5760)

Substantive zflash-lane work per Aaron's 3-lane substrate-check (Amara ferry
§33.2 PR #5757) + standing PoC permission. Completes the 3-lane parallel
substrate-engineering pattern:
- PR #5758 — workflow-engine determineReviewLevel (workflow scope)
- PR #5760 — better-git-crypt determineEncryptionPath (encryption scope)
- This PR — zflash determineRunnability (zflash scope)

Same substrate-engineering substrate (Result-shaped discriminator that maps
substrate-context → typed verdict) operating at 3 different substrate scopes.
The 3-lane work isn't 3 independent implementations; it's the same
substrate-engineering substrate from monad-propagation + asymmetric-authorship
rules operating across lanes producing parallel substrate.

Adds:
- RunnabilityVerdict discriminated union (6 variants: can-run-now,
  blocked-on-upstream-gate, blocked-on-state-preservation,
  blocked-on-multi-vm-orchestration, blocked-on-test-harness-path-fork,
  requires-physical-usb)
- determineRunnability(scenario, runnableUpstream): RunnabilityVerdict
  function with policy mapping per existing scenarios.ts notes
- computeRunnableSet() convenience — iterates SCENARIOS reflexively to
  surface the runnable subset

Tests (8 new; 20 total):
- initial-format → can-run-now (qemu-boot-test substrate)
- boot-cluster-up → can-run-now (qemu-full-install-test)
- reformat-with-retention → blocked-on-state-preservation (persisted-kv)
- reformat-from-scratch → blocked-on-test-harness-path-fork
- cluster-joining → blocked-on-multi-vm-orchestration
- all scenarios resolve to valid RunnabilityVerdict (exhaustiveness via
  TS strict-mode switch acknowledger)
- computeRunnableSet identifies composes-with-existing scenarios
- computeRunnableSet count matches composes-with-existing count

20 tests pass / 0 fail.

Composes with substrate:
- B-0891 row (zflash test-harness 5-scenario matrix)
- B-0867.20 PR #5758 (structurally parallel discriminator)
- B-0883 PR #5760 (structurally parallel discriminator)
- PR #5757 (Amara ferry substrate-check)
- PR #5516 asymmetric-authorship + PR #5511 monad-propagation
- tools/ci/qemu-full-install-test.ts (existing harness composition target)
- tools/ci/qemu-boot-test.ts (existing harness composition target)
- tools/ci/audit-installer-iso-content.ts (existing audit composition target)

Per Aaron's 3-lane substrate-check ('so you finished the 3 lanes?'): NO,
not finished. This is incremental progress on the zflash lane; all 3 lanes
now have structurally-parallel discriminator substrate. Phase 2 actual
QEMU state-preservation / multi-VM orchestration / path-fork support
deferred per operator-authorized follow-up.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 28, 2026 10:56
@AceHack AceHack enabled auto-merge (squash) May 28, 2026 10:56
@chatgpt-codex-connector
Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@AceHack AceHack merged commit efe785e into main May 28, 2026
32 of 33 checks passed
@AceHack AceHack deleted the otto-cli/b-0891-determine-runnability-discriminator-completes-3-lane-parallel-pattern-2026-05-28 branch May 28, 2026 10:58
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new TypeScript discriminator in the zflash test harness to classify each zflash scenario’s current “runnability” as a typed verdict, alongside helper logic to compute the runnable set and accompanying tests. This follows the same “context → typed verdict” discriminator pattern used in the workflow-engine and encryption lanes.

Changes:

  • Introduces RunnabilityVerdict and determineRunnability(scenario, runnableUpstream) in tools/zflash/test-harness/scenarios.ts.
  • Adds computeRunnableSet() convenience helper for identifying scenarios that can run now.
  • Expands scenarios.test.ts with discriminator tests and a compile-time exhaustiveness “acknowledger” switch.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
tools/zflash/test-harness/scenarios.ts Adds RunnabilityVerdict, determineRunnability, and computeRunnableSet for scenario runnability classification.
tools/zflash/test-harness/scenarios.test.ts Adds tests covering the new discriminator behavior and runnable-set computation.

Comment on lines +172 to +174
* B-0891 — determineRunnability: substantive lane work per Aaron's
* 3-lane substrate-check (Amara ferry §33.2 PR #5757) + standing PoC
* permission.
Comment on lines +219 to +246
* upstream scenarios to its RunnabilityVerdict.
*
* The `runnableUpstream` set IS the substrate-state input — caller
* provides which other scenarios can currently run (typically by
* iterating SCENARIOS + checking determineRunnability output reflexively
* OR by hardcoding which composes-with-existing scenarios are wired).
*/
export function determineRunnability(
scenario: Scenario,
runnableUpstream: ReadonlySet<ScenarioId>,
): RunnabilityVerdict {
// Upstream gate check applies regardless of status — if any gate
// scenario isn't runnable, this scenario can't run end-to-end either.
const missingGates = scenario.gates.filter(
(g) => !runnableUpstream.has(g),
);
if (missingGates.length > 0 && scenario.gates.length > 0) {
// Special-case: a scenario's gates name DOWNSTREAM scenarios it
// GATES, not UPSTREAM scenarios it depends on. Per scenarios.ts
// existing scenarios: `initial-format.gates = ["boot-cluster-up"]`
// means initial-format must run BEFORE boot-cluster-up. The gate
// direction is "I gate downstream X". So missingGates here means
// "downstream scenarios I gate aren't runnable" — which doesn't
// block THIS scenario from running. Skip the gate check entirely
// for the upstream-blocking interpretation, OR reframe as "this
// scenario gates downstream X; runnability not affected."
//
// For PoC: surface gates as informational; don't block on them.
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.

2 participants