mirror of
https://github.com/stablyai/orca.git
synced 2026-10-17 16:02:55 +00:00
2057 lines
78 KiB
HTML
2057 lines
78 KiB
HTML
<!doctype html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="utf-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||
<meta
|
||
name="description"
|
||
content="Implementation and validation plan for distributing Orca's self-contained SSH relay through GitHub Releases."
|
||
/>
|
||
<title>SSH relay distribution plan · Orca</title>
|
||
<style>
|
||
@font-face {
|
||
font-family: 'Geist';
|
||
src: url('../../../src/renderer/src/assets/fonts/Geist-Variable.woff2') format('woff2');
|
||
font-weight: 100 900;
|
||
font-style: normal;
|
||
font-display: swap;
|
||
}
|
||
|
||
:root {
|
||
color-scheme: light dark;
|
||
--background: #fff;
|
||
--foreground: #0a0a0a;
|
||
--card: #fff;
|
||
--card-foreground: #0a0a0a;
|
||
--primary: #171717;
|
||
--primary-foreground: #fafafa;
|
||
--secondary: #f5f5f5;
|
||
--secondary-foreground: #171717;
|
||
--muted: #f5f5f5;
|
||
--muted-foreground: #737373;
|
||
--accent: #f5f5f5;
|
||
--accent-foreground: #171717;
|
||
--destructive: #e40014;
|
||
--border: #e5e5e5;
|
||
--ring: #a1a1a1;
|
||
--status-success: #15803d;
|
||
--annotation-highlight: #f59e0b;
|
||
--radius: 0.625rem;
|
||
--font-sans: 'Geist', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
||
--font-mono:
|
||
'SF Mono', SFMono-Regular, ui-monospace, 'Cascadia Code', Menlo, Consolas,
|
||
'Liberation Mono', monospace;
|
||
}
|
||
|
||
@media (prefers-color-scheme: dark) {
|
||
:root {
|
||
--background: #0a0a0a;
|
||
--foreground: #fafafa;
|
||
--card: #171717;
|
||
--card-foreground: #fafafa;
|
||
--primary: #e5e5e5;
|
||
--primary-foreground: #171717;
|
||
--secondary: #262626;
|
||
--secondary-foreground: #fafafa;
|
||
--muted: #262626;
|
||
--muted-foreground: #a1a1a1;
|
||
--accent: #404040;
|
||
--accent-foreground: #fafafa;
|
||
--destructive: #ff6568;
|
||
--border: rgb(255 255 255 / 0.07);
|
||
--ring: #737373;
|
||
--status-success: #86efac;
|
||
--annotation-highlight: #fbbf24;
|
||
}
|
||
}
|
||
|
||
* {
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
html {
|
||
scroll-behavior: smooth;
|
||
}
|
||
|
||
body {
|
||
margin: 0;
|
||
background: var(--background);
|
||
color: var(--foreground);
|
||
font-family: var(--font-sans);
|
||
font-size: 14px;
|
||
line-height: 1.55;
|
||
letter-spacing: 0.01em;
|
||
}
|
||
|
||
a {
|
||
color: inherit;
|
||
text-decoration-color: var(--ring);
|
||
text-underline-offset: 3px;
|
||
}
|
||
|
||
a:hover {
|
||
text-decoration-color: currentColor;
|
||
}
|
||
|
||
a:focus-visible,
|
||
summary:focus-visible,
|
||
.table-wrap:focus-visible {
|
||
border-radius: calc(var(--radius) * 0.6);
|
||
outline: 2px solid var(--ring);
|
||
outline-offset: 3px;
|
||
}
|
||
|
||
code,
|
||
pre {
|
||
font-family: var(--font-mono);
|
||
}
|
||
|
||
code {
|
||
border: 1px solid var(--border);
|
||
border-radius: calc(var(--radius) * 0.6);
|
||
background: var(--muted);
|
||
padding: 0.08rem 0.3rem;
|
||
font-size: 0.86em;
|
||
}
|
||
|
||
.shell {
|
||
display: grid;
|
||
grid-template-columns: 248px minmax(0, 1fr);
|
||
min-height: 100vh;
|
||
}
|
||
|
||
.sidebar {
|
||
position: sticky;
|
||
top: 0;
|
||
height: 100vh;
|
||
overflow-y: auto;
|
||
border-right: 1px solid var(--border);
|
||
background: var(--card);
|
||
padding: 28px 20px;
|
||
}
|
||
|
||
.brand {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
margin-bottom: 28px;
|
||
font-weight: 650;
|
||
}
|
||
|
||
.brand-mark {
|
||
display: grid;
|
||
width: 28px;
|
||
height: 28px;
|
||
place-items: center;
|
||
border-radius: calc(var(--radius) * 0.8);
|
||
background: var(--primary);
|
||
color: var(--primary-foreground);
|
||
font-size: 12px;
|
||
letter-spacing: 0;
|
||
}
|
||
|
||
.eyebrow,
|
||
.nav-heading,
|
||
.section-kicker {
|
||
color: var(--muted-foreground);
|
||
font-size: 11px;
|
||
font-weight: 650;
|
||
letter-spacing: 0.05em;
|
||
text-transform: uppercase;
|
||
}
|
||
|
||
.nav-heading {
|
||
margin: 22px 10px 8px;
|
||
}
|
||
|
||
nav a {
|
||
display: block;
|
||
border-radius: calc(var(--radius) * 0.8);
|
||
padding: 7px 10px;
|
||
color: var(--muted-foreground);
|
||
font-size: 13px;
|
||
text-decoration: none;
|
||
}
|
||
|
||
nav a:hover {
|
||
background: var(--accent);
|
||
color: var(--accent-foreground);
|
||
}
|
||
|
||
main {
|
||
width: min(1080px, 100%);
|
||
margin: 0 auto;
|
||
padding: 64px 56px 96px;
|
||
}
|
||
|
||
header {
|
||
padding-bottom: 42px;
|
||
}
|
||
|
||
.meta-row,
|
||
.pill-row {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 8px;
|
||
align-items: center;
|
||
}
|
||
|
||
.meta-row {
|
||
justify-content: space-between;
|
||
margin-bottom: 26px;
|
||
}
|
||
|
||
.pill {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
min-height: 24px;
|
||
border: 1px solid var(--border);
|
||
border-radius: 999px;
|
||
background: var(--secondary);
|
||
padding: 2px 9px;
|
||
color: var(--secondary-foreground);
|
||
font-size: 11px;
|
||
font-weight: 600;
|
||
}
|
||
|
||
h1,
|
||
h2,
|
||
h3,
|
||
p {
|
||
margin-top: 0;
|
||
}
|
||
|
||
h1 {
|
||
max-width: 850px;
|
||
margin-bottom: 18px;
|
||
font-size: clamp(2.15rem, 5vw, 4.25rem);
|
||
font-weight: 680;
|
||
letter-spacing: -0.045em;
|
||
line-height: 0.98;
|
||
}
|
||
|
||
h2 {
|
||
margin-bottom: 12px;
|
||
font-size: 1.55rem;
|
||
font-weight: 650;
|
||
letter-spacing: -0.025em;
|
||
line-height: 1.2;
|
||
}
|
||
|
||
h3 {
|
||
margin-bottom: 8px;
|
||
font-size: 1rem;
|
||
font-weight: 650;
|
||
letter-spacing: -0.01em;
|
||
}
|
||
|
||
.lede {
|
||
max-width: 780px;
|
||
margin-bottom: 24px;
|
||
color: var(--muted-foreground);
|
||
font-size: 1.08rem;
|
||
}
|
||
|
||
.decision {
|
||
display: grid;
|
||
grid-template-columns: auto minmax(0, 1fr);
|
||
gap: 14px;
|
||
max-width: 820px;
|
||
border: 1px solid var(--border);
|
||
border-radius: calc(var(--radius) * 1.4);
|
||
background: var(--card);
|
||
padding: 18px;
|
||
}
|
||
|
||
.decision-index,
|
||
.phase-index {
|
||
display: grid;
|
||
width: 30px;
|
||
height: 30px;
|
||
flex: 0 0 auto;
|
||
place-items: center;
|
||
border-radius: 999px;
|
||
background: var(--primary);
|
||
color: var(--primary-foreground);
|
||
font-family: var(--font-mono);
|
||
font-size: 11px;
|
||
font-weight: 700;
|
||
}
|
||
|
||
.decision p,
|
||
.phase p,
|
||
.risk p {
|
||
margin-bottom: 0;
|
||
color: var(--muted-foreground);
|
||
}
|
||
|
||
section {
|
||
scroll-margin-top: 28px;
|
||
border-top: 1px solid var(--border);
|
||
padding: 52px 0;
|
||
}
|
||
|
||
.section-heading {
|
||
display: grid;
|
||
grid-template-columns: minmax(0, 1fr) minmax(240px, 0.72fr);
|
||
gap: 40px;
|
||
align-items: end;
|
||
margin-bottom: 28px;
|
||
}
|
||
|
||
.section-heading p {
|
||
margin-bottom: 0;
|
||
color: var(--muted-foreground);
|
||
}
|
||
|
||
.architecture {
|
||
display: grid;
|
||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||
gap: 10px;
|
||
align-items: stretch;
|
||
margin: 0;
|
||
padding: 0;
|
||
list-style: none;
|
||
}
|
||
|
||
.architecture-step {
|
||
position: relative;
|
||
min-height: 150px;
|
||
border: 1px solid var(--border);
|
||
border-radius: calc(var(--radius) * 1.4);
|
||
background: var(--card);
|
||
padding: 18px;
|
||
}
|
||
|
||
.architecture-step:not(:last-child)::after {
|
||
position: absolute;
|
||
z-index: 2;
|
||
top: 50%;
|
||
right: -16px;
|
||
width: 20px;
|
||
border-top: 1px solid var(--ring);
|
||
content: '';
|
||
}
|
||
|
||
.architecture-step strong {
|
||
display: block;
|
||
margin: 18px 0 7px;
|
||
}
|
||
|
||
.architecture-step p {
|
||
margin: 0;
|
||
color: var(--muted-foreground);
|
||
font-size: 12px;
|
||
}
|
||
|
||
.step-number {
|
||
color: var(--muted-foreground);
|
||
font-family: var(--font-mono);
|
||
font-size: 11px;
|
||
}
|
||
|
||
.callout {
|
||
margin-top: 18px;
|
||
border-left: 3px solid var(--annotation-highlight);
|
||
background: color-mix(in srgb, var(--annotation-highlight) 8%, transparent);
|
||
padding: 14px 16px;
|
||
}
|
||
|
||
.callout strong {
|
||
display: block;
|
||
margin-bottom: 4px;
|
||
}
|
||
|
||
.callout p {
|
||
margin: 0;
|
||
color: var(--muted-foreground);
|
||
}
|
||
|
||
.comparison {
|
||
display: grid;
|
||
grid-template-columns: 1fr 1fr;
|
||
gap: 16px;
|
||
}
|
||
|
||
.comparison article,
|
||
.risk,
|
||
details {
|
||
border: 1px solid var(--border);
|
||
border-radius: calc(var(--radius) * 1.4);
|
||
background: var(--card);
|
||
}
|
||
|
||
.comparison article,
|
||
.risk {
|
||
padding: 20px;
|
||
}
|
||
|
||
.comparison ul,
|
||
.phase ul,
|
||
.gate-list,
|
||
.definition-list {
|
||
margin: 12px 0 0;
|
||
padding-left: 20px;
|
||
}
|
||
|
||
li + li {
|
||
margin-top: 7px;
|
||
}
|
||
|
||
.phases {
|
||
display: grid;
|
||
gap: 12px;
|
||
}
|
||
|
||
.phase {
|
||
display: grid;
|
||
grid-template-columns: auto minmax(0, 1fr) minmax(140px, 0.25fr);
|
||
gap: 16px;
|
||
align-items: start;
|
||
border: 1px solid var(--border);
|
||
border-radius: calc(var(--radius) * 1.4);
|
||
background: var(--card);
|
||
padding: 20px;
|
||
}
|
||
|
||
.phase-output {
|
||
border-left: 1px solid var(--border);
|
||
padding-left: 16px;
|
||
color: var(--muted-foreground);
|
||
font-size: 12px;
|
||
}
|
||
|
||
.phase-output strong {
|
||
display: block;
|
||
margin-bottom: 4px;
|
||
color: var(--foreground);
|
||
}
|
||
|
||
.table-wrap {
|
||
overflow-x: auto;
|
||
border: 1px solid var(--border);
|
||
border-radius: calc(var(--radius) * 1.4);
|
||
}
|
||
|
||
table {
|
||
width: 100%;
|
||
border-collapse: collapse;
|
||
background: var(--card);
|
||
font-size: 13px;
|
||
}
|
||
|
||
.visually-hidden {
|
||
position: absolute;
|
||
width: 1px;
|
||
height: 1px;
|
||
overflow: hidden;
|
||
clip: rect(0 0 0 0);
|
||
clip-path: inset(50%);
|
||
white-space: nowrap;
|
||
}
|
||
|
||
th,
|
||
td {
|
||
border-bottom: 1px solid var(--border);
|
||
padding: 13px 14px;
|
||
text-align: left;
|
||
vertical-align: top;
|
||
}
|
||
|
||
th {
|
||
background: var(--muted);
|
||
color: var(--muted-foreground);
|
||
font-size: 11px;
|
||
font-weight: 650;
|
||
letter-spacing: 0.05em;
|
||
text-transform: uppercase;
|
||
}
|
||
|
||
tr:last-child td {
|
||
border-bottom: 0;
|
||
}
|
||
|
||
td:first-child {
|
||
font-weight: 620;
|
||
}
|
||
|
||
.status-required {
|
||
color: var(--status-success);
|
||
font-weight: 650;
|
||
}
|
||
|
||
.status-blocked {
|
||
color: var(--destructive);
|
||
font-weight: 650;
|
||
}
|
||
|
||
.artifact-grid,
|
||
.risk-grid,
|
||
.gate-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||
gap: 14px;
|
||
}
|
||
|
||
.artifact {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
gap: 12px;
|
||
border-bottom: 1px solid var(--border);
|
||
padding: 10px 0;
|
||
}
|
||
|
||
.artifact code {
|
||
border: 0;
|
||
background: transparent;
|
||
padding: 0;
|
||
}
|
||
|
||
details {
|
||
overflow: hidden;
|
||
}
|
||
|
||
details + details {
|
||
margin-top: 10px;
|
||
}
|
||
|
||
summary {
|
||
cursor: pointer;
|
||
padding: 15px 18px;
|
||
font-weight: 620;
|
||
}
|
||
|
||
details[open] summary {
|
||
border-bottom: 1px solid var(--border);
|
||
background: var(--muted);
|
||
}
|
||
|
||
.details-body {
|
||
padding: 18px;
|
||
}
|
||
|
||
.details-body p:last-child,
|
||
.details-body ul:last-child {
|
||
margin-bottom: 0;
|
||
}
|
||
|
||
.gate {
|
||
border-top: 2px solid var(--foreground);
|
||
background: var(--card);
|
||
padding: 18px 0 0;
|
||
}
|
||
|
||
.subsection-heading {
|
||
margin-top: 28px;
|
||
}
|
||
|
||
.gate small {
|
||
color: var(--muted-foreground);
|
||
}
|
||
|
||
.risk strong {
|
||
display: block;
|
||
margin-bottom: 7px;
|
||
}
|
||
|
||
.rollout {
|
||
display: grid;
|
||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||
gap: 0;
|
||
}
|
||
|
||
.rollout-step {
|
||
position: relative;
|
||
border-top: 1px solid var(--ring);
|
||
padding: 24px 20px 0 0;
|
||
}
|
||
|
||
.rollout-step::before {
|
||
position: absolute;
|
||
top: -5px;
|
||
left: 0;
|
||
width: 9px;
|
||
height: 9px;
|
||
border-radius: 999px;
|
||
background: var(--foreground);
|
||
content: '';
|
||
}
|
||
|
||
.rollout-step p {
|
||
color: var(--muted-foreground);
|
||
font-size: 12px;
|
||
}
|
||
|
||
.source-list {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 8px;
|
||
margin: 0;
|
||
padding: 0;
|
||
list-style: none;
|
||
}
|
||
|
||
.source-list a {
|
||
display: inline-flex;
|
||
min-height: 32px;
|
||
align-items: center;
|
||
border: 1px solid var(--border);
|
||
border-radius: calc(var(--radius) * 0.8);
|
||
background: var(--card);
|
||
padding: 5px 10px;
|
||
text-decoration: none;
|
||
}
|
||
|
||
.source-list a:hover {
|
||
background: var(--accent);
|
||
}
|
||
|
||
footer {
|
||
border-top: 1px solid var(--border);
|
||
padding-top: 28px;
|
||
color: var(--muted-foreground);
|
||
font-size: 12px;
|
||
}
|
||
|
||
@media (max-width: 900px) {
|
||
.shell {
|
||
display: block;
|
||
}
|
||
|
||
.sidebar {
|
||
position: static;
|
||
width: 100%;
|
||
height: auto;
|
||
border-right: 0;
|
||
border-bottom: 1px solid var(--border);
|
||
padding: 18px 24px;
|
||
}
|
||
|
||
.brand {
|
||
margin-bottom: 12px;
|
||
}
|
||
|
||
.nav-heading {
|
||
display: none;
|
||
}
|
||
|
||
nav {
|
||
display: flex;
|
||
gap: 4px;
|
||
overflow-x: auto;
|
||
padding-bottom: 2px;
|
||
}
|
||
|
||
nav a {
|
||
flex: 0 0 auto;
|
||
}
|
||
|
||
main {
|
||
padding: 48px 28px 72px;
|
||
}
|
||
|
||
.section-heading,
|
||
.architecture,
|
||
.rollout {
|
||
grid-template-columns: 1fr 1fr;
|
||
}
|
||
|
||
.architecture-step:not(:last-child)::after {
|
||
display: none;
|
||
}
|
||
}
|
||
|
||
@media (max-width: 640px) {
|
||
main {
|
||
padding-inline: 18px;
|
||
}
|
||
|
||
.section-heading,
|
||
.architecture,
|
||
.comparison,
|
||
.artifact-grid,
|
||
.risk-grid,
|
||
.gate-grid,
|
||
.rollout {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.phase {
|
||
grid-template-columns: auto minmax(0, 1fr);
|
||
}
|
||
|
||
.phase-output {
|
||
grid-column: 2;
|
||
border-top: 1px solid var(--border);
|
||
border-left: 0;
|
||
padding: 12px 0 0;
|
||
}
|
||
}
|
||
|
||
@media (prefers-reduced-motion: reduce) {
|
||
html {
|
||
scroll-behavior: auto;
|
||
}
|
||
}
|
||
|
||
@media print {
|
||
:root {
|
||
color-scheme: light;
|
||
}
|
||
|
||
.shell {
|
||
display: block;
|
||
}
|
||
|
||
.sidebar {
|
||
display: none;
|
||
}
|
||
|
||
main {
|
||
width: 100%;
|
||
padding: 0;
|
||
}
|
||
|
||
body {
|
||
print-color-adjust: exact;
|
||
-webkit-print-color-adjust: exact;
|
||
}
|
||
|
||
.phase,
|
||
.risk,
|
||
.architecture-step,
|
||
.comparison article,
|
||
.gate,
|
||
.rollout-step {
|
||
break-inside: avoid;
|
||
}
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="shell">
|
||
<aside class="sidebar" aria-label="Plan navigation">
|
||
<div class="brand">
|
||
<span class="brand-mark" aria-hidden="true">O</span>
|
||
<span>Orca engineering</span>
|
||
</div>
|
||
<div class="nav-heading">Plan</div>
|
||
<nav aria-label="Plan sections">
|
||
<a href="#decision">Decision</a>
|
||
<a href="#architecture">Architecture</a>
|
||
<a href="#phases">Implementation</a>
|
||
<a href="#artifacts">Artifacts</a>
|
||
<a href="#fallback">Fallback</a>
|
||
<a href="#validation">Validation</a>
|
||
<a href="#risks">Risks</a>
|
||
<a href="#rollout">Rollout</a>
|
||
<a href="#done">Definition of done</a>
|
||
</nav>
|
||
<div class="nav-heading">Context</div>
|
||
<nav aria-label="Related issues">
|
||
<a href="https://github.com/stablyai/orca/issues/8450">Issue #8450</a>
|
||
<a href="https://github.com/stablyai/orca/issues/1693">Issue #1693</a>
|
||
</nav>
|
||
</aside>
|
||
|
||
<main>
|
||
<header id="decision">
|
||
<div class="meta-row">
|
||
<span class="eyebrow">Implementation plan · 14 July 2026</span>
|
||
<div class="pill-row" role="list" aria-label="Plan status">
|
||
<span class="pill" role="listitem">Draft</span>
|
||
<span class="pill" role="listitem">SSH relay</span>
|
||
<span class="pill" role="listitem">Regression gated</span>
|
||
</div>
|
||
</div>
|
||
<h1>Ship the relay as a verified runtime, not a remote npm project.</h1>
|
||
<p class="lede">
|
||
Publish self-contained, platform-specific relay runtimes through the same GitHub Release
|
||
used by the Orca desktop app. Orca downloads and verifies the matching runtime locally,
|
||
transfers it over the existing SSH connection, and launches it from an immutable remote
|
||
cache.
|
||
</p>
|
||
<div class="decision">
|
||
<span class="decision-index" aria-hidden="true">✓</span>
|
||
<div>
|
||
<h3>Recommended decision</h3>
|
||
<p>
|
||
Make the verified runtime the primary path, keep the existing embedded relay plus
|
||
remote Node/npm installer as an automatic fallback only for classified availability
|
||
and compatibility failures, and remove or narrow that fallback only after the
|
||
complete declared support matrix has passed and soaked. Build and sign relay
|
||
artifacts before desktop packaging so every app embeds the exact signed
|
||
tuple-to-content manifest needed for offline remote-cache reuse.
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</header>
|
||
|
||
<section id="architecture">
|
||
<div class="section-heading">
|
||
<div>
|
||
<div class="section-kicker">Target architecture</div>
|
||
<h2>The SSH host never needs GitHub access.</h2>
|
||
</div>
|
||
<p>
|
||
The desktop owns release access, signature verification, caching, and extraction. SSH
|
||
authentication/connection and relay RPC transport stay unchanged. Bootstrap artifact
|
||
transfer is materially redesigned, independently gated, and still travels only through
|
||
the authenticated SSH connection.
|
||
</p>
|
||
</div>
|
||
|
||
<ol class="architecture" aria-label="Relay artifact delivery flow">
|
||
<li class="architecture-step">
|
||
<span class="step-number">01</span>
|
||
<strong>GitHub Release</strong>
|
||
<p>
|
||
Relay build precedes desktop builds and emits the signed manifest plus exact
|
||
archives.
|
||
</p>
|
||
</li>
|
||
<li class="architecture-step">
|
||
<span class="step-number">02</span>
|
||
<strong>Local cache</strong>
|
||
<p>
|
||
Embedded manifest resolves identity offline; downloaded bytes are verified and
|
||
extracted atomically.
|
||
</p>
|
||
</li>
|
||
<li class="architecture-step">
|
||
<span class="step-number">03</span>
|
||
<strong>SSH transfer</strong>
|
||
<p>Bounded streaming over SFTP or system SSH; remote tar is an optional fast path.</p>
|
||
</li>
|
||
<li class="architecture-step">
|
||
<span class="step-number">04</span>
|
||
<strong>Remote cache</strong>
|
||
<p>
|
||
Match the embedded content ID, verify transferred files once, record proof, then
|
||
launch.
|
||
</p>
|
||
</li>
|
||
</ol>
|
||
|
||
<div class="callout">
|
||
<strong>What “100% validated” means</strong>
|
||
<p>
|
||
Every required cell in the declared two-layer, risk-based matrix has evidence. It does
|
||
not mean every possible client × SSH server combination. A tuple without
|
||
real-environment proof stays on the legacy path and is not enabled by default.
|
||
</p>
|
||
</div>
|
||
</section>
|
||
|
||
<section id="baseline">
|
||
<div class="section-heading">
|
||
<div>
|
||
<div class="section-kicker">Baseline</div>
|
||
<h2>Change the dependency boundary without changing relay behavior.</h2>
|
||
</div>
|
||
<p>
|
||
The protocol, SSH authentication/connection, relay RPC transport, immutable install
|
||
directories, locks, reconnect logic, and garbage collection stay in place. Packaging
|
||
and bootstrap artifact transfer are the moving parts.
|
||
</p>
|
||
</div>
|
||
|
||
<div class="comparison">
|
||
<article>
|
||
<h3>Today</h3>
|
||
<ul>
|
||
<li>Orca embeds platform-neutral relay JavaScript.</li>
|
||
<li>The remote supplies Node and npm.</li>
|
||
<li>Remote npm installs <code>node-pty</code> and <code>@parcel/watcher</code>.</li>
|
||
<li>Linux may require Python, make, a compiler, and registry access.</li>
|
||
<li>Incomplete Node/npm pairs reproduce issue #8450.</li>
|
||
</ul>
|
||
</article>
|
||
<article>
|
||
<h3>Target</h3>
|
||
<ul>
|
||
<li>GitHub stores a complete, signed relay runtime per tuple.</li>
|
||
<li>The desktop downloads, verifies, and caches it.</li>
|
||
<li>
|
||
POSIX targets require a declared POSIX <code>sh</code>/byte-stream/file-operation
|
||
baseline; Windows targets require a declared PowerShell/.NET baseline.
|
||
</li>
|
||
<li>
|
||
The authenticated account needs permission to write and execute; Node, Python,
|
||
npm, and tar are not prerequisites.
|
||
</li>
|
||
<li>Bundled Node loads native modules built against that exact runtime.</li>
|
||
<li>The existing installer remains available if compatibility probing fails.</li>
|
||
</ul>
|
||
</article>
|
||
</div>
|
||
</section>
|
||
|
||
<section id="phases">
|
||
<div class="section-heading">
|
||
<div>
|
||
<div class="section-kicker">Implementation</div>
|
||
<h2>Eight reviewable phases, no big-bang switch.</h2>
|
||
</div>
|
||
<p>
|
||
Each phase has an independently testable output. Early phases add evidence and
|
||
artifacts without changing the default SSH connection path.
|
||
</p>
|
||
</div>
|
||
|
||
<div class="phases">
|
||
<article class="phase">
|
||
<span class="phase-index">0</span>
|
||
<div>
|
||
<h3>Stabilize the legacy fallback</h3>
|
||
<p>
|
||
Finish the narrow #8450 change so Node and npm are selected as one coherent
|
||
toolchain. Keep it separate from runtime distribution so affected users receive a
|
||
small, reviewable fix first.
|
||
</p>
|
||
</div>
|
||
<div class="phase-output">
|
||
<strong>Output</strong>Legacy bootstrap handles the reported NVM layout.
|
||
</div>
|
||
</article>
|
||
|
||
<article class="phase">
|
||
<span class="phase-index">1</span>
|
||
<div>
|
||
<h3>Define the runtime contract</h3>
|
||
<p>
|
||
Specify archive layout, manifest schema, platform/libc selection, Node version,
|
||
protocol identity, dependency versions, licenses, file modes, support baselines,
|
||
and exact POSIX/Windows bootstrap primitives. Hash the full runtime contents
|
||
rather than only relay JavaScript.
|
||
</p>
|
||
</div>
|
||
<div class="phase-output">
|
||
<strong>Output</strong>Versioned schema plus pure selector and identity tests.
|
||
</div>
|
||
</article>
|
||
|
||
<article class="phase">
|
||
<span class="phase-index">2</span>
|
||
<div>
|
||
<h3>Build self-contained runtimes</h3>
|
||
<p>
|
||
Assemble pinned Node, relay entries, patched <code>node-pty</code>, the exact
|
||
<code>@parcel/watcher</code> package, and required JavaScript dependencies on
|
||
matching CI environments. Run executable smoke probes before archiving.
|
||
</p>
|
||
</div>
|
||
<div class="phase-output">
|
||
<strong>Output</strong>Locally verifiable archives for every enabled tuple.
|
||
</div>
|
||
</article>
|
||
|
||
<article class="phase">
|
||
<span class="phase-index">3</span>
|
||
<div>
|
||
<h3>Sign and publish release assets</h3>
|
||
<p>
|
||
Use target-native relay build jobs plus native signing jobs. A fail-closed
|
||
aggregate job waits for every signed macOS/Windows byte, computes final hashes,
|
||
signs the canonical manifest, and makes its immutable output a prerequisite of
|
||
every desktop packaging job. Upload those exact archives, manifest, and signature
|
||
to the existing draft GitHub Release. Extend the required-assets gate to verify
|
||
presence, size, signature, manifest coverage, byte identity, and read-back before
|
||
publication; timeout, signing failure, exhausted retry, or manual-approval failure
|
||
leaves a recoverable draft and blocks every consumer.
|
||
</p>
|
||
</div>
|
||
<div class="phase-output">
|
||
<strong>Output</strong>Atomic app-and-relay release publication.
|
||
</div>
|
||
</article>
|
||
|
||
<article class="phase">
|
||
<span class="phase-index">4</span>
|
||
<div>
|
||
<h3>Add the desktop artifact resolver</h3>
|
||
<p>
|
||
Resolve the remote tuple and content ID from the embedded signed manifest, use its
|
||
exact build tag and direct release URL, download through Electron networking,
|
||
verify before extraction, and atomically populate a content-addressed cache.
|
||
Coordinate cache ownership across app processes and preserve
|
||
<code>ORCA_RELAY_PATH</code> for development.
|
||
</p>
|
||
</div>
|
||
<div class="phase-output">
|
||
<strong>Output</strong>Safe cold, warm, concurrent, and offline cache paths.
|
||
</div>
|
||
</article>
|
||
|
||
<article class="phase">
|
||
<span class="phase-index">5</span>
|
||
<div>
|
||
<h3>Deploy and validate the runtime</h3>
|
||
<p>
|
||
Replace whole-tree buffering and serial-only assumptions with bounded file
|
||
streaming: capability-probed tar may accelerate POSIX system SSH, but no-tar file
|
||
streaming is required and uses the SSH channel as a byte-preserving stdin stream
|
||
into exclusive per-file staging with only the declared shell/file primitives;
|
||
Windows uses a bounded binary PowerShell/.NET path and must not materialize the
|
||
runtime as one JSON/base64 buffer; SFTP uses bounded concurrency. After locally
|
||
verifying signed metadata and archive/tree hashes, transfer through authenticated
|
||
SSH, restore every declared executable bit, then execute the transferred bundled
|
||
Node to hash the entire staging tree. Verify the full tree, run bundled
|
||
Node/native-module and minimal PTY/watcher probes, write a structured
|
||
<code>.install-complete</code> containing schema, mode, and digest, atomically
|
||
publish the immutable install, and only then launch. Preserve current locks,
|
||
reconnect, and garbage collection.
|
||
</p>
|
||
</div>
|
||
<div class="phase-output">
|
||
<strong>Output</strong>Primary path performs no remote npm or HTTP operation.
|
||
</div>
|
||
</article>
|
||
|
||
<article class="phase">
|
||
<span class="phase-index">6</span>
|
||
<div>
|
||
<h3>Make fallback explicit and observable</h3>
|
||
<p>
|
||
Add <code>auto</code>, <code>bundled</code>, and <code>legacy</code> modes. The
|
||
public Beta is a per-SSH-target <code>bundled-auto</code> choice that maps to
|
||
<code>auto</code>; absent or unknown configuration maps to <code>legacy</code>,
|
||
and forced <code>bundled</code> remains an engineering/support diagnostic. Record
|
||
privacy-safe stage and fallback reason codes in diagnostics, without hostnames,
|
||
usernames, or paths. Give every stage a budget and shared AbortSignal. Before
|
||
fallback, cancel and await all download, extraction, upload, and probe work.
|
||
Bundled and legacy installs use distinct identities, locks, and sentinels so late
|
||
work cannot mutate the other mode. Only availability/compatibility failures may
|
||
enter proven legacy behavior in <code>auto</code>; signature, hash,
|
||
archive-safety, or native-signature failures fail closed without automatic mode
|
||
switching.
|
||
</p>
|
||
</div>
|
||
<div class="phase-output">
|
||
<strong>Output</strong>Automatic recovery plus a support escape hatch.
|
||
</div>
|
||
</article>
|
||
|
||
<article class="phase">
|
||
<span class="phase-index">7</span>
|
||
<div>
|
||
<h3>Gate rollout by evidence</h3>
|
||
<p>
|
||
Publish assets before consuming them, then ship the per-target Beta through RC and
|
||
stable while every target remains on legacy unless explicitly opted in. Any
|
||
default-on RC or stable promotion requires a separate reviewed decision. Enable
|
||
only tuples with complete live evidence; keep the fallback through at least two
|
||
stable cycles.
|
||
</p>
|
||
</div>
|
||
<div class="phase-output">
|
||
<strong>Output</strong>Reversible rollout with per-tuple promotion.
|
||
</div>
|
||
</article>
|
||
</div>
|
||
</section>
|
||
|
||
<section id="artifacts">
|
||
<div class="section-heading">
|
||
<div>
|
||
<div class="section-kicker">Artifact contract</div>
|
||
<h2>Build for the runtime, architecture, and libc together.</h2>
|
||
</div>
|
||
<p>
|
||
Bundling Node with its native modules removes ABI ambiguity. Linux libc remains a
|
||
separate compatibility boundary and must be detected before artifact selection.
|
||
</p>
|
||
</div>
|
||
|
||
<div class="artifact-grid">
|
||
<div>
|
||
<div class="artifact">
|
||
<code>linux-x64-glibc</code><span>Decision-gated candidate</span>
|
||
</div>
|
||
<div class="artifact">
|
||
<code>linux-arm64-glibc</code><span>Decision-gated candidate</span>
|
||
</div>
|
||
<div class="artifact">
|
||
<code>linux-x64-musl</code><span>Legacy-only; Orca build required</span>
|
||
</div>
|
||
<div class="artifact">
|
||
<code>linux-arm64-musl</code><span>Legacy-only; Orca build required</span>
|
||
</div>
|
||
</div>
|
||
<div>
|
||
<div class="artifact">
|
||
<code>darwin-x64</code><span>Decision-gated candidate</span>
|
||
</div>
|
||
<div class="artifact">
|
||
<code>darwin-arm64</code><span>Decision-gated candidate</span>
|
||
</div>
|
||
<div class="artifact">
|
||
<code>win32-x64</code><span>Decision-gated candidate</span>
|
||
</div>
|
||
<div class="artifact">
|
||
<code>win32-arm64</code><span>Decision-gated candidate</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="callout">
|
||
<strong>Legacy families are not bundled evidence</strong>
|
||
<p>
|
||
Current source recognizes Linux, macOS, and Windows remotes on x64 and arm64 and uses
|
||
coherent remote Node/npm plus the remote native-install path. Linux legacy identity
|
||
does not distinguish glibc from musl. The bundled selector introduces that distinction
|
||
and starts with musl disabled. A source-declared family or passing unit test is not a
|
||
fallback claim: this project currently has live legacy evidence only for Ubuntu 24.04
|
||
arm64 over built-in SSH2/SFTP, so every other fallback cell remains open.
|
||
</p>
|
||
</div>
|
||
|
||
<div class="callout">
|
||
<strong>Promotion rule</strong>
|
||
<p>
|
||
Milestone 1 starts with no declared bundled tuples and decides which candidates become
|
||
enabled. Once enabled, a tuple blocks release if its asset or live proof is missing.
|
||
Candidates awaiting a trustworthy Node runtime source or real hardware remain
|
||
supported only if their legacy E2E still proves current behavior. Otherwise they stay
|
||
ineligible for rollout rather than being silently claimed as supported.
|
||
</p>
|
||
</div>
|
||
|
||
<div class="callout">
|
||
<strong>Initial immutable runtime baseline</strong>
|
||
<p>
|
||
The first contract pins unchanged official Node v24.18.0 LTS binaries. Linux glibc
|
||
candidates require kernel 4.18, glibc 2.28, and libstdc++ 6.0.25 with
|
||
<code>GLIBCXX_3.4.25</code>; macOS candidates require 13.5. Initial Windows x64
|
||
candidates require Windows 10 22H2 build 19045 or Server 2022 build 20348, and arm64
|
||
requires Windows 11 24H2 build 26100. Windows bootstrap additionally requires OpenSSH
|
||
for Windows 8.1p1, Windows PowerShell 5.1, and .NET Framework 4.8.
|
||
</p>
|
||
<p>
|
||
Node's detached checksum signature is verified against a build-input-pinned official
|
||
release keyring before extraction. Musl has no accepted official binary for this
|
||
package, so musl remains legacy-only until Orca owns and proves a target-native source
|
||
build. Rosetta-translated shells remain legacy until the x64 artifact passes a live
|
||
Rosetta SSH cell. These are selector eligibility constraints, not tuple enablement;
|
||
every candidate still needs the complete two-layer evidence.
|
||
</p>
|
||
<p>
|
||
Windows target-native native-module builds use three immutable inputs authenticated by
|
||
that same signed checksum document: the tuple's official Node ZIP, the exact-version
|
||
<code>headers.tar.gz</code>, and the tuple's <code>win-*/node.lib</code>. The Windows
|
||
ZIP does not contain build headers or the import library. Stage only the required
|
||
executable, license, headers, and import library into the local build root; disable
|
||
implicit <code>node-gyp</code> downloads so no unrecorded build input can enter.
|
||
</p>
|
||
</div>
|
||
|
||
<details open>
|
||
<summary>Archive contents</summary>
|
||
<div class="details-body">
|
||
<ul>
|
||
<li>
|
||
Unmodified official Node v24.18.0 executable pinned by its signed binary-archive
|
||
hash. Windows native builds additionally authenticate the signed headers archive
|
||
and architecture-specific <code>node.lib</code>, neither of which is shipped in
|
||
the Windows runtime ZIP.
|
||
</li>
|
||
<li><code>relay.js</code> and crash-isolated <code>relay-watcher.js</code>.</li>
|
||
<li>Orca-patched <code>node-pty@1.1.0</code> built for the bundled runtime.</li>
|
||
<li>
|
||
Windows also carries the pinned node-pty ConPTY runtime closure (<code
|
||
>conpty.dll</code
|
||
>
|
||
and <code>OpenConsole.exe</code>) for the tuple architecture. Hash both files into
|
||
the tree identity, classify them as native runtime inputs for signing/trust, and
|
||
run PTY smoke with the production <code>useConptyDll: true</code> behavior rather
|
||
than silently exercising system ConPTY.
|
||
</li>
|
||
<li>
|
||
<code>@parcel/watcher@2.5.6</code> with exactly one native optional package.
|
||
</li>
|
||
<li>Runtime metadata, dependency licenses, and a file-level SHA-256 manifest.</li>
|
||
<li>
|
||
No development dependencies, package manager, compiler, source maps, PDBs, or
|
||
Orca-built debug symbols unless explicitly needed for diagnostics. Preserve the
|
||
verified official Node executable byte-for-byte even when upstream metadata is
|
||
present; never strip or rewrite those authenticated bytes.
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
</details>
|
||
|
||
<details open>
|
||
<summary>Release trust and identity</summary>
|
||
<div class="details-body">
|
||
<ul>
|
||
<li>
|
||
The packaged app embeds the signed manifest, exact build tag, and accepted public
|
||
keys.
|
||
</li>
|
||
<li>
|
||
Relay artifacts are immutable inputs to every desktop build, and those exact bytes
|
||
are uploaded.
|
||
</li>
|
||
<li>
|
||
Ed25519 signs a fixed-order, schema-validated UTF-8 JSON projection through the
|
||
existing <code>tweetnacl</code> dependency. Tuple and file arrays are sorted,
|
||
identity fields are portable ASCII, numbers are safe integers, and signatures
|
||
remain outside the signed projection.
|
||
</li>
|
||
<li>
|
||
An offline-generated 32-byte seed exists only in a tag-restricted
|
||
<code>relay-runtime-manifest-signing</code> GitHub Environment with required
|
||
reviewers. Only the aggregate signing job receives it; runtime publication stays
|
||
blocked until that environment and its access audit exist.
|
||
</li>
|
||
<li>
|
||
Key IDs are SHA-256 of the raw 32-byte public key. Rotation dual-signs two desktop
|
||
releases and at least 30 days; revocation and emergency replacement use a new
|
||
desktop build. Unknown, duplicate, or malformed signature entries fail closed.
|
||
</li>
|
||
<li>
|
||
Every Node/CVE/runtime/key change ships as a new desktop tag/build with a newly
|
||
embedded manifest; old clients stay frozen to their embedded manifest and accepted
|
||
keys.
|
||
</li>
|
||
<li>
|
||
There is no mutable freshness channel or runtime-only <code>latest</code> lookup;
|
||
emergency refresh and key response use the normal desktop update path.
|
||
</li>
|
||
<li>
|
||
The embedded manifest tag/channel/version must equal the compiled desktop
|
||
identity. A newer desktop rejects an older manifest; an explicit desktop downgrade
|
||
uses only its own embedded manifest and isolated cache identity.
|
||
</li>
|
||
<li>
|
||
GitHub keyless artifact attestations supplement build provenance but never replace
|
||
the offline-verifiable embedded Ed25519 signature.
|
||
</li>
|
||
<li>Archive identity includes every executable and native artifact.</li>
|
||
<li>
|
||
Downloads use <code>/releases/download/<exact-tag>/<asset></code>,
|
||
never a mutable latest URL.
|
||
</li>
|
||
<li>
|
||
Signature or hash failure rejects and deletes the artifact before any remote
|
||
transfer.
|
||
</li>
|
||
<li>
|
||
Preserve valid official Node signatures. Before final hashes, sign every
|
||
Orca-built macOS executable, <code>.node</code>, dylib, and
|
||
<code>spawn-helper</code> with the existing Developer ID identity, and send every
|
||
unsigned Windows <code>.exe</code>, DLL, and <code>.node</code> through the
|
||
existing SignPath inner-binary flow.
|
||
</li>
|
||
<li>
|
||
Native build/signing jobs verify platform-native trust on native runners and put
|
||
the attestation plus exact byte hashes in the signed manifest; clients verify that
|
||
portable signed evidence rather than assuming local tooling for a different target
|
||
OS.
|
||
</li>
|
||
<li>
|
||
The target repeats native-policy execution probes before finalization;
|
||
native-trust failure at either boundary fails closed.
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
</details>
|
||
|
||
<details open>
|
||
<summary>Platform and compatibility selection</summary>
|
||
<div class="details-body">
|
||
<ul>
|
||
<li>
|
||
Detect Linux libc without Node: prefer marked
|
||
<code>getconf GNU_LIBC_VERSION</code>, then parse marked
|
||
<code>ldd --version</code> output and musl loader paths.
|
||
</li>
|
||
<li>
|
||
Treat conflicting, noisy, absent, or unparseable libc evidence as unknown;
|
||
<code>auto</code> deterministically selects legacy.
|
||
</li>
|
||
<li>
|
||
Manifest entries declare minimum glibc or musl, libstdc++, kernel, macOS, and
|
||
Windows build requirements.
|
||
</li>
|
||
<li>
|
||
Probe requirements before download and again by executing bundled Node before
|
||
install finalization.
|
||
</li>
|
||
<li>
|
||
Cover BusyBox, Alpine, old glibc, containers, Rosetta, startup noise, and
|
||
ambiguous output in selector and live tests. No BusyBox-only variant is initially
|
||
qualified: Ubuntu's BusyBox 1.36.1 lacks <code>nohup</code> and selects legacy.
|
||
</li>
|
||
<li>
|
||
The POSIX baseline is POSIX <code>sh</code> with builtin
|
||
<code>command</code>/<code>printf</code>, byte-preserving stdin-to-file via
|
||
<code>cat</code>, and required
|
||
<code>mkdir</code
|
||
>/<code>rm</code>/<code>mv</code>/<code>chmod</code>/<code>test</code>/<code
|
||
>nohup</code
|
||
>
|
||
semantics. It excludes Node, Python, Perl, tar, base64, checksum tools, and
|
||
compilers.
|
||
</li>
|
||
<li>
|
||
Windows requires OpenSSH 8.1p1, Windows PowerShell 5.1, and .NET Framework 4.8. A
|
||
bounded 64 KiB <code>FileStream</code> loop writes raw stdin under an exclusive
|
||
<code>FileMode.CreateNew</code> staging lock; it rejects early EOF and excess
|
||
bytes and uses same-volume publish.
|
||
</li>
|
||
<li>
|
||
Both families run a nonce-bound binary-fidelity semantic probe once per
|
||
authenticated connection. Missing or incorrect primitives are compatibility
|
||
failures; probe results never survive reconnect or cross host boundaries.
|
||
</li>
|
||
<li>
|
||
The no-tar path opens one bounded stdin byte stream per manifest file and sends
|
||
exactly the declared size into exclusive staging. It becomes sequential under
|
||
<code>MaxSessions=1</code>; transferred bundled Node later hashes the complete
|
||
tree.
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
</details>
|
||
|
||
<div class="callout">
|
||
<strong>Hard resource and latency budgets</strong>
|
||
<p>
|
||
The local verified cache is capped at 2 GiB. Archives are rejected above 100 MiB
|
||
compressed, 350 MiB expanded, 5,000 entries, or 250 MiB for one file. Incremental
|
||
transfer/extraction memory is capped at 64 MiB on the desktop and 32 MiB remotely;
|
||
buffers stay at or below 1 MiB. SFTP starts at four files/channels and never exceeds
|
||
eight open files, dropping to one for <code>MaxSessions=1</code>.
|
||
</p>
|
||
<p>
|
||
Cold bootstrap is capped at 30 minutes with named sub-budgets, and cancellation must
|
||
join within 10 seconds. Warm p95 may be at most 100 ms or 10% slower than paired
|
||
legacy, whichever allowance is larger. Cold p95 may not exceed the smaller of 30
|
||
minutes or 115% of measured bytes/throughput time plus five minutes. Offline failures
|
||
classify within 20 seconds and eligible legacy starts within 10 seconds after
|
||
classification and join. Native GitHub jobs compare at least ten paired samples under
|
||
the same network shaping; inconclusive hosted variance requires a dedicated runner
|
||
rather than a weaker threshold.
|
||
</p>
|
||
</div>
|
||
</section>
|
||
|
||
<section id="fallback">
|
||
<div class="section-heading">
|
||
<div>
|
||
<div class="section-kicker">Compatibility</div>
|
||
<h2>Fallback is part of the design, not an afterthought.</h2>
|
||
</div>
|
||
<p>
|
||
Availability and compatibility failures may use a separately proven legacy path.
|
||
Signature, hash, archive-safety, extracted-tree, and native-signature failures fail
|
||
closed in <code>auto</code>; they never trigger an automatic mode switch.
|
||
</p>
|
||
</div>
|
||
|
||
<div class="table-wrap" role="region" aria-label="Fallback decisions" tabindex="0">
|
||
<table>
|
||
<caption class="visually-hidden">
|
||
Relay runtime fallback decisions and expected user impact
|
||
</caption>
|
||
<thead>
|
||
<tr>
|
||
<th scope="col">Condition</th>
|
||
<th scope="col">Action</th>
|
||
<th scope="col">User impact</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>
|
||
Previously validated runtime with matching structured sentinel and warm-path
|
||
structural checks
|
||
</td>
|
||
<td>
|
||
Trust initial-install proof under the immutable-directory assumption and launch
|
||
without a full-tree rehash
|
||
</td>
|
||
<td>No download, transfer, or npm work</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Verified local cache hit</td>
|
||
<td>Upload and validate</td>
|
||
<td>Remote may remain fully offline</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Client offline or asset absent, with no verified local cache</td>
|
||
<td>
|
||
Use proven legacy in per-target Beta <code>auto</code>; forced bundled fails at
|
||
the exact availability stage
|
||
</td>
|
||
<td>No GitHub request is ever delegated to the SSH host</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Bundled availability failure and legacy prerequisites also fail</td>
|
||
<td>
|
||
Report both stage codes with retry, update, and disable-Beta guidance; preserve
|
||
the original bundled error
|
||
</td>
|
||
<td>No false fallback-success claim or hidden retry loop</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Detected local or remote cache corruption</td>
|
||
<td>
|
||
Quarantine it and reinstall only from freshly verified bundled bytes; if
|
||
recovery cannot complete, fail closed without automatic legacy
|
||
</td>
|
||
<td>No corrupted cache is launched or hidden by fallback</td>
|
||
</tr>
|
||
<tr>
|
||
<td>GitHub timeout, 404, 429, or 5xx</td>
|
||
<td>Use legacy path in <code>auto</code> mode</td>
|
||
<td>Existing behavior remains available</td>
|
||
</tr>
|
||
<tr>
|
||
<td>
|
||
Unsupported tuple or pre-execution compatibility probe proves the runtime cannot
|
||
execute
|
||
</td>
|
||
<td>Use legacy path and record reason</td>
|
||
<td>Current behavior is retained only where the legacy E2E passes</td>
|
||
</tr>
|
||
<tr>
|
||
<td>
|
||
Signature, hash, archive-safety, extracted/transferred-tree, bundled-Node
|
||
integrity, or native-signature failure
|
||
</td>
|
||
<td>
|
||
Fail closed, delete or quarantine rejected bytes, and do not start automatic
|
||
legacy
|
||
</td>
|
||
<td>
|
||
Security failure is explicit and requires a trusted update or operator-selected
|
||
recovery
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Forced <code>bundled</code> mode fails</td>
|
||
<td>Fail with the exact stage and recovery guidance</td>
|
||
<td>No hidden change of requested mode</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<details open>
|
||
<summary>Fallback state machine</summary>
|
||
<div class="details-body">
|
||
<ol>
|
||
<li>Resolve the tuple and expected content identity from the embedded manifest.</li>
|
||
<li>
|
||
Run bundled stages under one parent AbortController with separate download,
|
||
extraction, transfer, and probe budgets.
|
||
</li>
|
||
<li>
|
||
On an eligible failure, abort the stage, close child processes/channels, and await
|
||
every task and cleanup promise.
|
||
</li>
|
||
<li>
|
||
Confirm no bundled lock or partial writer remains, then start legacy deployment
|
||
under a mode-qualified identity and lock.
|
||
</li>
|
||
<li>
|
||
Ignore late callbacks by generation; they may report diagnostics but cannot write
|
||
sentinels, launch, or mutate either install.
|
||
</li>
|
||
</ol>
|
||
<p>
|
||
Integrity failures, including detected cache mutation, stop before this transition
|
||
and cannot automatically select legacy. Hostile control of the authenticated remote
|
||
account is outside the integrity threat model; the remote proof establishes initial
|
||
transfer/finalization correctness. Warm launches assume Orca's completed directory
|
||
remains immutable; the sentinel is not ongoing proof against later filesystem
|
||
mutation. Detected warm-cache mutation fails closed. This does not protect against a
|
||
remote user who can replace both runtime and sentinel.
|
||
</p>
|
||
</div>
|
||
</details>
|
||
|
||
<details open>
|
||
<summary>Remote verification trust boundary and order</summary>
|
||
<div class="details-body">
|
||
<ol>
|
||
<li>
|
||
Verify the embedded signature, tuple, limits, archive SHA-256, and extracted tree
|
||
locally.
|
||
</li>
|
||
<li>
|
||
Transfer only those verified files through authenticated SSH into an exclusive
|
||
staging directory.
|
||
</li>
|
||
<li>
|
||
Do not depend on remote <code>sha256sum</code> or <code>shasum</code>; execute the
|
||
transferred bundled Node to hash every staged file and compare the complete
|
||
manifest.
|
||
</li>
|
||
<li>
|
||
Only after full-tree hashing, native probes, and PTY/watcher smoke may Orca write
|
||
the structured completion sentinel and publish the install.
|
||
</li>
|
||
</ol>
|
||
<p>
|
||
Local verification plus authenticated transfer and exclusive staging is the
|
||
pre-execution integrity boundary. Executing bundled Node is intentionally the first
|
||
staged binary execution and verifies transfer correctness before completion. A
|
||
hostile authenticated remote account remains outside scope because it can replace
|
||
both the runtime and its proof.
|
||
</p>
|
||
</div>
|
||
</details>
|
||
</section>
|
||
|
||
<section id="validation">
|
||
<div class="section-heading">
|
||
<div>
|
||
<div class="section-kicker">Validation</div>
|
||
<h2>Prove production behavior, failure behavior, and rollback behavior.</h2>
|
||
</div>
|
||
<p>
|
||
Mock tests protect decision logic. Release promotion additionally requires the real
|
||
archive, real native binaries, a real SSH daemon, and the exact packaged desktop path.
|
||
</p>
|
||
</div>
|
||
|
||
<div class="table-wrap" role="region" aria-label="Validation matrix" tabindex="0">
|
||
<table>
|
||
<caption class="visually-hidden">
|
||
Required relay validation surfaces, cases, and pass oracles
|
||
</caption>
|
||
<thead>
|
||
<tr>
|
||
<th scope="col">Surface</th>
|
||
<th scope="col">Required cases</th>
|
||
<th scope="col">Oracle</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>Build</td>
|
||
<td>
|
||
Every declared tuple; minimum OS baseline; exact Node and native dependency
|
||
versions; SBOM and provenance
|
||
</td>
|
||
<td>
|
||
Archive runs on target, contents match manifest, native signatures pass, no
|
||
unexpected platform package remains
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Platform selection</td>
|
||
<td>
|
||
glibc/musl and version probes, BusyBox, Alpine, containers, old glibc, Rosetta,
|
||
noisy and conflicting output
|
||
</td>
|
||
<td>
|
||
One compatible tuple is selected, or unknown deterministically selects tested
|
||
legacy behavior
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Remote environment</td>
|
||
<td>
|
||
No Node/npm/Python/compiler/tar/hash tools; blocked egress; missing required
|
||
primitives; BusyBox; NVM below shell guard; read-only/noexec home; quota and
|
||
inode exhaustion
|
||
</td>
|
||
<td>
|
||
Declared POSIX or Windows primitive baselines connect without undeclared tools;
|
||
missing primitives and filesystem constraints classify compatibly and never
|
||
improvise an untrusted command path
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Download and cache</td>
|
||
<td>
|
||
Redirect and header scoping, proxy, deleted asset, cold/warm/offline cache,
|
||
multiple app processes, eviction, permissions, cancellation, timeout,
|
||
404/429/5xx, disk full, corruption
|
||
</td>
|
||
<td>
|
||
One verified cache entry or clean availability fallback; corruption is
|
||
quarantined and recovered only from freshly verified bytes or fails closed
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Archive security</td>
|
||
<td>
|
||
Bad signature/hash/native signature, wrong tuple, traversal path, absolute path,
|
||
symlink escape, oversized expansion
|
||
</td>
|
||
<td>
|
||
Manifest/archive failures are rejected before transfer; native trust is verified
|
||
on target-native build/read-back and again by target-policy probes before
|
||
finalization; every integrity failure fails closed
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td>SSH deployment</td>
|
||
<td>
|
||
Full-size runtime over SFTP and POSIX/Windows system SSH; tar/no-tar; no remote
|
||
hash tools; corrupted upload; bundled-Node corruption/failure; bounded memory
|
||
and concurrency; <code>MaxSessions=1</code>; interrupted upload; stale lock
|
||
</td>
|
||
<td>
|
||
Bundled Node hashes the full staged tree before sentinel write;
|
||
corruption/failure leaves no complete install, memory stays in budget, and the
|
||
ordering is asserted
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td>PTY and watcher</td>
|
||
<td>
|
||
Spawn, input, resize, exit, shell environment, create/rename/modify/delete
|
||
events, watcher crash
|
||
</td>
|
||
<td>
|
||
Exact PTY bytes and watcher events; relay PID and existing PTY survive watcher
|
||
replacement
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Relay API conformance</td>
|
||
<td>
|
||
PTY, Git, filesystem and streaming RPCs, preflight, agent hooks, port scan,
|
||
aborts, and protocol handshake
|
||
</td>
|
||
<td>
|
||
The packaged runtime matches existing relay request, response, streaming,
|
||
cancellation, and error contracts
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Lifecycle and fallback</td>
|
||
<td>
|
||
Reconnect, PTY reattach, restart, concurrent clients, upgrade, downgrade,
|
||
interrupted upgrade, GC, timeout-to-legacy, forced rollback
|
||
</td>
|
||
<td>
|
||
No lost session, protocol drift, late mutation, background process, cross-mode
|
||
lock/sentinel use, or deletion of a live version
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Performance</td>
|
||
<td>Cold and warm paths over 1/10/100 Mbps links and 50–200 ms latency</td>
|
||
<td>
|
||
Warm path has no meaningful regression; cold p95 does not exceed agreed legacy
|
||
baseline
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<div class="callout">
|
||
<strong>Risk-based matrix, not an implied full Cartesian</strong>
|
||
<p>
|
||
Evidence has two layers. Every enabled remote tuple must pass both built-in SFTP and
|
||
system SSH, including Windows remote/system SSH and <code>MaxSessions=1</code>. Every
|
||
supported client OS/architecture must separately prove resolver/cache plus both
|
||
transfer families against representative POSIX and Windows remotes. Each required cell
|
||
has an evidence ID; untested client × remote combinations are not claimed.
|
||
</p>
|
||
</div>
|
||
|
||
<div class="callout">
|
||
<strong>GitHub Actions runner policy</strong>
|
||
<p>
|
||
GitHub Actions is the primary orchestration and evidence surface for PR, nightly,
|
||
release, and promotion gates. A GitHub-hosted runner may fill a required cell only
|
||
when it provides real hardware or native virtualization for the declared
|
||
OS/architecture and exercises a real OpenSSH daemon, the full-size packaged runtime,
|
||
and the production transport named by that cell. Same-host and native-container
|
||
targets qualify only when they preserve the declared remote, SSH, primitive, egress,
|
||
and isolation conditions; mocks, reduced fixtures, cross-builds, and QEMU-only runs do
|
||
not qualify as live evidence.
|
||
</p>
|
||
<p>
|
||
Cross-family client-to-remote cells use workflow-provisioned ephemeral native SSH
|
||
targets or an approved self-hosted target pool; the remote need not itself be
|
||
GitHub-hosted. Each job records the runner label and image, native architecture,
|
||
remote image or snapshot identity, teardown result, commands, metrics, and artifacts.
|
||
A tuple stays on proven legacy behavior when no qualifying native runner or reachable
|
||
representative remote is available. Numeric regression comparisons use a repeatable
|
||
runner class or a dedicated runner when hosted-runner variance would make the agreed
|
||
threshold inconclusive.
|
||
</p>
|
||
<p>
|
||
Qualifying jobs pin explicit native labels: <code>ubuntu-24.04</code> and
|
||
<code>ubuntu-24.04-arm</code>, <code>macos-15-intel</code> and <code>macos-15</code>,
|
||
plus <code>windows-2022</code> and <code>windows-11-arm</code>. GitHub refreshes these
|
||
images weekly, so each job logs the resolved image version; <code>*-latest</code> and
|
||
third-party runner labels do not qualify a tuple merely because another repository
|
||
workflow uses them. Hosted capacity is unreserved, and no approved self-hosted SSH
|
||
target pool or cross-family endpoint is assumed.
|
||
</p>
|
||
</div>
|
||
|
||
<h3 class="subsection-heading">Release gates</h3>
|
||
<div class="gate-grid">
|
||
<article class="gate">
|
||
<h3>PR gate</h3>
|
||
<small>Every change</small>
|
||
<ul class="gate-list">
|
||
<li>
|
||
Selector, identity, manifest, cache, extraction, fallback, and install fault
|
||
tests.
|
||
</li>
|
||
<li>Existing SSH relay, PTY, watcher, reconnect, and release contract suites.</li>
|
||
<li>At least Linux x64 glibc live artifact E2E.</li>
|
||
</ul>
|
||
</article>
|
||
<article class="gate">
|
||
<h3>Nightly gate</h3>
|
||
<small>Broad compatibility</small>
|
||
<ul class="gate-list">
|
||
<li>All available real remote tuples and both SSH transport families.</li>
|
||
<li>Network fault matrix and constrained bandwidth/latency runs.</li>
|
||
<li>Upgrade, downgrade, concurrent install, and remote cache GC soak.</li>
|
||
</ul>
|
||
</article>
|
||
<article class="gate">
|
||
<h3>Release gate</h3>
|
||
<small>Blocks publication</small>
|
||
<ul class="gate-list">
|
||
<li>
|
||
Every enabled archive built, signed, uploaded, downloaded back, and executed.
|
||
</li>
|
||
<li>
|
||
Target-native build jobs and native signing jobs feed one fail-closed
|
||
aggregate/manifest-signing job.
|
||
</li>
|
||
<li>
|
||
Signed macOS and Windows bytes return before final hashes and manifest signature
|
||
are produced.
|
||
</li>
|
||
<li>
|
||
Every desktop embeds the same signed manifest whose exact bytes and archives are
|
||
uploaded.
|
||
</li>
|
||
<li>Manifest covers the exact app tag and contains no missing or extra tuple.</li>
|
||
<li>
|
||
Platform-native signatures, SBOM, provenance, and signing-key policy checks pass.
|
||
</li>
|
||
<li>Packaged desktop completes the no-Node, no-egress SSH E2E.</li>
|
||
<li>
|
||
Timeout, retry exhaustion, manual-approval failure, signing failure, and
|
||
recovered-draft rehearsals all block unsafe publication.
|
||
</li>
|
||
</ul>
|
||
</article>
|
||
<article class="gate">
|
||
<h3>Promotion gate</h3>
|
||
<small>Blocks default-on</small>
|
||
<ul class="gate-list">
|
||
<li>Three consecutive RC builds pass without unexplained fallback.</li>
|
||
<li>No new PTY, watcher, reconnect, or bootstrap regression in canary evidence.</li>
|
||
<li>
|
||
Forced rollback and the legacy E2E pass for every tuple where fallback is claimed.
|
||
</li>
|
||
</ul>
|
||
</article>
|
||
</div>
|
||
</section>
|
||
|
||
<section id="risks">
|
||
<div class="section-heading">
|
||
<div>
|
||
<div class="section-kicker">Risk register</div>
|
||
<h2>Resolve these before default-on.</h2>
|
||
</div>
|
||
<p>
|
||
The largest risks are compatibility boundaries and release coupling, not the GitHub
|
||
download itself.
|
||
</p>
|
||
</div>
|
||
|
||
<div class="risk-grid">
|
||
<article class="risk">
|
||
<strong>Linux baseline mismatch</strong>
|
||
<p>
|
||
Build against the oldest supported glibc and libstdc++ baseline; run on that exact
|
||
baseline before promotion.
|
||
</p>
|
||
</article>
|
||
<article class="risk">
|
||
<strong>Untrusted musl runtime source</strong>
|
||
<p>
|
||
Do not invent a binary source. Document provenance and updates, or retain legacy
|
||
mode for musl until Orca can build it.
|
||
</p>
|
||
</article>
|
||
<article class="risk">
|
||
<strong>Native patch drift</strong>
|
||
<p>
|
||
Build from Orca’s lockfile and patch set; assert the patched diagnostic exports and
|
||
real PTY behavior in every artifact.
|
||
</p>
|
||
</article>
|
||
<article class="risk">
|
||
<strong>Missing release assets</strong>
|
||
<p>
|
||
Keep releases draft until all relay assets pass read-back verification; publication
|
||
depends on the completeness job.
|
||
</p>
|
||
</article>
|
||
<article class="risk">
|
||
<strong>Cold-transfer latency</strong>
|
||
<p>
|
||
Cache by content, prefetch last-known target tuples after updates, preserve progress
|
||
stages, and keep a bounded fallback.
|
||
</p>
|
||
</article>
|
||
<article class="risk">
|
||
<strong>Home directory cannot execute binaries</strong>
|
||
<p>
|
||
Probe bundled Node before finalizing. Auto mode falls back to the remote runtime
|
||
path with a precise diagnostic reason.
|
||
</p>
|
||
</article>
|
||
<article class="risk">
|
||
<strong>Release asset tampering</strong>
|
||
<p>
|
||
Verify a signed canonical manifest and archive SHA-256 before extraction; never
|
||
execute or transfer rejected bytes.
|
||
</p>
|
||
</article>
|
||
<article class="risk">
|
||
<strong>Fallback masks defects</strong>
|
||
<p>
|
||
Record stage-specific reason codes and require zero unexplained fallback across the
|
||
RC promotion window.
|
||
</p>
|
||
</article>
|
||
<article class="risk">
|
||
<strong>Bundled Node lifecycle</strong>
|
||
<p>
|
||
Own a supported-version/EOL policy, SBOM and provenance, update cadence, and CVE
|
||
response SLA. Every refresh ships a new desktop build and embedded manifest;
|
||
installed old clients remain pinned.
|
||
</p>
|
||
</article>
|
||
<article class="risk">
|
||
<strong>Signing-key lifecycle</strong>
|
||
<p>
|
||
Specify canonical bytes, protected-environment access, key IDs, dual-key rotation,
|
||
revocation response through a desktop update, and exact-tag anti-rollback. Do not
|
||
add mutable freshness lookup.
|
||
</p>
|
||
</article>
|
||
<article class="risk">
|
||
<strong>OS-native trust controls</strong>
|
||
<p>
|
||
Test quarantined bytes on clean macOS 13.5 x64/arm64 snapshots with Gatekeeper and
|
||
strict codesign. Test Server 2022 x64 and Windows 11 24H2 arm64 with current
|
||
Defender intelligence, then Windows 11 24H2 x64 with the release WDAC policy in
|
||
audit and enforced modes. Record snapshot, policy, and security-intelligence IDs;
|
||
any denial blocks release rather than weakening the endpoint control.
|
||
</p>
|
||
</article>
|
||
<article class="risk">
|
||
<strong>Large-runtime transfer</strong>
|
||
<p>
|
||
Use bounded streaming and cancellation per transport; prohibit whole-tree
|
||
JSON/base64 buffering and require a no-tar path before default-on.
|
||
</p>
|
||
</article>
|
||
<article class="risk">
|
||
<strong>Fallback races</strong>
|
||
<p>
|
||
Abort and join every bundled stage before legacy starts; separate mode identities
|
||
and reject callbacks from stale generations.
|
||
</p>
|
||
</article>
|
||
<article class="risk">
|
||
<strong>Ambiguous host detection</strong>
|
||
<p>
|
||
Use marked no-Node probes and conservative version checks. Unknown, conflicting, or
|
||
unsupported results choose proven legacy behavior.
|
||
</p>
|
||
</article>
|
||
</div>
|
||
</section>
|
||
|
||
<section id="rollout">
|
||
<div class="section-heading">
|
||
<div>
|
||
<div class="section-kicker">Rollout</div>
|
||
<h2>Publish, observe, enable, then simplify.</h2>
|
||
</div>
|
||
<p>
|
||
Artifact availability lands before production consumption. Every later stage remains
|
||
reversible from the same app build.
|
||
</p>
|
||
</div>
|
||
|
||
<div class="rollout">
|
||
<article class="rollout-step">
|
||
<h3>Asset-only</h3>
|
||
<p>Build and publish runtimes, run read-back E2E, leave production on legacy.</p>
|
||
</article>
|
||
<article class="rollout-step">
|
||
<h3>Per-target Beta</h3>
|
||
<p>
|
||
Ship a Beta-tagged option on SSH target add/edit surfaces; every existing and new
|
||
target remains on legacy unless explicitly opted in.
|
||
</p>
|
||
</article>
|
||
<article class="rollout-step">
|
||
<h3>Stable Beta soak</h3>
|
||
<p>
|
||
Gather privacy-safe real-host evidence while the packaged and persisted default
|
||
remains legacy.
|
||
</p>
|
||
</article>
|
||
<article class="rollout-step">
|
||
<h3>Future default review</h3>
|
||
<p>
|
||
Change a tuple to default-on only through a separate reviewed decision after CI,
|
||
native-runner, Beta-usage, support, and rollback gates pass.
|
||
</p>
|
||
</article>
|
||
</div>
|
||
|
||
<div class="callout">
|
||
<strong>Per-target Beta contract</strong>
|
||
<p>
|
||
Store an extensible runtime mode per SSH target rather than a global boolean. Missing,
|
||
malformed, imported, existing, and newly created target configuration defaults to
|
||
<code>legacy</code>. The Beta option selects bundled-preferred
|
||
<code>auto</code> behavior only for that target and only on its next connection or an
|
||
explicit reconnect; it never hot-swaps a live PTY, watcher, or relay generation.
|
||
</p>
|
||
<p>
|
||
Classified availability and compatibility failures may enter proven legacy
|
||
automatically. Integrity and security failures still fail closed, but the local error
|
||
surface provides an explicit action to disable Beta for that target and reconnect
|
||
through legacy. Shipping this option does not authorize changing the default or
|
||
removing legacy behavior.
|
||
</p>
|
||
</div>
|
||
</section>
|
||
|
||
<section id="done">
|
||
<div class="section-heading">
|
||
<div>
|
||
<div class="section-kicker">Definition of done</div>
|
||
<h2>Stable is blocked until every statement is evidence-backed.</h2>
|
||
</div>
|
||
<p>
|
||
These are release criteria, not aspirations. Missing bundled evidence keeps the
|
||
affected tuple on legacy only when its legacy E2E passes; otherwise Orca must not
|
||
claim that tuple as supported.
|
||
</p>
|
||
</div>
|
||
|
||
<div class="comparison">
|
||
<article>
|
||
<h3>Functional and compatibility</h3>
|
||
<ul class="definition-list">
|
||
<li>Every enabled tuple passes its real-environment artifact E2E.</li>
|
||
<li>
|
||
A host with no Node, npm, compiler, or egress gets working PTYs and file watching.
|
||
</li>
|
||
<li>The exact #8450 environment passes bundled and forced-legacy modes.</li>
|
||
<li>
|
||
Reconnect, reattach, upgrade, downgrade, and rollback preserve live sessions.
|
||
</li>
|
||
<li>All relay RPC families pass conformance through the packaged runtime.</li>
|
||
<li>Existing relay, PTY, watcher, Git, and release suites remain green.</li>
|
||
</ul>
|
||
</article>
|
||
<article>
|
||
<h3>Release and operations</h3>
|
||
<ul class="definition-list">
|
||
<li>
|
||
Every asset is signed, hashed, uploaded, read back, and executed before
|
||
publication.
|
||
</li>
|
||
<li>
|
||
Every desktop embeds the exact signed manifest used to identify offline remote
|
||
caches.
|
||
</li>
|
||
<li>
|
||
Transfer memory, cancellation, no-tar, permissions, and structured-sentinel gates
|
||
pass.
|
||
</li>
|
||
<li>No primary-path remote command invokes npm or opens an HTTP connection.</li>
|
||
<li>GitHub failure falls back without corrupting local or remote cache state.</li>
|
||
<li>
|
||
Every integrity/security failure fails closed in auto and never starts legacy
|
||
automatically.
|
||
</li>
|
||
<li>
|
||
Node lifecycle, SBOM, provenance, key rotation, and native signing policies are
|
||
operational.
|
||
</li>
|
||
<li>
|
||
Each required two-layer matrix cell links an evidence ID; no untested Cartesian
|
||
combinations are claimed.
|
||
</li>
|
||
<li>
|
||
Warm connections show no meaningful latency regression against the recorded
|
||
baseline.
|
||
</li>
|
||
<li>Three consecutive RCs pass with zero unexplained fallback reasons.</li>
|
||
</ul>
|
||
</article>
|
||
</div>
|
||
|
||
<div class="callout">
|
||
<strong>Stop condition</strong>
|
||
<p>
|
||
If a required live runner, trusted runtime source, compatibility baseline, or rollback
|
||
proof is unavailable, do not declare the tuple bundled-by-default. Continue serving it
|
||
through the tested legacy path.
|
||
</p>
|
||
</div>
|
||
</section>
|
||
|
||
<section id="references">
|
||
<div class="section-heading">
|
||
<div>
|
||
<div class="section-kicker">Repository anchors</div>
|
||
<h2>Primary implementation touchpoints.</h2>
|
||
</div>
|
||
<p>Links are relative so this document remains useful from a local checkout.</p>
|
||
</div>
|
||
<ul class="source-list">
|
||
<li><a href="../../../config/scripts/build-relay.mjs">Relay build</a></li>
|
||
<li><a href="../../../src/main/ssh/ssh-relay-deploy.ts">SSH deploy</a></li>
|
||
<li>
|
||
<a href="../../../src/main/ssh/ssh-relay-versioned-install.ts">Versioned install</a>
|
||
</li>
|
||
<li>
|
||
<a href="../../../src/main/ssh/ssh-remote-platform-detection.ts"
|
||
>Platform detection</a
|
||
>
|
||
</li>
|
||
<li>
|
||
<a href="../../../config/scripts/verify-release-required-assets.mjs"
|
||
>Release asset gate</a
|
||
>
|
||
</li>
|
||
<li><a href="../../../.github/workflows/release-cut.yml">Release workflow</a></li>
|
||
<li>
|
||
<a href="../../../tests/e2e/helpers/docker-ssh-relay-target.ts">Live SSH harness</a>
|
||
</li>
|
||
</ul>
|
||
</section>
|
||
|
||
<footer>
|
||
This plan intentionally keeps the current installer available during rollout. “No
|
||
regressions” is enforced through declared support, executable evidence, automatic
|
||
fallback, and a tested rollback—not through an untestable claim about every SSH host.
|
||
</footer>
|
||
</main>
|
||
</div>
|
||
</body>
|
||
</html>
|