feat(gstack2): add capability readiness process#11
Conversation
…/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>
|
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. |
There was a problem hiding this comment.
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
| 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; |
There was a problem hiding this comment.
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>
| 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"; |
There was a problem hiding this comment.
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>
|
|
||
| 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. |
There was a problem hiding this comment.
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>
| 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. |
| | | ||
| +-- unsupported ----> judgment-only work or supported platform | ||
| | | ||
| +-- unavailable/failed |
There was a problem hiding this comment.
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>
| 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)) { |
There was a problem hiding this comment.
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>
| if (capability && !CAPABILITY_READINESS_CAPABILITIES.includes(capability)) { | |
| if (capability !== undefined && !CAPABILITY_READINESS_CAPABILITIES.includes(capability)) { |
| 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 |
There was a problem hiding this comment.
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>
|
Superseded by #10. The consolidated PR now includes this capability-readiness work plus the |
Summary
Adds a capability-readiness process to the GStack 2 optional runtime, exposed as a non-mutating command:
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, orfailed. The command never grants consent, previews metadata, or installs anything. Physical iOS off macOS returnsunsupportedwithout disabling pure judgment.Substantive commits:
capabilityReadiness()doctor projection +formatCapabilityReadiness(), the--capabilityCLI 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.failed/exit 1 (matching plaingstack doctor) instead ofdegraded/exit 0.(The merge commit with
codex/gstack-2is 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.test:gstack2): 223 pass / 0 failbun test, skill validation + browse integration): passgstack doctor --capability pdf(+--json, bad-capability guard) — correct axes, exit 1 uninstalled, exit 2 on unknown capability, non-mutatingPre-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 plaingstack doctorreported exit 1 for the identical report. Surfaced by an adversarial review pass, fixed by gatingdegradedon runtimewarnand mapping runtimefailtofailed, 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
doctorsubcommand). Paid evals not run.Documentation
Shipped with the change: README troubleshooting section points at the new command;
docs/gstack-2/CAPABILITY-READINESS.mddocuments the state machine; all six skillRUNTIME.mdreferences carry the readiness contract.Notes
Versioning intentionally skipped at the author's request (personal fork): no VERSION bump, no CHANGELOG entry.
Test plan
bun test: passDo 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 withgstack doctorwhen the managed runtime hard-fails.New Features
--capabilityflag returns a focused, non‑mutating result in human or--jsonform.ready,degraded,unavailable,unsupported,failed; non‑ready exits 1, usage errors exit 2.formatCapabilityReadiness(), CLI wiring, usage help, anddocs/gstack-2/CAPABILITY-READINESS.md; README and skillRUNTIME.mdreferences updated.Bug Fixes
failed/ok:false/exit 1 (wasdegraded/ok:true), with a regression test.Written for commit e6f0018. Summary will update on new commits.