Skip to content

feat(gstack2): add capability readiness process#11

Closed
time-attack wants to merge 3 commits into
codex/gstack-2from
time-attack/Add-capability-readiness-process-2
Closed

feat(gstack2): add capability readiness process#11
time-attack wants to merge 3 commits into
codex/gstack-2from
time-attack/Add-capability-readiness-process-2

Conversation

@time-attack

@time-attack time-attack commented Jul 21, 2026

Copy link
Copy Markdown
Owner

Summary

Adds a capability-readiness process to the GStack 2 optional runtime, exposed as a non-mutating command:

gstack doctor --capability browser|design|diagram|pdf|ios [--json]

It keeps five independent axes separate — pure-judgment availability (always on), platform support, preview consent, install consent, and runtime readiness — so "not installed" is never treated as a product failure and preview approval is never conflated with install approval. Readiness resolves to exactly one of ready, degraded, unavailable, unsupported, or failed. The command never grants consent, previews metadata, or installs anything. Physical iOS off macOS returns unsupported without disabling pure judgment.

Substantive commits:

  • feat(gstack2): add capability readiness process — the capabilityReadiness() doctor projection + formatCapabilityReadiness(), the --capability CLI flag wired into the existing doctor result envelope and exit-code contract, docs/gstack-2/CAPABILITY-READINESS.md, a README troubleshooting update, and all six regenerated runtime references.
  • fix(gstack2): treat hard runtime failure as not-ready — a capability whose binary launches under a hard-failed managed runtime now reports failed/exit 1 (matching plain gstack doctor) instead of degraded/exit 0.

(The merge commit with codex/gstack-2 is bookkeeping, not a substantive change.)

Test Coverage

Focused suite test/gstack2-capability-readiness.test.ts: 5 tests — unavailable/ready/degraded/failed (incl. the runtime-fail regression), iOS-unsupported-off-darwin, human output across all axes, and an end-to-end non-mutating JSON run. All new code paths covered.

  • Full GStack 2 suite (test:gstack2): 223 pass / 0 fail
  • Free gate (bun test, skill validation + browse integration): pass
  • CLI smoke: gstack doctor --capability pdf (+ --json, bad-capability guard) — correct axes, exit 1 uninstalled, exit 2 on unknown capability, non-mutating

Pre-Landing Review

1 finding (informational), fixed: an exit-code divergence where a capability launching under a hard-failed runtime reported ok:true/exit 0 while plain gstack doctor reported exit 1 for the identical report. Surfaced by an adversarial review pass, fixed by gating degraded on runtime warn and mapping runtime fail to failed, and locked with a regression test. No other issues.

Design Review

No frontend files changed — design review skipped.

Eval Results

No skill judgment logic changed (additive doc paragraph + a new doctor subcommand). Paid evals not run.

Documentation

Shipped with the change: README troubleshooting section points at the new command; docs/gstack-2/CAPABILITY-READINESS.md documents the state machine; all six skill RUNTIME.md references carry the readiness contract.

Notes

Versioning intentionally skipped at the author's request (personal fork): no VERSION bump, no CHANGELOG entry.

Test plan

  • GStack 2 suite: 223 pass / 0 fail
  • Free gate bun test: pass
  • CLI smoke + exit codes verified

Do NOT merge — awaiting explicit confirmation.

🤖 Generated with Claude Code


Summary by cubic

Adds a capability readiness check to GStack 2 via gstack doctor --capability browser|design|diagram|pdf|ios, reporting readiness without changing the machine. Aligns exit codes with gstack doctor when the managed runtime hard-fails.

  • New Features

    • --capability flag returns a focused, non‑mutating result in human or --json form.
    • Reports five independent axes: judgment availability, platform support, preview consent, install consent, and runtime readiness.
    • Readiness is one of: ready, degraded, unavailable, unsupported, failed; non‑ready exits 1, usage errors exit 2.
    • Adds formatCapabilityReadiness(), CLI wiring, usage help, and docs/gstack-2/CAPABILITY-READINESS.md; README and skill RUNTIME.md references updated.
  • Bug Fixes

    • A capability under a hard‑failed managed runtime now reports failed/ok:false/exit 1 (was degraded/ok:true), with a regression test.

Written for commit e6f0018. Summary will update on new commits.

Review in cubic

Sinabina and others added 3 commits July 21, 2026 13:03
…/Add-capability-readiness-process-2

# Conflicts:
#	scripts/gstack2/generate-skill-tree.ts
#	skills/debug/references/RUNTIME.md
#	skills/design/references/RUNTIME.md
#	skills/plan/references/RUNTIME.md
#	skills/qa/references/RUNTIME.md
#	skills/review/references/RUNTIME.md
#	skills/ship/references/RUNTIME.md
…eadiness

