diff --git a/components/Faq.js b/components/Faq.js
index 89ba57b..747be95 100644
--- a/components/Faq.js
+++ b/components/Faq.js
@@ -29,7 +29,7 @@ export const faqItems = [
},
{
question: 'What software does OpenAdapt work with?',
- answer: 'OpenAdapt targets repeated workflows across browser applications, Windows UI Automation, native macOS, and remote desktop environments. Choose managed browser execution or connect a self-hosted or customer-controlled runtime for desktop, RDP, Citrix, private systems, and regulated data.',
+ answer: 'OpenAdapt targets repeated workflows across browser applications, Windows UI Automation, native macOS Accessibility, Linux AT-SPI, RDP, Citrix, and other remote desktop environments. Choose managed browser execution or connect a local, self-hosted, or customer-controlled runtime for desktop, remote, private-system, and regulated workflows.',
},
]
diff --git a/components/InstallSection.js b/components/InstallSection.js
index a2295b4..0b52bca 100644
--- a/components/InstallSection.js
+++ b/components/InstallSection.js
@@ -46,7 +46,7 @@ export default function InstallSection() {
One command installs the OpenAdapt launcher and governed
workflow compiler. The same CLI records, compiles, and replays
- across browser, Windows, macOS, RDP, and Citrix under one
+ across browser, Windows, macOS, Linux, RDP, and Citrix under one
governed loop. No account or hosted service is required.
diff --git a/components/MastHead.js b/components/MastHead.js
index 7df786f..2f5cf40 100644
--- a/components/MastHead.js
+++ b/components/MastHead.js
@@ -54,10 +54,10 @@ export default function Home({ githubStats }) {
Demonstrate a repeated task once. OpenAdapt
compiles it into a local program that replays at
$0 per healthy run across browser, Windows,
- macOS, RDP, and Citrix. When the screen changes,
- it re-checks its evidence, repairs with AI when
- it can, and halts for a person instead of
- guessing.{' '}
+ macOS, Linux, RDP, and Citrix. When the screen
+ changes, it re-checks its evidence, repairs with
+ AI when it can, and halts for a person instead
+ of guessing.{' '}
See how it runs across every interface.
diff --git a/components/NavHeader.js b/components/NavHeader.js
index 30b63a7..26e5307 100644
--- a/components/NavHeader.js
+++ b/components/NavHeader.js
@@ -30,7 +30,7 @@ const SOLUTIONS_LINKS = [
const PRODUCT_LINKS = [
{ label: 'How it works', href: '/how-it-works' },
- { label: 'How it runs', href: '/#product-status' },
+ { label: 'Platforms & deployment', href: '/#product-status' },
{ label: 'Workflows', href: '/workflows' },
{ label: 'Safety', href: '/safety' },
{ label: 'Compare', href: '/compare' },
diff --git a/components/ProductStatus.js b/components/ProductStatus.js
index a4c0bfb..1be1885 100644
--- a/components/ProductStatus.js
+++ b/components/ProductStatus.js
@@ -56,12 +56,12 @@ const executionSurfaces = [
detail: 'Compile DOM, accessibility, visual, and interaction evidence into deterministic browser workflows.',
},
{
- title: 'Windows applications',
- detail: 'Use structured UI Automation with retained visual evidence to operate legacy desktop applications.',
+ title: 'Desktop applications',
+ detail: 'Use Windows UI Automation, macOS Accessibility, or Linux AT-SPI with retained visual evidence to operate native applications.',
},
{
- title: 'RDP, Citrix & VDI',
- detail: 'Carry the same policy, verification, repair, and audit model into remote application environments.',
+ title: 'Remote applications',
+ detail: 'Carry the same policy, verification, repair, and audit model through RDP, Citrix Workspace, and other VDI environments.',
},
]
@@ -110,9 +110,10 @@ export default function ProductStatus() {
Built for the interfaces your work depends on
- From modern browser apps to legacy Windows and remote desktops,
- workflows stay inspectable, policy-bound, and governed by
- explicit verification.
+ From modern browser apps to native Windows, macOS, and
+ Linux software and remote desktops, workflows stay
+ inspectable, policy-bound, and governed by explicit
+ verification.
{executionSurfaces.map((item) => (
diff --git a/components/Qualification.js b/components/Qualification.js
index f5202a3..2daa38b 100644
--- a/components/Qualification.js
+++ b/components/Qualification.js
@@ -6,7 +6,7 @@ import Link from 'next/link'
// end; where one does not, it halts for a human or an AI instead of trusting
// the screen. The oracle is an enhancement, never a gate on using the product.
// We lead with fit, then affirm that when work fits that shape OpenAdapt runs
-// it across every interface (browser, Windows, macOS, RDP, Citrix) under one
+// it across every interface (browser, Windows, macOS, Linux, RDP, Citrix) under one
// governed loop, with the full /compare breakdown one click away.
const fits = [
@@ -54,8 +54,8 @@ export default function Qualification() {
When work fits that shape, OpenAdapt runs it across every
interface it touches under one governed loop: browser,
- Windows, macOS, RDP, and Citrix. See how it compares with
- RPA, computer-use agents, and browser recorders on the{' '}
+ Windows, macOS, Linux, RDP, and Citrix. See how it compares
+ with RPA, computer-use agents, and browser recorders on the{' '}
comparison page
diff --git a/components/ReplayHero.js b/components/ReplayHero.js
index 94c8436..c71c5a2 100644
--- a/components/ReplayHero.js
+++ b/components/ReplayHero.js
@@ -155,7 +155,7 @@ export default function ReplayHero() {
A compiled workflow replaying against OpenEMR’s live
public demo. The same governed loop runs across browser,
- Windows, macOS, RDP, and Citrix.
+ Windows, macOS, Linux, RDP, and Citrix.
diff --git a/cypress/e2e/basic.cy.js b/cypress/e2e/basic.cy.js
index 0cd3712..edd1fda 100644
--- a/cypress/e2e/basic.cy.js
+++ b/cypress/e2e/basic.cy.js
@@ -151,7 +151,7 @@ describe('public product truth', () => {
cy.contains('button', 'Product').click()
cy.get('#nav-solutions-menu').should('not.exist')
cy.get('#nav-product-menu').within(() => {
- cy.contains('a', 'How it runs').should(
+ cy.contains('a', 'Platforms & deployment').should(
'have.attr',
'href',
'/#product-status'
@@ -277,8 +277,8 @@ describe('public product truth', () => {
'be.visible'
)
cy.contains('Web applications').should('be.visible')
- cy.contains('Windows applications').should('be.visible')
- cy.contains('RDP, Citrix & VDI').should('be.visible')
+ cy.contains('Desktop applications').should('be.visible')
+ cy.contains('Remote applications').should('be.visible')
cy.contains('qualification evidence')
.should('have.attr', 'href')
.and('include', '/tree/main/benchmark')
@@ -383,7 +383,7 @@ describe('public product truth', () => {
.should('have.attr', 'href')
.and('equal', '/solutions/insurance')
cy.contains('Product').scrollIntoView().should('be.visible')
- cy.contains('a', 'How it runs').should(
+ cy.contains('a', 'Platforms & deployment').should(
'have.attr',
'href',
'/#product-status'
diff --git a/data/workflowCatalog.js b/data/workflowCatalog.js
index fb230e7..fa6b8c8 100644
--- a/data/workflowCatalog.js
+++ b/data/workflowCatalog.js
@@ -8,19 +8,17 @@
const FLOW_REPO = 'https://github.com/OpenAdaptAI/openadapt-flow'
-// Canonical substrate maturity labels, reconciled to public/status.json (the
-// single source of truth). The same governed loop covers every substrate; the
-// label says how broadly each has been exercised today. Beta = broadly
-// exercised (browser); Early access = validated on specific named tasks
-// (Windows UIA, native macOS, RDP); Exploratory = no validated real-environment
-// integration yet (Citrix / VDI). The three catalog entries below all run
-// through the browser substrate.
+// Canonical substrate availability labels, reconciled to public/status.json.
+// Each released backend is available behind the same governed loop; its exact
+// evidence scope and deployment boundary live in the status manifest. The
+// catalog entries below all run through the browser substrate.
export const SUBSTRATE_MATURITY = {
- browser: 'Beta',
- windows: 'Early access',
- macos: 'Early access',
- rdp: 'Early access',
- citrix: 'Exploratory',
+ browser: 'Available',
+ windows: 'Available',
+ macos: 'Available',
+ linux: 'Available',
+ rdp: 'Available',
+ citrix: 'Available',
}
// Shared honesty envelope. Every catalog entry sets these explicitly so the
diff --git a/pages/download.js b/pages/download.js
index aec6158..5ca11d4 100644
--- a/pages/download.js
+++ b/pages/download.js
@@ -92,7 +92,7 @@ export default function DownloadPage({ release, fetchFailed }) {
Install OpenAdapt | OpenAdapt
Install OpenAdapt
- Start with the OpenAdapt CLI
+ Install the CLI or desktop app
The flagship{' '}
@@ -136,19 +136,22 @@ export default function DownloadPage({ release, fetchFailed }) {
diff --git a/pages/index.js b/pages/index.js
index a1462a4..96ed9c2 100644
--- a/pages/index.js
+++ b/pages/index.js
@@ -59,9 +59,9 @@ const softwareSchema = {
name: 'OpenAdapt',
alternateName: 'OpenAdapt.AI',
applicationCategory: 'DeveloperApplication',
- operatingSystem: 'Windows, macOS, Linux (browser workflow path)',
+ operatingSystem: 'Windows, macOS, Linux',
description:
- 'Open-source governed workflow compiler for repeated GUI work. Record a browser workflow, compile it into a deterministic local program, and use configured verification to resolve, repair, or halt under interface drift.',
+ 'Open-source governed workflow compiler for repeated GUI work across browser, Windows, macOS, Linux, RDP, and Citrix. Record a workflow, compile it into a deterministic local program, and use configured verification to resolve, repair, or halt under interface drift.',
url: 'https://openadapt.ai',
downloadUrl: 'https://pypi.org/project/openadapt/',
author: {
diff --git a/pages/workflows.js b/pages/workflows.js
index 326b283..ef2250c 100644
--- a/pages/workflows.js
+++ b/pages/workflows.js
@@ -222,6 +222,10 @@ export default function WorkflowsPage() {
Native macOS —{' '}
{SUBSTRATE_MATURITY.macos}
+
+ Native Linux —{' '}
+ {SUBSTRATE_MATURITY.linux}
+
RDP —{' '}
{SUBSTRATE_MATURITY.rdp}
@@ -241,9 +245,10 @@ export default function WorkflowsPage() {
>
status manifest
- . Beta means broadly exercised; Early access means
- validated on specific named tasks; Exploratory means no
- validated real-environment integration yet.
+ . Available means the backend ships in the released
+ compiler/runtime. The manifest records its exact bounded
+ evidence and whether execution is managed or
+ customer-controlled.
diff --git a/public/status.json b/public/status.json
index 68d9459..8a9bc24 100644
--- a/public/status.json
+++ b/public/status.json
@@ -1,41 +1,71 @@
{
- "$comment": "Canonical machine-readable status evidence for OpenAdapt. Served at https://openadapt.ai/status.json and consumed by status-aware website surfaces and tests for cross-repo reconciliation. The homepage presents product capabilities without rendering this maturity ledger directly. OpenAdapt is one governed product across every execution substrate; each substrate carries a maturity tier from the canonical ladder defined in `tiers`. The tiers describe how broadly a substrate has been exercised today, not whether it is first-class in the product.",
- "generated_at": "2026-07-21",
+ "$comment": "Canonical machine-readable release, capability, evidence, and deployment status for OpenAdapt. Served at https://openadapt.ai/status.json and consumed by status-aware public surfaces and tests. OpenAdapt is one Beta product across browser, Windows, macOS, Linux, RDP, and Citrix/VDI. Capability availability is distinct from the deployment boundary and from the bounded evidence scope recorded for each substrate.",
+ "generated_at": "2026-07-24",
+ "product_lifecycle": "Beta",
"versions": {
"launcher": "1.7.1",
- "flow": "1.19.0",
- "desktop": "0.6.2"
+ "flow": "1.20.1",
+ "desktop": "0.9.0"
},
"tiers": {
- "Beta": "Works and is broadly exercised. Available today through the managed hosted product for browser workflows.",
- "Early access": "Works and is validated on specific named tasks, but not yet broadly exercised. Real UI Automation, accessibility, and RDP backends run under the governed loop.",
- "Exploratory": "The governed integration path is defined; real-environment qualification has not completed.",
- "Research": "Experimental and not yet part of the governed product."
+ "Available": "Implemented in the released compiler and governed runtime. Production use still qualifies the exact workflow, application, environment, identity contract, and effect oracle.",
+ "Beta": "Public Beta product or service with an explicit delivery and evidence boundary."
},
"substrates": [
{
"name": "Browser",
- "public_label": "Beta",
+ "public_label": "Available",
"internal_tier": "reference",
- "evidence_note": "Record, compile, and replay browser workflows end to end. Healthy runs make no model calls, and identity, effect, and policy coverage are enforced per bundle before anything executes. This is the reference loop that backs the managed hosted product."
+ "delivery": "Local, managed OpenAdapt Cloud, or customer-controlled",
+ "evidence_note": "Record, compile, and replay browser workflows end to end. Healthy runs make no model calls, and identity, effect, and policy coverage are enforced per bundle before governed execution. This is the reference loop behind the managed browser runner."
+ },
+ {
+ "name": "Windows",
+ "public_label": "Available",
+ "internal_tier": "qualified-uia",
+ "delivery": "Local or customer-controlled",
+ "evidence_note": "The released Windows UIA backend records, compiles, and replays native applications. The accepted WinForms matrix completed 3/3 independently verified effects and refused 3/3 stale targets plus 3/3 ambiguous targets, with zero silent incorrect successes, over-halts, or model calls.",
+ "evidence_url": "https://github.com/OpenAdaptAI/openadapt-flow/blob/defafbae758a75c8e149d9693f2cffe1f2264b8c/benchmark/windows_uia/results.json"
+ },
+ {
+ "name": "macOS",
+ "public_label": "Available",
+ "internal_tier": "qualified-native-window",
+ "delivery": "Local or customer-controlled",
+ "evidence_note": "The released native macOS backend binds one exact application window and refuses ambiguity before input. Counted TextEdit evidence confirmed 3/3 exact-byte effects plus a two-window ambiguity refusal, with zero silent incorrect successes or over-halts.",
+ "evidence_url": "https://github.com/OpenAdaptAI/openadapt-flow/blob/ca1b522cad215875f7471782283f8f8bb8e6c998/benchmark/macos_native/textedit_counted_3plus1_b1b61a5_20260717.adjudication.json"
+ },
+ {
+ "name": "Linux",
+ "public_label": "Available",
+ "internal_tier": "qualified-atspi-x11",
+ "delivery": "Local or customer-controlled",
+ "evidence_note": "The released Linux backend uses exact AT-SPI application and window binding. Required current-main CI confirmed 3/3 exact-file effects, 3/3 ambiguity refusals, and 3/3 stale-target refusals, with zero silent incorrect successes, over-halts, operator interventions, or model calls.",
+ "evidence_url": "https://github.com/OpenAdaptAI/openadapt-flow/actions/runs/30059807758/job/89378981573"
},
{
- "name": "Windows / macOS / RDP",
- "public_label": "Early access",
- "internal_tier": "scoped-acceptance",
- "evidence_note": "Operate native Windows, macOS, and RDP applications under the same governed loop: structured UI Automation and accessibility evidence, effect verification against an independent oracle, and fail-closed halting when verification does not pass. Validated on specific named tasks and environments, with execution provided by self-hosted or customer-controlled runtimes."
+ "name": "RDP",
+ "public_label": "Available",
+ "internal_tier": "qualified-remote-transport-and-lifecycle",
+ "delivery": "Local or customer-controlled",
+ "evidence_note": "RDP has two accepted bounded results: 3/3 real Aardwolf-over-Windows transport/input effects, and a full record-to-compile-to-governed-replay lifecycle over a real FreeRDP round trip with 3/3 healthy effects and 3/3 drift safe-halts. Both report zero model calls, silent incorrect successes, and over-halts.",
+ "evidence_url": "https://github.com/OpenAdaptAI/openadapt-flow/blob/affedc5f1f0de533a0744deaa8e30a203c91c6b3/benchmark/rdp_ladder/results.json"
},
{
"name": "Citrix / VDI",
- "public_label": "Exploratory",
- "internal_tier": "remote-window",
- "evidence_note": "Bringing the governed loop to Citrix and VDI remote application delivery, carrying identity, effect, and policy checks and halt-on-uncertainty into a pixel-and-evidence safety floor. The adapter contract is defined; real-environment ICA/HDX qualification remains the evidence gate."
+ "public_label": "Available",
+ "internal_tier": "qualified-citrix-workspace-window-contract",
+ "delivery": "Local or customer-controlled",
+ "evidence_note": "The released dedicated --backend citrix path binds the exact Citrix Workspace window, gates readiness, carries target metadata into durable resume, and runs the same pixel identity, effect, policy, and halt contracts. The accepted no-DOM qualification confirmed 3/3 healthy effects and 3/3 drift safe-halts with zero model calls, silent writes, false completions, or over-halts.",
+ "qualification_boundary": "The accepted artifact explicitly records ica_hdx_accepted=false. It qualifies the shipped Citrix Workspace-window backend contract over a no-DOM canvas stand-in, not a counted real ICA/HDX batch; an exact ICA/HDX environment is qualified separately before consequential use.",
+ "evidence_url": "https://github.com/OpenAdaptAI/openadapt-flow/blob/f6faac5b900b78cbda5980de0e983a9f987285ac/benchmark/citrix_workspace/results.json"
},
{
"name": "Hosted Cloud",
"public_label": "Beta",
"internal_tier": "managed-control-plane",
- "evidence_note": "The managed control plane provides governed browser execution, run history, reporting, usage, and workflow updates, backed by live billing. Desktop, RDP, and Citrix connect through self-hosted or customer-controlled runtimes. Runtime data handling and customer-controlled boundaries are configured per deployment."
+ "delivery": "Managed browser runner and control plane",
+ "evidence_note": "OpenAdapt Cloud provides governed managed browser execution, run history, reporting, usage, and workflow updates. Windows, macOS, Linux, RDP, and Citrix/VDI execute through local, self-hosted, or customer-controlled runtimes under the same governance model; they are not silently moved into the shared managed browser boundary."
}
]
}
diff --git a/tests/navContract.test.js b/tests/navContract.test.js
index 92276a5..2b6f37a 100644
--- a/tests/navContract.test.js
+++ b/tests/navContract.test.js
@@ -58,7 +58,7 @@ test('top navigation consolidates solutions, product and developer destinations'
assert.match(nav, /dropdown: SOLUTIONS_LINKS/)
for (const [label, href] of [
- ['How it runs', '/#product-status'],
+ ['Platforms & deployment', '/#product-status'],
['Safety', '/safety'],
['Compare', '/compare'],
['Templates', '/templates'],
diff --git a/tests/publicTruth.test.js b/tests/publicTruth.test.js
index a58bfc8..e1590d0 100644
--- a/tests/publicTruth.test.js
+++ b/tests/publicTruth.test.js
@@ -179,9 +179,11 @@ test('launch surfaces lead with capabilities instead of temporary gap labels', (
assert.match(product, /One execution model across your stack/)
assert.match(product, /Built for the interfaces your work depends on/)
assert.match(product, /Web applications/)
- assert.match(product, /Windows applications/)
- assert.match(product, /RDP, Citrix & VDI/)
- assert.match(product, /workflows stay inspectable, policy-bound/)
+ assert.match(product, /Desktop applications/)
+ assert.match(product, /Windows UI Automation, macOS Accessibility, or Linux AT-SPI/)
+ assert.match(product, /Remote applications/)
+ assert.match(product, /RDP, Citrix Workspace, and other VDI/)
+ assert.match(product, /workflows stay\s+inspectable, policy-bound/)
assert.match(product, /Every production workflow is qualified against its target application/)
assert.match(product, /tree\/main\/benchmark/)
assert.match(product, /docs\/LIMITS\.md/)
diff --git a/tests/statusManifest.test.js b/tests/statusManifest.test.js
index 26f5b8f..7e90077 100644
--- a/tests/statusManifest.test.js
+++ b/tests/statusManifest.test.js
@@ -9,45 +9,33 @@ const read = (relativePath) =>
const manifest = JSON.parse(read('public/status.json'))
-// The canonical public substrate labels. These are the single source of truth
-// that the website, docs (openadapt-ops), launcher README, masthead, and PyPI
-// metadata all reconcile to. Every substrate is first-class in the product; the
-// label is a maturity tier from the canonical ladder (manifest.tiers) that says
-// how broadly the substrate has been exercised today. "Scoped" is never a
-// public label — the ladder is Beta / Early access / Exploratory / Research.
const CANONICAL_LABELS = {
- Browser: 'Beta',
- 'Windows / macOS / RDP': 'Early access',
- 'Citrix / VDI': 'Exploratory',
+ Browser: 'Available',
+ Windows: 'Available',
+ macOS: 'Available',
+ Linux: 'Available',
+ RDP: 'Available',
+ 'Citrix / VDI': 'Available',
'Hosted Cloud': 'Beta',
}
-// The canonical maturity ladder. Every public label must be one of these tiers,
-// and each tier must carry a plain-language definition so any surface that shows
-// the ladder can render a legend.
-const CANONICAL_TIERS = ['Beta', 'Early access', 'Exploratory', 'Research']
+const CANONICAL_TIERS = ['Available', 'Beta']
-// Component versions verified against PyPI on 2026-07-19.
+// Verified against the public releases on 2026-07-24.
const CANONICAL_VERSIONS = {
launcher: '1.7.1',
- flow: '1.19.0',
- desktop: '0.6.2',
+ flow: '1.20.1',
+ desktop: '0.9.0',
}
-test('status manifest labels every substrate with a canonical maturity tier', () => {
+test('status manifest separates released substrate availability from evidence scope', () => {
const byName = Object.fromEntries(
manifest.substrates.map((s) => [s.name, s.public_label])
)
assert.deepEqual(byName, CANONICAL_LABELS)
+ assert.equal(manifest.product_lifecycle, 'Beta')
- // "Scoped" is the confusing label this ladder replaces — it must not appear
- // as any public label.
for (const substrate of manifest.substrates) {
- assert.doesNotMatch(
- substrate.public_label,
- /scoped/i,
- `${substrate.name} public_label must not use the ambiguous "scoped"`
- )
assert.ok(
CANONICAL_TIERS.includes(substrate.public_label),
`${substrate.name} public_label must be a canonical tier`
@@ -56,82 +44,97 @@ test('status manifest labels every substrate with a canonical maturity tier', ()
substrate.evidence_note && substrate.evidence_note.length > 40,
`${substrate.name} must carry a capability note`
)
+ assert.ok(
+ typeof substrate.delivery === 'string' &&
+ substrate.delivery.length > 0,
+ `${substrate.name} must record its delivery boundary`
+ )
assert.ok(
typeof substrate.internal_tier === 'string' &&
substrate.internal_tier.length > 0,
`${substrate.name} must record an internal tier`
)
+ assert.doesNotMatch(
+ `${substrate.public_label} ${substrate.evidence_note}`,
+ /early access|exploratory|research|design.partner/i
+ )
}
})
-test('status manifest defines the canonical ladder with plain definitions', () => {
- assert.ok(manifest.tiers && typeof manifest.tiers === 'object')
+test('status manifest defines its public labels in plain language', () => {
assert.deepEqual(Object.keys(manifest.tiers), CANONICAL_TIERS)
for (const tier of CANONICAL_TIERS) {
- assert.ok(
- typeof manifest.tiers[tier] === 'string' &&
- manifest.tiers[tier].length > 20,
- `tier ${tier} must carry a plain-language definition`
- )
+ assert.ok(manifest.tiers[tier].length > 20)
}
- // Every label actually used must be defined in the ladder.
for (const substrate of manifest.substrates) {
- assert.ok(
- manifest.tiers[substrate.public_label],
- `${substrate.public_label} must be defined in manifest.tiers`
- )
+ assert.ok(manifest.tiers[substrate.public_label])
}
})
-test('status manifest describes its machine-readable role exactly', () => {
- assert.match(manifest.$comment, /machine-readable status evidence/)
- assert.match(manifest.$comment, /status-aware website surfaces and tests/)
+test('status manifest describes release, capability, evidence, and deployment status', () => {
assert.match(
manifest.$comment,
- /homepage presents product capabilities without rendering this maturity ledger/
+ /machine-readable release, capability, evidence, and deployment status/
)
- assert.doesNotMatch(manifest.$comment, /imported directly by the homepage/)
+ assert.match(manifest.$comment, /Windows, macOS, Linux, RDP, and Citrix/)
+ assert.match(manifest.$comment, /distinct from the deployment boundary/)
})
-test('hosted cloud scope is browser-only, matching the TOS and checkout gate', () => {
- // The managed subscription is a browser-only Beta by the site's own
- // machinery (lib/hostedOfferContract.js requires substrate=browser +
- // lifecycle=beta; the TOS calls it a Beta browser launch service). The
- // manifest note must not resell it as running across every substrate.
+test('bounded substrate evidence is exact and linked', () => {
+ const byName = Object.fromEntries(
+ manifest.substrates.map((s) => [s.name, s])
+ )
+
+ assert.match(byName.Windows.evidence_note, /3\/3 independently verified effects/)
+ assert.match(byName.Windows.evidence_note, /3\/3 stale targets/)
+ assert.match(byName.Windows.evidence_note, /3\/3 ambiguous targets/)
+
+ assert.match(byName.macOS.evidence_note, /3\/3 exact-byte effects/)
+ assert.match(byName.macOS.evidence_note, /two-window ambiguity refusal/)
+
+ assert.match(byName.Linux.evidence_note, /3\/3 exact-file effects/)
+ assert.match(byName.Linux.evidence_note, /3\/3 ambiguity refusals/)
+ assert.match(byName.Linux.evidence_note, /3\/3 stale-target refusals/)
+ assert.match(byName.Linux.evidence_url, /30059807758\/job\/89378981573/)
+
+ assert.match(byName.RDP.evidence_note, /Aardwolf-over-Windows/)
+ assert.match(byName.RDP.evidence_note, /FreeRDP round trip/)
+ assert.match(byName.RDP.evidence_note, /3\/3 drift safe-halts/)
+
+ const citrix = byName['Citrix / VDI']
+ assert.match(citrix.evidence_note, /dedicated --backend citrix/)
+ assert.match(citrix.evidence_note, /3\/3 healthy effects/)
+ assert.match(citrix.evidence_note, /3\/3 drift safe-halts/)
+ assert.match(citrix.qualification_boundary, /ica_hdx_accepted=false/)
+ assert.match(citrix.qualification_boundary, /not a counted real ICA\/HDX batch/)
+
+ for (const name of ['Windows', 'macOS', 'Linux', 'RDP', 'Citrix / VDI']) {
+ assert.match(byName[name].evidence_url, /^https:\/\/github\.com\//)
+ }
+})
+
+test('hosted cloud scope stays managed-browser-only', () => {
const hosted = manifest.substrates.find((s) => s.name === 'Hosted Cloud')
assert.equal(hosted.public_label, 'Beta')
- assert.match(hosted.evidence_note, /browser (workflows|execution)/i)
+ assert.match(hosted.delivery, /Managed browser runner/)
+ assert.match(hosted.evidence_note, /managed browser execution/i)
assert.doesNotMatch(hosted.evidence_note, /across every substrate/i)
- assert.match(
- hosted.evidence_note,
- /self-hosted|customer-controlled/i,
- 'hosted note must route non-browser substrates to self-hosted / on-prem'
- )
+ assert.match(hosted.evidence_note, /local, self-hosted, or customer-controlled/i)
})
test('status manifest encodes the verified component versions', () => {
assert.deepEqual(manifest.versions, CANONICAL_VERSIONS)
- assert.match(manifest.generated_at, /^\d{4}-\d{2}-\d{2}$/)
+ assert.equal(manifest.generated_at, '2026-07-24')
})
-test('homepage presents capabilities without exposing the maturity ledger', () => {
- // The sales page describes the target product capability. The public status
- // manifest remains available to technical consumers, but transient maturity
- // labels and component versions do not belong in the homepage narrative.
+test('homepage presents coherent desktop and remote dimensions', () => {
const product = read('components/ProductStatus.js')
assert.doesNotMatch(product, /public\/status\.json/)
assert.doesNotMatch(product, /status\.substrates|substrate\.public_label/)
- assert.doesNotMatch(product, /status\.tiers|status\.versions/)
assert.match(product, /Web applications/)
- assert.match(product, /Windows applications/)
- assert.match(product, /RDP, Citrix & VDI/)
-
- for (const label of Object.values(CANONICAL_LABELS)) {
- assert.doesNotMatch(
- product,
- new RegExp(`['"\\s]${label}['"\\s]`),
- `ProductStatus must not render the temporary "${label}" label`
- )
- }
+ assert.match(product, /Desktop applications/)
+ assert.match(product, /Windows UI Automation, macOS Accessibility, or Linux AT-SPI/)
+ assert.match(product, /Remote applications/)
+ assert.match(product, /RDP, Citrix Workspace, and other VDI/)
})
diff --git a/tests/workflowCatalog.test.js b/tests/workflowCatalog.test.js
index 0a5e1d8..26fe3e1 100644
--- a/tests/workflowCatalog.test.js
+++ b/tests/workflowCatalog.test.js
@@ -81,26 +81,20 @@ test('every catalog entry carries the required honesty fields', () => {
}
})
-test('every substrate carries a canonical maturity tier reconciled to status.json', () => {
- // Labels reconcile to public/status.json (the single source of truth):
- // Beta = broadly exercised (browser); Early access = validated on specific
- // named tasks (Windows / macOS / RDP); Exploratory = no validated
- // real-environment integration yet (Citrix). "Supported" and the ambiguous
- // "scoped" are never used as public labels here.
+test('every released substrate is available and reconciled to status.json', () => {
const expected = {
- browser: 'Beta',
- windows: 'Early access',
- macos: 'Early access',
- rdp: 'Early access',
- citrix: 'Exploratory',
+ browser: 'Available',
+ windows: 'Available',
+ macos: 'Available',
+ linux: 'Available',
+ rdp: 'Available',
+ citrix: 'Available',
}
// Field-by-field: SUBSTRATE_MATURITY comes from a vm sandbox, so its
// prototype is not reference-equal to a plain object literal here.
assert.deepEqual({ ...SUBSTRATE_MATURITY }, expected)
- for (const label of Object.values(SUBSTRATE_MATURITY)) {
- assert.doesNotMatch(label, /scoped|supported/i)
- }
- // The three catalog entries are all browser fixtures, so they carry Beta.
+ // The three catalog entries are all browser fixtures, so they carry the
+ // browser availability label. Their task-level evidence remains separate.
for (const entry of CATALOG) {
assert.equal(entry.substrate, 'browser', `${entry.id} substrate`)
assert.equal(