A capability whose binary launches while the managed runtime hard-fails
(e.g. skill-API mismatch) was reported as `degraded`/ok:true/exit 0, diverging
from plain `gstack doctor` (ok:false/exit 1) for the identical report. Split
the branch so runtime `warn` stays `degraded` and runtime `fail` maps to
`failed`, and add a regression test for the runtime-fail + capability-pass case.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@cursor

cursor Bot commented Jul 21, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

6 issues found across 12 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="scripts/gstack2/generate-skill-tree.ts">

<violation number="1" location="scripts/gstack2/generate-skill-tree.ts:517">
P2: The documented command fails if copied because `|` is interpreted by the shell as a pipeline. Using a `<name>` placeholder and listing the accepted names separately keeps the example executable and unambiguous.</violation>
</file>

<file name="docs/gstack-2/CAPABILITY-READINESS.md">

<violation number="1" location="docs/gstack-2/CAPABILITY-READINESS.md:52">
P2: The flow sends every `failed` result through bootstrap preview/install, but several failed states cannot be repaired that way. Separate `unavailable` setup from `failed` evidence-specific remediation so users do not reinstall an already-selected capability unnecessarily.</violation>

<violation number="2" location="docs/gstack-2/CAPABILITY-READINESS.md:73">
P3: Browser-backed readiness requires an explicit provider choice, so “do not ... add a browser provider” can mislead users into avoiding the supported configuration step. Clarify that the prohibition applies to adding a new/alternate provider implementation, not selecting an existing provider.</violation>
</file>

<file name="runtime/cli.js">

<violation number="1" location="runtime/cli.js:166">
P2: An explicitly empty capability is silently ignored, so `gstack doctor --capability ""` runs plain doctor instead of exiting 2 for an unknown/missing value. Checking presence against `undefined` ensures every supplied value is validated.</violation>

<violation number="2" location="runtime/cli.js:170">
P1: A capability assessment can roll back and rewrite a pending runtime pointer, despite this command’s non-mutating contract. The focused path still runs `runDoctor()`, whose `recoverPendingUpgrade()` performs recovery writes; it should use an inspection-only path instead.</violation>
</file>

<file name="runtime/doctor.js">

<violation number="1" location="runtime/doctor.js:249">
P1: `gstack doctor --capability diagram|pdf` can return `ready` (or `degraded`) and exit 0 when required browser readiness failed, because this projection ignores `RUNTIME_CAPABILITY_DEPENDENCIES[capability]`. Include those capability checks when deriving status and readiness evidence.</violation>
</file>

Tip: instead of fixing issues one by one fix them all with cubic

Re-trigger cubic

Comment thread runtime/cli.js
const report = await runDoctor({ home, cwd, expectedSkillApi: parsed.values.get("--skill-api") });
write(stdout, parsed.flags.has("--json") ? `${JSON.stringify(report, null, 2)}\n` : formatDoctor(report));
return report.ok ? 0 : 1;
const result = capability ? capabilityReadiness(report, capability) : report;

@cubic-dev-ai cubic-dev-ai Bot Jul 21, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1: A capability assessment can roll back and rewrite a pending runtime pointer, despite this command’s non-mutating contract. The focused path still runs runDoctor(), whose recoverPendingUpgrade() performs recovery writes; it should use an inspection-only path instead.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At runtime/cli.js, line 170:

<comment>A capability assessment can roll back and rewrite a pending runtime pointer, despite this command’s non-mutating contract. The focused path still runs `runDoctor()`, whose `recoverPendingUpgrade()` performs recovery writes; it should use an inspection-only path instead.</comment>

<file context>
@@ -154,11 +160,18 @@ async function initCommand({ args, home, cwd, stdout, legacyAlias = false }) {
   const report = await runDoctor({ home, cwd, expectedSkillApi: parsed.values.get("--skill-api") });
-  write(stdout, parsed.flags.has("--json") ? `${JSON.stringify(report, null, 2)}\n` : formatDoctor(report));
-  return report.ok ? 0 : 1;
+  const result = capability ? capabilityReadiness(report, capability) : report;
+  write(stdout, parsed.flags.has("--json")
+    ? `${JSON.stringify(result, null, 2)}\n`
</file context>
Fix with cubic

Comment thread runtime/doctor.js
const capabilityCheck = report.checks.find((check) => check.id === `capability:${capability}`);
const runtimeCheck = report.checks.find((check) => check.id === "managed-runtime");
let status;
if (capabilityCheck?.status === "pass" && runtimeCheck?.status === "pass") status = "ready";

@cubic-dev-ai cubic-dev-ai Bot Jul 21, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1: gstack doctor --capability diagram|pdf can return ready (or degraded) and exit 0 when required browser readiness failed, because this projection ignores RUNTIME_CAPABILITY_DEPENDENCIES[capability]. Include those capability checks when deriving status and readiness evidence.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At runtime/doctor.js, line 249:

<comment>`gstack doctor --capability diagram|pdf` can return `ready` (or `degraded`) and exit 0 when required browser readiness failed, because this projection ignores `RUNTIME_CAPABILITY_DEPENDENCIES[capability]`. Include those capability checks when deriving status and readiness evidence.</comment>

<file context>
@@ -209,6 +217,83 @@ export async function runDoctor(options = {}) {
+  const capabilityCheck = report.checks.find((check) => check.id === `capability:${capability}`);
+  const runtimeCheck = report.checks.find((check) => check.id === "managed-runtime");
+  let status;
+  if (capabilityCheck?.status === "pass" && runtimeCheck?.status === "pass") status = "ready";
+  else if (capabilityCheck?.status === "pass" && runtimeCheck?.status === "warn") status = "degraded";
+  else if (capabilityCheck?.status === "pass") status = "failed";
</file context>
Fix with cubic


The package/runtime compatibility tuple is \`schemaVersion=1\`, \`runtimeVersion=2.0.0\`, and \`skillApi=2.0\`; the machine-readable copy is \`references/support/runtime-contract.json\`. An incompatible active runtime is unavailable, not permission to upgrade it.

Use \`gstack doctor --capability browser|design|diagram|pdf|ios\` (optionally \`--json\`) for a non-mutating, capability-specific readiness result. Its independent axes must remain distinct: pure judgment availability, platform support, preview consent, install consent, and runtime readiness. Readiness is exactly \`ready\`, \`degraded\`, \`unavailable\`, \`unsupported\`, or \`failed\`. Doctor never grants or persists consent, previews metadata, or installs anything. \`unavailable\` means setup may be offered; \`failed\` means selected runtime evidence failed; \`unsupported\` is a platform boundary; and \`degraded\` means the capability passed while the managed runtime has a warning.

@cubic-dev-ai cubic-dev-ai Bot Jul 21, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: The documented command fails if copied because | is interpreted by the shell as a pipeline. Using a <name> placeholder and listing the accepted names separately keeps the example executable and unambiguous.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At scripts/gstack2/generate-skill-tree.ts, line 517:

<comment>The documented command fails if copied because `|` is interpreted by the shell as a pipeline. Using a `<name>` placeholder and listing the accepted names separately keeps the example executable and unambiguous.</comment>

<file context>
@@ -514,6 +514,8 @@ Some retained helpers are shell scripts. \`gstack doctor\` verifies Bash and, on
 
 The package/runtime compatibility tuple is \`schemaVersion=1\`, \`runtimeVersion=2.0.0\`, and \`skillApi=2.0\`; the machine-readable copy is \`references/support/runtime-contract.json\`. An incompatible active runtime is unavailable, not permission to upgrade it.
 
+Use \`gstack doctor --capability browser|design|diagram|pdf|ios\` (optionally \`--json\`) for a non-mutating, capability-specific readiness result. Its independent axes must remain distinct: pure judgment availability, platform support, preview consent, install consent, and runtime readiness. Readiness is exactly \`ready\`, \`degraded\`, \`unavailable\`, \`unsupported\`, or \`failed\`. Doctor never grants or persists consent, previews metadata, or installs anything. \`unavailable\` means setup may be offered; \`failed\` means selected runtime evidence failed; \`unsupported\` is a platform boundary; and \`degraded\` means the capability passed while the managed runtime has a warning.
+
 The developer-only fallback is \`node references/support/runtime-bootstrap.mjs install --source <reviewed-checkout> --capability <name> [matching browser flags] --yes\`; show its trust warning and use it only when the user explicitly selects a checkout they reviewed. If the packaged bootstrap is unavailable, stop capability setup instead of guessing a checkout-relative command. Deferring installation records no consent and must not block pure judgment.
</file context>
Suggested change
Use \`gstack doctor --capability browser|design|diagram|pdf|ios\` (optionally \`--json\`) for a non-mutating, capability-specific readiness result. Its independent axes must remain distinct: pure judgment availability, platform support, preview consent, install consent, and runtime readiness. Readiness is exactly \`ready\`, \`degraded\`, \`unavailable\`, \`unsupported\`, or \`failed\`. Doctor never grants or persists consent, previews metadata, or installs anything. \`unavailable\` means setup may be offered; \`failed\` means selected runtime evidence failed; \`unsupported\` is a platform boundary; and \`degraded\` means the capability passed while the managed runtime has a warning.
Use \`gstack doctor --capability <name>\` (optionally \`--json\`) for a non-mutating, capability-specific readiness result, where \`<name>\` is \`browser\`, \`design\`, \`diagram\`, \`pdf\`, or \`ios\`. Its independent axes must remain distinct: pure judgment availability, platform support, preview consent, install consent, and runtime readiness. Readiness is exactly \`ready\`, \`degraded\`, \`unavailable\`, \`unsupported\`, or \`failed\`. Doctor never grants or persists consent, previews metadata, or installs anything. \`unavailable\` means setup may be offered; \`failed\` means selected runtime evidence failed; \`unsupported\` is a platform boundary; and \`degraded\` means the capability passed while the managed runtime has a warning.
Fix with cubic

|
+-- unsupported ----> judgment-only work or supported platform
|
+-- unavailable/failed

@cubic-dev-ai cubic-dev-ai Bot Jul 21, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: The flow sends every failed result through bootstrap preview/install, but several failed states cannot be repaired that way. Separate unavailable setup from failed evidence-specific remediation so users do not reinstall an already-selected capability unnecessarily.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At docs/gstack-2/CAPABILITY-READINESS.md, line 52:

<comment>The flow sends every `failed` result through bootstrap preview/install, but several failed states cannot be repaired that way. Separate `unavailable` setup from `failed` evidence-specific remediation so users do not reinstall an already-selected capability unnecessarily.</comment>

<file context>
@@ -0,0 +1,75 @@
+          |
+          +-- unsupported ----> judgment-only work or supported platform
+          |
+          +-- unavailable/failed
+                    |
+                    v
</file context>
Fix with cubic

Comment thread runtime/cli.js
const parsed = parseFlags(args, new Set(["--json", "--skill-api", "--capability"]));
if (parsed.positionals.length) throw cliError("Doctor accepts only named options", "USAGE");
const capability = parsed.values.get("--capability");
if (capability && !CAPABILITY_READINESS_CAPABILITIES.includes(capability)) {

@cubic-dev-ai cubic-dev-ai Bot Jul 21, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: An explicitly empty capability is silently ignored, so gstack doctor --capability "" runs plain doctor instead of exiting 2 for an unknown/missing value. Checking presence against undefined ensures every supplied value is validated.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At runtime/cli.js, line 166:

<comment>An explicitly empty capability is silently ignored, so `gstack doctor --capability ""` runs plain doctor instead of exiting 2 for an unknown/missing value. Checking presence against `undefined` ensures every supplied value is validated.</comment>

<file context>
@@ -154,11 +160,18 @@ async function initCommand({ args, home, cwd, stdout, legacyAlias = false }) {
+  const parsed = parseFlags(args, new Set(["--json", "--skill-api", "--capability"]));
   if (parsed.positionals.length) throw cliError("Doctor accepts only named options", "USAGE");
+  const capability = parsed.values.get("--capability");
+  if (capability && !CAPABILITY_READINESS_CAPABILITIES.includes(capability)) {
+    throw cliError(`Unknown capability: ${capability}. Choose ${CAPABILITY_READINESS_CAPABILITIES.join(", ")}.`, "USAGE");
+  }
</file context>
Suggested change
if (capability && !CAPABILITY_READINESS_CAPABILITIES.includes(capability)) {
if (capability !== undefined && !CAPABILITY_READINESS_CAPABILITIES.includes(capability)) {
Fix with cubic

Preview consent is not install consent. Deferring either does not block pure
judgment. Follow the packaged bootstrap contract for exact dependency closure,
compressed bytes, signature checks, and atomic installation. Do not run setup
from a standards-installed skill directory, add a browser provider, replace the

@cubic-dev-ai cubic-dev-ai Bot Jul 21, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P3: Browser-backed readiness requires an explicit provider choice, so “do not ... add a browser provider” can mislead users into avoiding the supported configuration step. Clarify that the prohibition applies to adding a new/alternate provider implementation, not selecting an existing provider.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At docs/gstack-2/CAPABILITY-READINESS.md, line 73:

<comment>Browser-backed readiness requires an explicit provider choice, so “do not ... add a browser provider” can mislead users into avoiding the supported configuration step. Clarify that the prohibition applies to adding a new/alternate provider implementation, not selecting an existing provider.</comment>

<file context>
@@ -0,0 +1,75 @@
+Preview consent is not install consent. Deferring either does not block pure
+judgment. Follow the packaged bootstrap contract for exact dependency closure,
+compressed bytes, signature checks, and atomic installation. Do not run setup
+from a standards-installed skill directory, add a browser provider, replace the
+local Chromium/Playwright backend, or replace the physical-iOS
+DebugBridge/CoreDevice harness.
</file context>
Fix with cubic

@time-attack

Copy link
Copy Markdown
Owner Author

Superseded by #10. The consolidated PR now includes this capability-readiness work plus the e6f0018b runtime-fail→failed fix (cherry-picked), so this content lands there. Closing to avoid three overlapping PRs into codex/gstack-2.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant