From e41a5e5374d4d60250c2e9b9814f906738684995 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sun, 6 Sep 2026 12:02:37 +0000 Subject: [PATCH] chore(openspec): drop working-tree archive history Remove leftover openspec/changes/archive/ so completed archaeology lives only in git history. Leave deferred in-flight OpenSpec changes in place. Add a product-path keep comment so classify runs the macOS test matrix. --- .../.openspec.yaml | 2 - .../design.md | 87 ------- .../proposal.md | 76 ------ .../specs/ci-platform-coverage/spec.md | 27 -- .../specs/code-quality-tooling/spec.md | 92 ------- .../specs/core-installation-soak/spec.md | 15 -- .../specs/core-npm-release/spec.md | 15 -- .../specs/installation-routing/spec.md | 39 --- .../specs/project-memory/spec.md | 9 - .../specs/release-governance/spec.md | 69 ------ .../specs/release-note-input/spec.md | 15 -- .../specs/release-workflow/spec.md | 233 ------------------ .../tasks.md | 61 ----- .../.openspec.yaml | 2 - .../proposal.md | 48 ---- .../specs/release-workflow/spec.md | 25 -- .../tasks.md | 34 --- .../.openspec.yaml | 2 - .../proposal.md | 42 ---- .../specs/code-quality-tooling/spec.md | 28 --- .../tasks.md | 28 --- .../.openspec.yaml | 2 - .../proposal.md | 43 ---- .../specs/code-quality-tooling/spec.md | 47 ---- .../specs/project-memory/spec.md | 15 -- .../specs/release-workflow/spec.md | 57 ----- .../tasks.md | 46 ---- .../.openspec.yaml | 2 - .../design.md | 43 ---- .../proposal.md | 26 -- .../specs/quantex-state/spec.md | 29 --- .../tasks.md | 15 -- .../.openspec.yaml | 2 - .../design.md | 37 --- .../proposal.md | 27 -- .../specs/agent-uninstall/spec.md | 27 -- .../tasks.md | 16 -- .../.openspec.yaml | 2 - .../proposal.md | 48 ---- .../specs/code-quality-tooling/spec.md | 9 - .../specs/release-workflow/spec.md | 9 - .../tasks.md | 37 --- .../.openspec.yaml | 2 - .../proposal.md | 36 --- .../specs/release-workflow/spec.md | 30 --- .../tasks.md | 28 --- .../.openspec.yaml | 2 - .../design.md | 50 ---- .../proposal.md | 31 --- .../specs/code-quality-tooling/spec.md | 50 ---- .../specs/product-readme/spec.md | 23 -- .../specs/project-memory/spec.md | 19 -- .../specs/release-workflow/spec.md | 13 - .../tasks.md | 21 -- .../.openspec.yaml | 2 - .../design.md | 54 ---- .../proposal.md | 38 --- .../specs/agent-version-probing/spec.md | 39 --- .../tasks.md | 21 -- .../.openspec.yaml | 2 - .../design.md | 64 ----- .../proposal.md | 32 --- .../specs/release-workflow/spec.md | 44 ---- .../tasks.md | 23 -- .../.openspec.yaml | 2 - .../design.md | 52 ---- .../proposal.md | 34 --- .../specs/agent-update/spec.md | 6 - .../specs/cli-contract-registry/spec.md | 6 - .../specs/macos-desktop-client/spec.md | 41 --- .../specs/package-distribution/spec.md | 11 - .../tasks.md | 21 -- .../.openspec.yaml | 2 - .../design.md | 57 ----- .../proposal.md | 30 --- .../specs/agent-canary-validation/spec.md | 42 ---- .../tasks.md | 24 -- src/lifecycle/uninstall-postcondition.ts | 1 + 78 files changed, 1 insertion(+), 2440 deletions(-) delete mode 100644 openspec/changes/archive/2026-08-05-redesign-project-workflow/.openspec.yaml delete mode 100644 openspec/changes/archive/2026-08-05-redesign-project-workflow/design.md delete mode 100644 openspec/changes/archive/2026-08-05-redesign-project-workflow/proposal.md delete mode 100644 openspec/changes/archive/2026-08-05-redesign-project-workflow/specs/ci-platform-coverage/spec.md delete mode 100644 openspec/changes/archive/2026-08-05-redesign-project-workflow/specs/code-quality-tooling/spec.md delete mode 100644 openspec/changes/archive/2026-08-05-redesign-project-workflow/specs/core-installation-soak/spec.md delete mode 100644 openspec/changes/archive/2026-08-05-redesign-project-workflow/specs/core-npm-release/spec.md delete mode 100644 openspec/changes/archive/2026-08-05-redesign-project-workflow/specs/installation-routing/spec.md delete mode 100644 openspec/changes/archive/2026-08-05-redesign-project-workflow/specs/project-memory/spec.md delete mode 100644 openspec/changes/archive/2026-08-05-redesign-project-workflow/specs/release-governance/spec.md delete mode 100644 openspec/changes/archive/2026-08-05-redesign-project-workflow/specs/release-note-input/spec.md delete mode 100644 openspec/changes/archive/2026-08-05-redesign-project-workflow/specs/release-workflow/spec.md delete mode 100644 openspec/changes/archive/2026-08-05-redesign-project-workflow/tasks.md delete mode 100644 openspec/changes/archive/2026-08-06-align-governance-gates/.openspec.yaml delete mode 100644 openspec/changes/archive/2026-08-06-align-governance-gates/proposal.md delete mode 100644 openspec/changes/archive/2026-08-06-align-governance-gates/specs/release-workflow/spec.md delete mode 100644 openspec/changes/archive/2026-08-06-align-governance-gates/tasks.md delete mode 100644 openspec/changes/archive/2026-08-06-drop-windows-thread-pool/.openspec.yaml delete mode 100644 openspec/changes/archive/2026-08-06-drop-windows-thread-pool/proposal.md delete mode 100644 openspec/changes/archive/2026-08-06-drop-windows-thread-pool/specs/code-quality-tooling/spec.md delete mode 100644 openspec/changes/archive/2026-08-06-drop-windows-thread-pool/tasks.md delete mode 100644 openspec/changes/archive/2026-08-06-finish-governance-followups/.openspec.yaml delete mode 100644 openspec/changes/archive/2026-08-06-finish-governance-followups/proposal.md delete mode 100644 openspec/changes/archive/2026-08-06-finish-governance-followups/specs/code-quality-tooling/spec.md delete mode 100644 openspec/changes/archive/2026-08-06-finish-governance-followups/specs/project-memory/spec.md delete mode 100644 openspec/changes/archive/2026-08-06-finish-governance-followups/specs/release-workflow/spec.md delete mode 100644 openspec/changes/archive/2026-08-06-finish-governance-followups/tasks.md delete mode 100644 openspec/changes/archive/2026-08-06-fix-install-sh-state-corruption/.openspec.yaml delete mode 100644 openspec/changes/archive/2026-08-06-fix-install-sh-state-corruption/design.md delete mode 100644 openspec/changes/archive/2026-08-06-fix-install-sh-state-corruption/proposal.md delete mode 100644 openspec/changes/archive/2026-08-06-fix-install-sh-state-corruption/specs/quantex-state/spec.md delete mode 100644 openspec/changes/archive/2026-08-06-fix-install-sh-state-corruption/tasks.md delete mode 100644 openspec/changes/archive/2026-08-06-fix-uninstall-path-residual-state-corruption/.openspec.yaml delete mode 100644 openspec/changes/archive/2026-08-06-fix-uninstall-path-residual-state-corruption/design.md delete mode 100644 openspec/changes/archive/2026-08-06-fix-uninstall-path-residual-state-corruption/proposal.md delete mode 100644 openspec/changes/archive/2026-08-06-fix-uninstall-path-residual-state-corruption/specs/agent-uninstall/spec.md delete mode 100644 openspec/changes/archive/2026-08-06-fix-uninstall-path-residual-state-corruption/tasks.md delete mode 100644 openspec/changes/archive/2026-08-06-remove-author-governance/.openspec.yaml delete mode 100644 openspec/changes/archive/2026-08-06-remove-author-governance/proposal.md delete mode 100644 openspec/changes/archive/2026-08-06-remove-author-governance/specs/code-quality-tooling/spec.md delete mode 100644 openspec/changes/archive/2026-08-06-remove-author-governance/specs/release-workflow/spec.md delete mode 100644 openspec/changes/archive/2026-08-06-remove-author-governance/tasks.md delete mode 100644 openspec/changes/archive/2026-08-06-retire-prerelease-channel/.openspec.yaml delete mode 100644 openspec/changes/archive/2026-08-06-retire-prerelease-channel/proposal.md delete mode 100644 openspec/changes/archive/2026-08-06-retire-prerelease-channel/specs/release-workflow/spec.md delete mode 100644 openspec/changes/archive/2026-08-06-retire-prerelease-channel/tasks.md delete mode 100644 openspec/changes/archive/2026-08-06-sync-docs-with-current-contract/.openspec.yaml delete mode 100644 openspec/changes/archive/2026-08-06-sync-docs-with-current-contract/design.md delete mode 100644 openspec/changes/archive/2026-08-06-sync-docs-with-current-contract/proposal.md delete mode 100644 openspec/changes/archive/2026-08-06-sync-docs-with-current-contract/specs/code-quality-tooling/spec.md delete mode 100644 openspec/changes/archive/2026-08-06-sync-docs-with-current-contract/specs/product-readme/spec.md delete mode 100644 openspec/changes/archive/2026-08-06-sync-docs-with-current-contract/specs/project-memory/spec.md delete mode 100644 openspec/changes/archive/2026-08-06-sync-docs-with-current-contract/specs/release-workflow/spec.md delete mode 100644 openspec/changes/archive/2026-08-06-sync-docs-with-current-contract/tasks.md delete mode 100644 openspec/changes/archive/2026-08-07-fix-stderr-version-probe/.openspec.yaml delete mode 100644 openspec/changes/archive/2026-08-07-fix-stderr-version-probe/design.md delete mode 100644 openspec/changes/archive/2026-08-07-fix-stderr-version-probe/proposal.md delete mode 100644 openspec/changes/archive/2026-08-07-fix-stderr-version-probe/specs/agent-version-probing/spec.md delete mode 100644 openspec/changes/archive/2026-08-07-fix-stderr-version-probe/tasks.md delete mode 100644 openspec/changes/archive/2026-08-14-verify-install-scripts-release/.openspec.yaml delete mode 100644 openspec/changes/archive/2026-08-14-verify-install-scripts-release/design.md delete mode 100644 openspec/changes/archive/2026-08-14-verify-install-scripts-release/proposal.md delete mode 100644 openspec/changes/archive/2026-08-14-verify-install-scripts-release/specs/release-workflow/spec.md delete mode 100644 openspec/changes/archive/2026-08-14-verify-install-scripts-release/tasks.md delete mode 100644 openspec/changes/archive/2026-08-15-remove-macos-desktop-client/.openspec.yaml delete mode 100644 openspec/changes/archive/2026-08-15-remove-macos-desktop-client/design.md delete mode 100644 openspec/changes/archive/2026-08-15-remove-macos-desktop-client/proposal.md delete mode 100644 openspec/changes/archive/2026-08-15-remove-macos-desktop-client/specs/agent-update/spec.md delete mode 100644 openspec/changes/archive/2026-08-15-remove-macos-desktop-client/specs/cli-contract-registry/spec.md delete mode 100644 openspec/changes/archive/2026-08-15-remove-macos-desktop-client/specs/macos-desktop-client/spec.md delete mode 100644 openspec/changes/archive/2026-08-15-remove-macos-desktop-client/specs/package-distribution/spec.md delete mode 100644 openspec/changes/archive/2026-08-15-remove-macos-desktop-client/tasks.md delete mode 100644 openspec/changes/archive/2026-08-16-validate-lifecycle-receipt-contract/.openspec.yaml delete mode 100644 openspec/changes/archive/2026-08-16-validate-lifecycle-receipt-contract/design.md delete mode 100644 openspec/changes/archive/2026-08-16-validate-lifecycle-receipt-contract/proposal.md delete mode 100644 openspec/changes/archive/2026-08-16-validate-lifecycle-receipt-contract/specs/agent-canary-validation/spec.md delete mode 100644 openspec/changes/archive/2026-08-16-validate-lifecycle-receipt-contract/tasks.md diff --git a/openspec/changes/archive/2026-08-05-redesign-project-workflow/.openspec.yaml b/openspec/changes/archive/2026-08-05-redesign-project-workflow/.openspec.yaml deleted file mode 100644 index 1b062d3a..00000000 --- a/openspec/changes/archive/2026-08-05-redesign-project-workflow/.openspec.yaml +++ /dev/null @@ -1,2 +0,0 @@ -schema: spec-driven -created: 2026-08-04 diff --git a/openspec/changes/archive/2026-08-05-redesign-project-workflow/design.md b/openspec/changes/archive/2026-08-05-redesign-project-workflow/design.md deleted file mode 100644 index 85ec78d0..00000000 --- a/openspec/changes/archive/2026-08-05-redesign-project-workflow/design.md +++ /dev/null @@ -1,87 +0,0 @@ -# Design: redesign-project-workflow - -## Approach - -The redesign applies four principles everywhere: one rule lives in one home, every required gate really runs and can fail, the release path is exercisable without cutting a real release, and every script earns its file. Existing strong pieces (immutable release-candidate hand-off, path taxonomy, PR body policy, OpenSpec as contract source of truth, the runtime skill as process home) are kept; duplication and drift around them are removed. - -## Script consolidation - -Seven merge groups collapse `scripts/` from 35 files to 28: - -| Surviving file | Absorbs | Shape | -|---|---|---| -| `pm-lifecycle-smoke.ts` | `cargo-`, `deno-`, `uv-lifecycle-smoke.ts` | Per-manager config table (install type, package name, args); selected by argv | -| `release-artifacts.ts` | `compress-release-binaries.ts`, `write-release-checksums.ts`, `generate-release-manifest.ts`, `verify-release-artifacts.ts` | One sequential pipeline, previously only ever chained | -| `commit-policy.ts` | `commit-trailer-policy.ts`, `pr-merge-commit-policy.ts` | `--mode push\|pr`; shared trailer pattern and commit-JSON parsing live once | -| `test-isolation.ts` | `test-container.ts`, `test-sandbox.ts` | `--backend docker\|modal`; shared runner, backend-specific availability checks | -| `verify-package-distribution.ts` | `verify-v1-downstream.ts` | Folded as a final verification step of its only consumer | -| `release-pr-policy.ts` | `release-pr-policy.js` + hand-written `.d.ts` | TypeScript like every other policy script | -| `write-agent-catalog-manifest.ts` | `write-agent-catalog-schema.ts` | Schema write becomes one generation step | - -`scripts/path-taxonomy.ts` `sandboxRelevantFiles` and all test/package.json/workflow references are updated to the surviving names in the same change. - -Three scripts are added, each replacing untestable or duplicated logic: - -- `ci-context.ts` — lists changed files (PR `listFiles` / push `compare`) and commits (PR commits / push compare) via `gh api`, emitting both as step outputs. Imports only Node builtins so the `classify` job needs no `bun install`. Replaces three copy-pasted `github-script` blocks in `ci.yml`/`sandbox-tests.yml`. -- `release-candidate.ts` — the entire build-candidate chain (seal contract → build → build:bin → artifacts → smoke → package checks → stage → verify) as one script with two modes: default CI-strict, and `--local` for `bun run release:dry-run` (skips GitHub-identity validations, allows a dirty tree). `release.yml`'s build-candidate job becomes checkout + setup + this script + upload, so CI and local run the same definition. This closes the audit's root cause: the release path was previously only exercisable by cutting a real release. -- `verify-release-candidate.ts` — absorbs `release.yml`'s inline Node heredocs as subcommands: `download-check` (hash/size of the downloaded candidate), `npm-state` (registry publication state), `assets-check` (GitHub Release assets match candidate), `registry-closure` (poll until registry integrity converges). YAML keeps only native `gh`/`npm` one-liners. - -## CI gates - -`ci.yml`: - -- `classify` runs `ci-context.ts` then `path-taxonomy.ts` once, exporting `changed_files`, `commits_json`, `scope`, `run_test_matrix`, `sandbox_relevant`. -- `lint` consumes `needs.classify.outputs` (no API re-listing): commit policy (mode by event), memory check, OpenSpec validate, lint, format check, typecheck. -- `governance` (PR only) consumes the same outputs: release-PR policy (release-please branches), PR body policy, commit policy `--mode pr`. -- `test (windows-latest)` drops `github.event_name != 'pull_request'`; all three platform jobs gate PRs when the change is product-impacting. - -Required checks (target ruleset, documented for the maintainer): `lint`, `governance`, `test (ubuntu-latest)`, `test (macos-latest)`, `test (windows-latest)`. `sandbox-tests` becomes explicitly advisory: fork PRs skip it for lack of secrets and a skipped required check silently passes, so it never actually gated — the label now matches reality. `sandbox-tests.yml` keeps its triggers and fail-safe classification, sharing `ci-context.ts`. - -## Release train - -release-please stays (`skip-github-release: true`): it opens Release PRs; it never tags. - -Tagging becomes a designed step, not a backstop: the `tag-release` job (renamed from `tag-release-backstop`, script `scripts/tag-release.ts`, package script `ci:tag-release`) runs after release-please on protected-branch push. When branch head is a release commit, manifest version has no tag, and the push CI run succeeded, it creates and pushes the tag **with `git push` under the GitHub App token**, which reliably fires `release.yml`'s `on: push: tags` trigger, then relabels the Release PR. The redundant `workflow_dispatch` fan-out is removed — exactly one trigger path, no double-fire. The dead `if: github.event_name == 'push'` guard is removed. - -`release-pr-policy` gains a major-bump guard: a Release PR whose target version is a major bump is rejected unless the PR body carries an explicit `Release-As: ` override block, closing the accidental-v2.0.0 path. - -`release.yml` keeps its two-job shape (build-candidate → publish) and immutable-candidate contract; step bodies move into the scripts above. `release-core.yml` stays manual and separate; the releasing runbook documents that a Core release must precede any CLI release that depends on a new Core version. - -## Documentation single-homing - -- Runtime skill (`skills/quantex-agent-runtime/SKILL.md`) remains the sole full process text. `AGENTS.md` keeps mission, red lines, validation triggers, and pointers; duplicated gate prose becomes one-line pointers. -- `docs/github-collaboration.md` shrinks to GitHub-surface topics (templates, labels, discussion funnel, required-checks table); closure labels, PR-body preflight, worktree rules, and release prose are removed in favor of pointers. -- `docs/runbooks/quantex-task-start.md` is deleted (verbatim duplicate of the skill's Task Start Entry); referencers point at the skill. -- `skills/quantex-cli/references/automation-playbook.md` merges its unique content into `output-contracts.md` and is deleted. -- `docs/sessions/2026-04-28-oxlint-oxfmt-migration.md` is deleted (raw transcript; violates the sessions no-transcripts policy; orphaned). -- The three runtime bootstrap stubs (`.agents/`, `.codex/`, `.github/skills/`) are generated from one canonical template `skills/quantex-agent-runtime/bootstrap-stub.md`; `memory:check` asserts byte parity so they cannot drift again. - -## OpenSpec consolidation - -- `release-workflow` absorbs `release-governance`, `release-note-input`, and `core-npm-release`: one release contract covering the train, Release PR governance, note input format, and Core publication. -- `code-quality-tooling` absorbs `ci-platform-coverage`: one contributor contract covering local validation, hooks, CI matrix, honest skip semantics, and required checks. -- `core-installation-soak` is reframed as `installation-routing`: the 1.5 soak time-box and freeze language are stale at 1.8.x, but the routing contract (`QUANTEX_INSTALLATION_ENGINE=legacy` whole-invocation override, dry-run compatibility route, no mid-invocation engine switching) is still live behavior in `src/commands/installation-routing.ts` and is preserved without the time-box. -- `project-memory` is de-duplicated (the root-markdown allowlist requirement appears twice today) and remains the durable policy contract; operational prose stays in the runtime skill. -- `openspec/config.yaml` context stops restating gate prose and points to the runtime skill. - -Spec merges are applied in place under `openspec/specs/` as tasks of this change; the change's spec deltas record requirement movement for review, and archive closure later uses the skip-specs path. The completed `fix-release-tag-automation` change is archived as part of this cleanup. - -## Local validation chain - -- `bun run setup` runs `simple-git-hooks` explicitly; contributing docs tell developers to run it once after `bun install`. This fixes the silent drift where `bunfig.toml` `ignoreScripts=true` disables `prepare`, leaving stale hooks that never ran the current validation set. -- `pre-commit` becomes `bunx lint-staged` only (no per-commit `bun install --frozen-lockfile`, no `npx` in a Bun-first repo). -- `pre-push` keeps mirroring CI (lint, format:check, typecheck, openspec:validate, memory:check). -- Dead `test:readonly-smoke` entry is removed; its vitest files already run under the default `test` glob. - -## Testing - -- Renamed/merged scripts keep their existing vitest coverage, updated to new entry points: lifecycle smoke (parameterized), commit policy (both modes), path taxonomy (new sandbox-relevant names), PR governance, release-PR policy (plus new major-bump guard cases). -- New tests: `ci-context.test.ts` (event-shape parsing and output writing, gh api mocked), `release-candidate.test.ts` (mode gating, step ordering, local vs CI strictness), `verify-release-candidate.test.ts` (hash checks, npm-state parsing, closure polling), stub-parity coverage inside the memory-check test. -- `openspec:validate` and `memory:check` must pass with the merged specs and deleted docs. - -## Risks - -- **Ruleset drift**: required checks live in GitHub settings, not the repo. Mitigation: ADR 0009 + releasing runbook carry the exact target list, and the PR body calls out the one-time maintainer action. -- **Job renames breaking required checks**: job display names (`lint`, `governance`, `test (...)`) are unchanged; only the backstop job is renamed, and it was never a required check. -- **Release behavior change**: the first release after merge is the live exercise of the new tag path. Mitigation: `release:dry-run` covers the artifact chain locally; the tag path itself is unit-tested; the release runbook keeps the manual tag fallback. -- **Spec merge churn**: four capability names disappear; inbound references (AGENTS.md, docs, tests) are updated in the same change and guarded by `openspec:validate` + `memory:check`. diff --git a/openspec/changes/archive/2026-08-05-redesign-project-workflow/proposal.md b/openspec/changes/archive/2026-08-05-redesign-project-workflow/proposal.md deleted file mode 100644 index c2827ca4..00000000 --- a/openspec/changes/archive/2026-08-05-redesign-project-workflow/proposal.md +++ /dev/null @@ -1,76 +0,0 @@ -# Proposal: redesign-project-workflow - -## Why - -A full-repo audit (35 scripts, 5 workflows, 49 process docs, 21 specs, 120 commits of history) shows the project workflow has outgrown its design: the same rules are restated in up to five homes, near-duplicate scripts multiply, required CI gates do not match what actually runs on PRs, and the release train has been in a continuous fix-on-fix loop for 3.5 months (three mechanism redesigns, a same-day revert-and-republish, an accidental v2.0.0 major). Roughly half of the last 120 commits on main are process overhead rather than product work. - -The root causes are structural, so this change redesigns the workflow around four principles: **one rule lives in one home**, **every required gate really runs and can fail**, **the release path is exercisable without cutting a real release**, and **every script earns its file**. - -## What Changes - -- **Consolidate `scripts/` from 35 files to 28** (7 merge groups, 3 new testable scripts): - - Merge `cargo/deno/uv-lifecycle-smoke.ts` into one parameterized `pm-lifecycle-smoke.ts`. - - Merge the 4-step `release:artifacts` chain into one `release-artifacts.ts`. - - Merge `commit-trailer-policy.ts` + `pr-merge-commit-policy.ts` into `commit-policy.ts --mode push|pr`. - - Merge `test-container.ts` + `test-sandbox.ts` into `test-isolation.ts --backend docker|modal`. - - Fold `verify-v1-downstream.ts` into its only consumer `verify-package-distribution.ts`. - - Convert `release-pr-policy.js` + hand-written `.d.ts` to a single TypeScript file. - - Fold the 6-line `write-agent-catalog-schema.ts` into `write-agent-catalog-manifest.ts`. - - Add `ci-context.ts`: one script that lists changed files and PR/push commits via `gh api`, replacing three copy-pasted `github-script` YAML blocks. - - Add `release-candidate.ts`: the whole build-candidate chain as one locally runnable script (CI strict mode / `--local` dry-run mode), so the release path is testable without a real release. Exposed as `bun run release:dry-run`. - - Add `verify-release-candidate.ts`: absorbs `release.yml`'s inline Node heredocs (candidate hash check, npm state resolution, registry closure polling, asset verification) into a testable script. -- **Make CI gates honest** (`ci.yml`, `sandbox-tests.yml`): - - `classify` computes files+commits once via `ci-context.ts`; `lint` and `governance` consume its outputs instead of re-calling the GitHub API (removes ~120 lines of duplicated YAML JS). - - `test (windows-latest)` now runs on PRs when the change is product-impacting (today it never runs on PRs while being a nominally required check). - - Required checks become `lint`, `governance`, and the three platform test contexts; `sandbox-tests` becomes explicitly advisory (fork PRs silently pass it today while getting zero coverage). **BREAKING (process)**: branch rulesets must be updated to add `governance` and drop `sandbox-tests`. -- **Make the release train deterministic** (`release-please.yml`, `release.yml`): - - Rename the `tag-release-backstop` job/script to `tag-release` (`ci:tag-release`): tagging after a manually merged Release PR is the designed mechanism, not a backstop. Remove the dead `if: github.event_name == 'push'` guard. - - Guarantee exactly one `release.yml` trigger: the tag is pushed with `git push` under the GitHub App token (which fires `on: push: tags`), and the redundant `workflow_dispatch` fan-out is removed, eliminating the double-fire. - - `release.yml` build-candidate collapses to `bun run release:candidate`; publish-side inline Node heredocs move to `verify-release-candidate.ts` subcommands. - - `release-pr-policy` rejects unannounced major version bumps (root cause of the accidental v2.0.0). -- **Give every rule one home** (docs): - - Delete `docs/sessions/2026-04-28-oxlint-oxfmt-migration.md` (raw transcript, orphaned, violates the sessions no-transcripts policy). - - Delete `docs/runbooks/quantex-task-start.md`; its content is the runtime skill's Task Start Entry (single home). - - Shrink `docs/github-collaboration.md` to GitHub-surface topics only (templates, labels, discussion funnel, rulesets); process rules point to `skills/quantex-agent-runtime/SKILL.md`. - - Merge `skills/quantex-cli/references/automation-playbook.md` into `output-contracts.md`. - - Trim `AGENTS.md` gate text to pointers (runtime skill stays the process source of truth). - - Single-source the three agent-runtime bootstrap stubs (`.agents/`, `.codex/`, `.github/`) from one template and enforce byte-parity in `memory:check` (today `.github`'s stub has already drifted). -- **Consolidate OpenSpec specs from 21 to 17**: - - Merge `release-governance`, `release-note-input`, `core-npm-release` into `release-workflow`. - - Merge `ci-platform-coverage` into `code-quality-tooling`. - - Reframe `core-installation-soak` as `installation-routing`: the soak time-box language is stale at 1.8.x, but the routing contract it carries (`QUANTEX_INSTALLATION_ENGINE=legacy` override, dry-run compatibility route) is still live behavior and is preserved without the freeze framing. - - De-duplicate `project-memory` (the root-markdown allowlist requirement is stated twice) and keep it as durable policy; operational prose lives in the runtime skill. - - Slim `openspec/config.yaml` context so gate text lives only in the runtime skill. -- **Fix the local validation chain**: - - Add `bun run setup` (explicit `simple-git-hooks` install) because `bunfig.toml` `ignoreScripts=true` silently disables `prepare` — today the installed hooks are stale and never run the current validation set. - - `pre-commit` drops the per-commit `bun install --frozen-lockfile` and uses `bunx lint-staged` instead of `npx`. - - Remove the dead `test:readonly-smoke` package script (its vitest files run under the default `test` glob). -- **Archive the completed change** `fix-release-tag-automation` (merged, released in 1.8.2, spec deltas already synced) as part of this cleanup. -- Add ADR 0009 recording this redesign and the required-checks change. - -## Capabilities - -- **New Capabilities**: none. -- **Modified Capabilities**: - - `release-workflow` — absorbs the three sibling release specs; tag-release mechanism, release-candidate pipeline, dry-run, major-bump guard. - - `release-governance` — requirements move into `release-workflow`; capability removed. - - `release-note-input` — requirements move into `release-workflow`; capability removed. - - `core-npm-release` — requirements move into `release-workflow`; capability removed. - - `code-quality-tooling` — absorbs `ci-platform-coverage`; hooks/setup contract updated. - - `ci-platform-coverage` — requirements move into `code-quality-tooling`; capability removed. - - `project-memory` — de-duplicated; stays the durable policy contract. - - `core-installation-soak` — removed; routing contract moves to the new `installation-routing` capability. - - `installation-routing` (new) — soak-free restatement of the live Core/legacy routing contract. - -## Impact - -- `scripts/` (13 files removed/merged, 3 added), `package.json` scripts + hooks, `bunfig.toml` (unchanged; hooks documented), `.github/workflows/{ci,release,release-please,sandbox-tests}.yml` -- `openspec/specs/` (5 capabilities removed/merged, 2 rewritten), `openspec/config.yaml`, `openspec/changes/fix-release-tag-automation/` (archived) -- `AGENTS.md`, `docs/README.md`, `docs/github-collaboration.md`, `docs/releases.md`, `docs/runbooks/*`, `docs/adr/0009-*` (new), `docs/sessions/` (1 deletion), `skills/quantex-cli/references/` -- `.agents/`, `.codex/`, `.github/skills/` bootstrap stubs + `scripts/check-project-memory.ts` parity check -- Tests referencing merged scripts or spec names: `test/{lifecycle-smoke,path-taxonomy,pr-governance,commit-trailer-policy,pr-merge-commit-policy,release-pr-policy,pr-body-policy}.test.ts` and new tests for `ci-context`, `release-candidate`, `verify-release-candidate` -- Out of scope (non-goals): product CLI behavior, agent catalog content, the `packages/core` SDK surface, README product tables, branch ruleset settings themselves (documented for the maintainer to apply). - -## Intake classification - -Durable-process and workflow redesign (project memory policy, durable workflow, OpenSpec rules, GitHub collaboration flow); OpenSpec required. diff --git a/openspec/changes/archive/2026-08-05-redesign-project-workflow/specs/ci-platform-coverage/spec.md b/openspec/changes/archive/2026-08-05-redesign-project-workflow/specs/ci-platform-coverage/spec.md deleted file mode 100644 index 469f5ce6..00000000 --- a/openspec/changes/archive/2026-08-05-redesign-project-workflow/specs/ci-platform-coverage/spec.md +++ /dev/null @@ -1,27 +0,0 @@ -# ci-platform-coverage Delta - -## REMOVED Requirements - -### Requirement: CI SHALL use honest skip semantics for conditional jobs - -**Reason**: Merged into `code-quality-tooling`; the Windows pull-request exclusion no longer exists because Windows now runs on product-impacting PRs. - -**Migration**: Follow the same-named requirement in `openspec/specs/code-quality-tooling/spec.md`. - -### Requirement: CI SHALL run on consolidated workflow entry points - -**Reason**: Merged into `code-quality-tooling`. - -**Migration**: Follow the same-named requirement in `openspec/specs/code-quality-tooling/spec.md`. - -### Requirement: Windows pull requests SHALL skip the full test job - -**Reason**: Reversed by design: Windows coverage now gates product-impacting pull requests instead of skipping them, so the nominally required Windows check is real. - -**Migration**: Follow `Windows coverage SHALL gate product-impacting pull requests` in `openspec/specs/code-quality-tooling/spec.md`. - -### Requirement: Windows full tests run after integration - -**Reason**: Superseded by Windows coverage on both pull requests and protected-branch pushes. - -**Migration**: Follow `Windows coverage SHALL gate product-impacting pull requests` in `openspec/specs/code-quality-tooling/spec.md`. diff --git a/openspec/changes/archive/2026-08-05-redesign-project-workflow/specs/code-quality-tooling/spec.md b/openspec/changes/archive/2026-08-05-redesign-project-workflow/specs/code-quality-tooling/spec.md deleted file mode 100644 index c01bb2f6..00000000 --- a/openspec/changes/archive/2026-08-05-redesign-project-workflow/specs/code-quality-tooling/spec.md +++ /dev/null @@ -1,92 +0,0 @@ -# code-quality-tooling Delta - -## ADDED Requirements - -### Requirement: Hook installation SHALL be explicit and refreshable - -Because `bunfig.toml` sets `ignoreScripts=true` for supply-chain safety, the `prepare` lifecycle script does not install git hooks automatically. The repository SHALL expose `bun run setup` to (re)install `simple-git-hooks`, and contributor-facing documentation SHALL direct developers to run it once after `bun install` and whenever hook definitions change. - -#### Scenario: Fresh clone installs hooks - -- **WHEN** a contributor clones the repository and runs `bun install` -- **THEN** git hooks are not silently installed by lifecycle scripts -- **AND** running `bun run setup` installs the versioned `simple-git-hooks` definitions from `package.json` - -### Requirement: CI SHALL collect change context once through a shared script - -Merge-gating workflows SHALL collect changed-file and commit metadata through the shared `ci:context` script instead of inline `github-script` blocks, and downstream jobs SHALL consume the classification outputs rather than re-calling the GitHub API. - -#### Scenario: pull request context is computed once - -- **WHEN** a pull request targets `main` or `beta` -- **THEN** the `classify` job computes changed files, commits, and pull request trust exactly once -- **AND** lint, governance, and test jobs consume those outputs through job dependencies -- **AND** no workflow duplicates the file- or commit-listing logic inline in YAML - -### Requirement: CI SHALL run on consolidated workflow entry points - -Lint, governance, and test jobs SHALL be defined in a consolidated `ci.yml` workflow. PR body validation SHALL run within `ci.yml` rather than a separate `pr-governance.yml` workflow. - -#### Scenario: single CI workflow for merge gates - -- **WHEN** a PR targets `main` or `beta` -- **THEN** `ci.yml` MUST provide lint, test matrix, and PR governance validation jobs -- **AND** `pr-governance.yml` MUST NOT exist as a separate workflow - -### Requirement: CI SHALL use honest skip semantics for conditional jobs - -CI workflows SHALL use job-level `if` conditions that produce `skipped` status instead of empty-success jobs when tests are not applicable (process-only changes, fork PR sandbox exclusions). - -#### Scenario: process-only change skips full test matrix - -- **WHEN** a PR changes only process/documentation paths classified as non-product-impacting -- **THEN** platform test jobs that are not applicable MUST report `skipped` rather than succeed without running tests - -#### Scenario: fork PR skips sandbox tests - -- **WHEN** a sandbox-related PR originates from a fork -- **THEN** the sandbox-tests job MUST report `skipped` rather than succeed without running Modal tests - -### Requirement: Windows coverage SHALL gate product-impacting pull requests - -For pull requests with product-matrix scope, CI SHALL run the full Windows Vitest command in the `test (windows-latest)` job, using the established thread-pool invocation. Windows coverage MUST NOT be limited to post-merge runs. - -#### Scenario: Product-impacting pull request runs Windows tests - -- **WHEN** a pull request changes files that require the product test matrix -- **THEN** the `test (windows-latest)` job invokes the established thread-pool full-test command -- **AND** a failure blocks merge through the active ruleset - -#### Scenario: Process-only pull request skips Windows tests - -- **WHEN** a pull request is classified process-only -- **THEN** the `test (windows-latest)` job reports `skipped` -- **AND** merge remains allowed when other required checks pass - -## MODIFIED Requirements - -### Requirement: Pre-commit lint and format enforcement - -The repository SHALL enforce lint and format on staged files before each commit through `simple-git-hooks` and `lint-staged`. The pre-commit hook MUST run `bunx lint-staged` only: dependency installation belongs to explicit environment setup, not to every commit. lint-staged MUST run `oxfmt` only on staged files supported by the formatter in this repository configuration, and MUST run `oxlint --fix` only on staged JavaScript or TypeScript files after formatting, so that the linter sees post-formatter content without being invoked on unsupported file types. When every matched JavaScript or TypeScript path is excluded by oxlint configuration, the lint invocation MUST be a successful no-op; real diagnostics for matched files MUST remain commit-blocking. - -#### Scenario: Contributor commits a staged file - -- **GIVEN** a contributor stages files matched by `lint-staged` globs -- **WHEN** the pre-commit hook runs -- **THEN** the hook invokes `oxfmt` on staged formatter-supported files to write formatting fixes -- **AND** then invokes `oxlint --fix` on staged JavaScript or TypeScript files -- **AND** if either step finds a real failure, the commit is aborted - -#### Scenario: All staged TypeScript files are ignored by oxlint - -- **GIVEN** every staged JavaScript or TypeScript file is excluded by oxlint configuration -- **WHEN** the pre-commit hook runs -- **THEN** oxlint completes successfully without selecting a file -- **AND** the commit is not blocked solely because no lintable target remains - -#### Scenario: Contributor stages OpenSpec archive metadata - -- **GIVEN** a contributor stages an OpenSpec archive file such as `.openspec.yaml` -- **WHEN** the pre-commit hook runs -- **THEN** the hook does not route that file through an unsupported `oxfmt` invocation -- **AND** the commit is not blocked solely because the formatter cannot handle that file type in the current repository configuration diff --git a/openspec/changes/archive/2026-08-05-redesign-project-workflow/specs/core-installation-soak/spec.md b/openspec/changes/archive/2026-08-05-redesign-project-workflow/specs/core-installation-soak/spec.md deleted file mode 100644 index 3c5b36a6..00000000 --- a/openspec/changes/archive/2026-08-05-redesign-project-workflow/specs/core-installation-soak/spec.md +++ /dev/null @@ -1,15 +0,0 @@ -# core-installation-soak Delta - -## REMOVED Requirements - -### Requirement: The second Core-default soak freezes the selected installation boundary - -**Reason**: The 1.5 soak time-box and freeze framing are stale at 1.8.x, but the routing contract itself is still live behavior; it is restated without the time-box in the new `installation-routing` capability. - -**Migration**: Follow `Install and ensure SHALL route whole invocations to one engine` in `openspec/specs/installation-routing/spec.md`. - -### Requirement: The Core-default rollback rehearsal is operator-repeatable - -**Reason**: Moved to the new `installation-routing` capability without changes. - -**Migration**: Follow the same-named requirement in `openspec/specs/installation-routing/spec.md`. diff --git a/openspec/changes/archive/2026-08-05-redesign-project-workflow/specs/core-npm-release/spec.md b/openspec/changes/archive/2026-08-05-redesign-project-workflow/specs/core-npm-release/spec.md deleted file mode 100644 index 603c0b57..00000000 --- a/openspec/changes/archive/2026-08-05-redesign-project-workflow/specs/core-npm-release/spec.md +++ /dev/null @@ -1,15 +0,0 @@ -# core-npm-release Delta - -## REMOVED Requirements - -### Requirement: Core publication is independent and OIDC-backed - -**Reason**: Merged into `release-workflow` so the release contract has one home. - -**Migration**: Follow the same-named requirement in `openspec/specs/release-workflow/spec.md`. - -### Requirement: Core releases use immutable, idempotent recovery sources - -**Reason**: Merged into `release-workflow`. - -**Migration**: Follow the same-named requirement in `openspec/specs/release-workflow/spec.md`. diff --git a/openspec/changes/archive/2026-08-05-redesign-project-workflow/specs/installation-routing/spec.md b/openspec/changes/archive/2026-08-05-redesign-project-workflow/specs/installation-routing/spec.md deleted file mode 100644 index 15252355..00000000 --- a/openspec/changes/archive/2026-08-05-redesign-project-workflow/specs/installation-routing/spec.md +++ /dev/null @@ -1,39 +0,0 @@ -# installation-routing Delta - -## ADDED Requirements - -### Requirement: Install and ensure SHALL route whole invocations to one engine - -Quantex SHALL keep Core as the pre-invocation default for non-dry-run `install` and `ensure`. The legacy engine SHALL remain available as a whole-invocation compatibility route only for v1 dry-run planning and an exact `QUANTEX_INSTALLATION_ENGINE=legacy` override. Quantex MUST NOT select Core for `update`, `uninstall`, or `run`, and MUST NOT fall back between engines after an invocation begins. - -#### Scenario: operator selects the legacy rollback route - -- **WHEN** an operator starts `install` or `ensure` with - `QUANTEX_INSTALLATION_ENGINE=legacy` -- **THEN** that new invocation uses the legacy engine from start to finish -- **AND THEN** a value other than the exact `legacy` override does not create a - new routing mode - -#### Scenario: dry-run has compatibility precedence - -- **WHEN** an operator invokes `install` or `ensure` with `--dry-run`, with or - without the compatibility override -- **THEN** the invocation uses the retained legacy planning route -- **AND THEN** it does not start a Core lifecycle mutation - -### Requirement: The Core-default rollback rehearsal is operator-repeatable - -Quantex SHALL document a rollback rehearsal that proves the existing -whole-invocation legacy route, records observable command and state evidence, -and returns to the Core default in a later invocation. The procedure MUST NOT -recommend switching engines after a provider, filesystem, or state side effect -has started. - -#### Scenario: operator follows the rollback rehearsal - -- **WHEN** an operator follows the documented procedure for one promoted - command -- **THEN** it can verify the legacy invocation and the subsequent Core-default - invocation independently -- **AND THEN** the procedure preserves state schema version 2 and does not - require an automatic rollback diff --git a/openspec/changes/archive/2026-08-05-redesign-project-workflow/specs/project-memory/spec.md b/openspec/changes/archive/2026-08-05-redesign-project-workflow/specs/project-memory/spec.md deleted file mode 100644 index c9d97b4d..00000000 --- a/openspec/changes/archive/2026-08-05-redesign-project-workflow/specs/project-memory/spec.md +++ /dev/null @@ -1,9 +0,0 @@ -# project-memory Delta - -## REMOVED Requirements - -### Requirement: Root markdown allowlist SHALL track canonical README entry points (duplicate) - -**Reason**: This requirement was stated twice in the same specification; the first occurrence remains the contract. - -**Migration**: Follow the first `Root markdown allowlist SHALL track canonical README entry points` requirement in `openspec/specs/project-memory/spec.md`. diff --git a/openspec/changes/archive/2026-08-05-redesign-project-workflow/specs/release-governance/spec.md b/openspec/changes/archive/2026-08-05-redesign-project-workflow/specs/release-governance/spec.md deleted file mode 100644 index 031ffbdc..00000000 --- a/openspec/changes/archive/2026-08-05-redesign-project-workflow/specs/release-governance/spec.md +++ /dev/null @@ -1,69 +0,0 @@ -# release-governance Delta - -## REMOVED Requirements - -### Requirement: PRs Must Declare Release Intent - -**Reason**: Merged into `release-workflow` so the release contract has one home. - -**Migration**: Follow the same-named requirement in `openspec/specs/release-workflow/spec.md`. - -### Requirement: Process-only PRs MUST use the shared scope taxonomy for release-metadata enforcement - -**Reason**: Merged into `release-workflow`. - -**Migration**: Follow the same-named requirement in `openspec/specs/release-workflow/spec.md`. - -### Requirement: PR body governance MUST be locally executable - -**Reason**: Merged into `release-workflow`. - -**Migration**: Follow the same-named requirement in `openspec/specs/release-workflow/spec.md`. - -### Requirement: Product-Impacting PRs Must Not Silently Skip Release - -**Reason**: Merged into `release-workflow`. - -**Migration**: Follow the same-named requirement in `openspec/specs/release-workflow/spec.md`. - -### Requirement: Release PRs Keep Dedicated Validation - -**Reason**: Merged into `release-workflow`. - -**Migration**: Follow the same-named requirement in `openspec/specs/release-workflow/spec.md`. - -### Requirement: Protected-branch CI MUST reject prohibited co-author trailers in new commits - -**Reason**: Merged into `release-workflow`; commit trailer and merge commit policies now live in one `commit-policy.ts` script with push/pr modes. - -**Migration**: Follow the same-named requirement in `openspec/specs/release-workflow/spec.md`. - -### Requirement: PR body governance MUST be run before PR delivery actions - -**Reason**: Merged into `release-workflow`. - -**Migration**: Follow the same-named requirement in `openspec/specs/release-workflow/spec.md`. - -### Requirement: Pull request delivery MUST prefer linear history - -**Reason**: Merged into `release-workflow`. - -**Migration**: Follow the same-named requirement in `openspec/specs/release-workflow/spec.md`. - -### Requirement: PR governance MUST validate release-summary input - -**Reason**: Merged into `release-workflow` as `Release-source PRs MUST provide release-please consumable summaries`. - -**Migration**: Follow `Release-source PRs MUST provide release-please consumable summaries` in `openspec/specs/release-workflow/spec.md`. - -### Requirement: Protected branches SHALL require aligned status check contexts - -**Reason**: Merged into `release-workflow` and updated to the honest required-check set (`lint`, `governance`, three platform tests; `sandbox-tests` advisory). - -**Migration**: Follow the same-named requirement in `openspec/specs/release-workflow/spec.md` and update branch rulesets to match. - -### Requirement: Skipped required checks SHALL not block merge - -**Reason**: Merged into `release-workflow`; the Windows-on-PR skip example no longer exists because Windows now runs on product-impacting PRs. - -**Migration**: Follow the same-named requirement in `openspec/specs/release-workflow/spec.md`. diff --git a/openspec/changes/archive/2026-08-05-redesign-project-workflow/specs/release-note-input/spec.md b/openspec/changes/archive/2026-08-05-redesign-project-workflow/specs/release-note-input/spec.md deleted file mode 100644 index 4199550f..00000000 --- a/openspec/changes/archive/2026-08-05-redesign-project-workflow/specs/release-note-input/spec.md +++ /dev/null @@ -1,15 +0,0 @@ -# release-note-input Delta - -## REMOVED Requirements - -### Requirement: Release-source PRs MUST provide release-please consumable summaries - -**Reason**: Merged into `release-workflow` so the release contract has one home. - -**Migration**: Follow the same-named requirement in `openspec/specs/release-workflow/spec.md`. - -### Requirement: Release-As source metadata MUST be explicit - -**Reason**: Merged into `release-workflow`. - -**Migration**: Follow the same-named requirement in `openspec/specs/release-workflow/spec.md`. diff --git a/openspec/changes/archive/2026-08-05-redesign-project-workflow/specs/release-workflow/spec.md b/openspec/changes/archive/2026-08-05-redesign-project-workflow/specs/release-workflow/spec.md deleted file mode 100644 index 03516115..00000000 --- a/openspec/changes/archive/2026-08-05-redesign-project-workflow/specs/release-workflow/spec.md +++ /dev/null @@ -1,233 +0,0 @@ -# release-workflow Delta - -## ADDED Requirements - -### Requirement: PRs Must Declare Release Intent - -Every pull request SHALL include a dedicated release-intent section in its body. - -#### Scenario: PR body is validated - -- **WHEN** PR Governance validates a pull request body -- **THEN** it requires a `## Release Intent` section alongside the standard summary, artifacts, validation, docs, scope, and closure sections. - -### Requirement: Release-source PRs MUST provide release-please consumable summaries - -Every non-generated pull request with release-worthy metadata SHALL include a `## Release Summary` section containing a non-empty `BEGIN_COMMIT_OVERRIDE` / `END_COMMIT_OVERRIDE` block with at least one conventional-commit entry suitable for user-facing release notes. - -#### Scenario: Release source omits the summary - -- **WHEN** a non-generated PR uses release-worthy metadata -- **AND** its Release Summary is missing, blank, malformed, or contains only a placeholder override -- **THEN** PR governance MUST reject the PR before merge with guidance to provide a release-please commit override - -### Requirement: Release-As source metadata MUST be explicit - -A source PR that requests a one-shot release through `Release-As` SHALL declare the same non-empty `Release-As: ` footer in its Release Summary and in the merged commit. - -#### Scenario: Neutral release trigger is documented - -- **WHEN** a source PR uses `Release-As` without feature or breaking conventional metadata -- **THEN** PR governance MUST treat the declared footer as release-worthy metadata -- **AND** it MUST require both the release summary override and the visible Release-As declaration - -### Requirement: Process-only PRs MUST use the shared scope taxonomy for release-metadata enforcement - -PR governance SHALL determine whether a pull request is process-only by using the same canonical repository taxonomy as merge-gating CI before enforcing release-metadata restrictions. - -#### Scenario: Process-only PR changes workflow or OpenSpec files - -- **WHEN** a pull request changes only files classified as process-only by the canonical repository taxonomy -- **THEN** PR governance MUST treat the pull request as process-only for release-metadata enforcement -- **AND** it MUST reject release-worthy conventional metadata such as `feat:`, `fix:`, or `perf:` for that scope - -### Requirement: Product-Impacting PRs Must Not Silently Skip Release - -PR Governance SHALL reject product-impacting pull requests whose title is not release-worthy unless the PR explicitly declares that release is not applicable with a non-placeholder reason. - -#### Scenario: Product-impacting PR has non-release title and no reason - -- **WHEN** a pull request changes files classified as product-impacting by the canonical repository taxonomy -- **AND** its title is not release-worthy -- **AND** its release-intent section is missing, empty, or only says a placeholder such as `n/a` -- **THEN** PR Governance fails with guidance to use release-worthy metadata or provide a reason. - -### Requirement: PR body governance MUST be locally executable - -The repository SHALL expose PR body governance as a local script used by both contributors and GitHub Actions. - -#### Scenario: GitHub validates a PR body - -- **WHEN** PR Governance runs for a pull request -- **THEN** it invokes the shared local PR body governance script -- **AND** it does not maintain an independent copy of the required-heading or release-intent logic inline in workflow YAML - -### Requirement: PR body governance MUST be run before PR delivery actions - -Agents and contributors SHALL run the local PR body governance command before creating a pull request or editing a pull request body when they provide a body manually. - -#### Scenario: Agent creates a pull request - -- **GIVEN** an agent has prepared a branch for PR delivery -- **WHEN** the agent writes the pull request body -- **THEN** it MUST write the body to a file based on `.github/pull_request_template.md` -- **AND** it MUST run `bun run pr:body:check -- --body-file --title ""` before `gh pr create --body-file <body-file>` - -### Requirement: Release PRs Keep Dedicated Validation - -Release-please generated Release PRs SHALL remain governed by the dedicated Release PR validator instead of the product-impacting release-intent check. - -#### Scenario: Release-please PR opens - -- **WHEN** a pull request comes from a release-please branch -- **THEN** PR Governance does not require product-impacting release intent for the version-file changes -- **AND** the Release PR validator validates the release branch, title, generated marker, and changed file scope -- **AND** it rejects versions not greater than the base version, direct `0.x` to `1.0.0` promotions, and burned release versions - -### Requirement: Major version bumps SHALL require explicit maintainer declaration - -A Release PR whose proposed stable version crosses to a new major from a non-zero-major base SHALL be rejected unless the Release PR body carries an explicit maintainer-added `Release-As: <proposed version>` declaration. - -#### Scenario: Undeclared major bump is rejected - -- **WHEN** a generated stable Release PR proposes a new major version over a `1.x` or later base -- **AND** its body does not declare `Release-As: <proposed version>` -- **THEN** the Release PR validator MUST fail with guidance that a maintainer must explicitly approve the new major - -#### Scenario: Declared major bump proceeds - -- **WHEN** a generated stable Release PR proposes a new major version over a `1.x` or later base -- **AND** its body declares `Release-As: <proposed version>` -- **THEN** the major-bump check passes - -### Requirement: Protected-branch CI MUST reject prohibited co-author trailers in new commits - -Repository CI SHALL reject newly introduced commits containing `Co-authored-by:` trailers on pull requests and protected-branch pushes, and SHALL reject pull requests whose commit metadata risks synthesized co-author trailers on squash merge. The merge commit policy validator SHALL fail when no commit metadata is supplied. Release-please branches are exempt from the Release-As commit-footer consistency check because generated release commits never carry source-PR footers. - -#### Scenario: Protected-branch push introduces co-author trailer - -- **WHEN** CI evaluates the commits introduced by a direct push to a protected branch -- **AND** any of those commit messages contains a `Co-authored-by:` trailer -- **THEN** CI fails before downstream release automation treats the push as releasable history -- **AND** it reports the offending commit SHA and trailer line - -### Requirement: Pull request delivery MUST prefer linear history - -For ordinary repository pull requests, maintainers and agents MUST select rebase merge first and MAY use squash merge only when rebase is unavailable or unsafe. - -#### Scenario: A ready pull request can be rebased safely - -- **GIVEN** the approved pull request head is unchanged and every required check passes -- **WHEN** the pull request is merged -- **THEN** the operator MUST prefer rebase merge -- **AND** the resulting protected-branch history remains linear - -### Requirement: The release-candidate pipeline SHALL be locally exercisable - -The repository SHALL expose `bun run release:dry-run` so maintainers and agents can exercise the build-candidate chain locally without a tag or publication. CI MUST run the same pipeline definition in strict mode so the local and CI paths cannot diverge. - -#### Scenario: maintainer exercises the release path locally - -- **WHEN** a maintainer runs `bun run release:dry-run` on a checkout with installed dependencies -- **THEN** the pipeline runs build, binary build, artifact generation, smoke verification, Core package checks, candidate staging, and candidate verification -- **AND** it skips GitHub release-identity validation that requires a real tag - -### Requirement: Core publication is independent and OIDC-backed - -The repository SHALL publish `quantex-core` only through a manually dispatched `release-core.yml` workflow with GitHub Actions OIDC, without an npm token, CLI release-please involvement, a GitHub Release, standalone binaries, or CLI publication gating on Core registry state. - -#### Scenario: maintainer dispatches a Core release - -- **WHEN** a maintainer dispatches `Release Core` for `main` -- **THEN** the workflow builds and validates only the Core package contract before publishing -- **AND** npm receives an OIDC-authenticated `quantex-core` publish without a long-lived npm credential - -### Requirement: Core releases use immutable, idempotent recovery sources - -The Core release workflow MUST use `core-v<version>` as its immutable source tag and inspect `quantex-core@<version>` before publishing, reject a tag pointing at another commit, and treat an exact existing npm version as already published. - -#### Scenario: a Core release is retried - -- **WHEN** a maintainer dispatches Core release after an interrupted publish -- **THEN** the workflow reuses the existing matching `core-v<version>` tag -- **AND** it publishes only if the exact package version is conclusively absent - -### Requirement: A Core release SHALL precede dependent CLI releases - -When a CLI release depends on a new `quantex-core` version, the maintainer SHALL publish that Core version through `release-core.yml` before the CLI Release PR merges. - -#### Scenario: CLI release needs a new Core version - -- **WHEN** `package.json` pins a `quantex-core` version that is not yet on npm -- **THEN** the maintainer MUST dispatch the Core release first -- **AND** the CLI release candidate pipeline MUST NOT be expected to succeed before Core is published - -## MODIFIED Requirements - -### Requirement: Tag push SHALL trigger publish without redundant merge gates - -When a `v*` tag is pushed, `release.yml` SHALL validate the immutable release identity, build, verify release artifacts, smoke-test, and publish to npm and GitHub Release without re-running lint, typecheck, or vitest gates already enforced at merge. - -#### Scenario: tag publish runs artifact pipeline only - -- **WHEN** a `v<version>` tag is pushed -- **THEN** `release.yml` MUST run the release-candidate pipeline (seal validation, build, `release:artifacts`, `release:smoke`, package checks, candidate staging, candidate verification) and npm/GitHub publish -- **AND** it MUST NOT require lint, format:check, typecheck, or test jobs to pass again - -### Requirement: Release tagging SHALL seal merged Release PRs deterministically - -Because release-please runs with `skip-github-release: true` and maintainers re-author Release PR branches before merge, a dedicated `tag-release` job SHALL run after release-please on each protected-branch push. When the branch head is a `chore: release <version>` commit, the manifest version has no tag at that commit, and the branch-head push CI run succeeded, the job SHALL create and push `v<version>` with `git push` under the release GitHub App token so the tag event triggers `release.yml` exactly once, then relabel the merged release PR from `autorelease: pending` to `autorelease: tagged`. A workflow dispatch MAY be used only as a fallback after polling shows the tag event did not trigger the Release workflow. - -#### Scenario: manually merged Release PR receives tag after CI - -- **WHEN** a release-please Release PR is merged manually to `main` or `beta` -- **AND** the branch head commit title is `chore: release <version>` -- **AND** push CI succeeded on that commit -- **AND** tag `v<version>` does not exist at the branch head -- **THEN** the tag-release job MUST push tag `v<version>` at the branch head through `git push` -- **AND** it MUST relabel the merged release PR to `autorelease: tagged` - -#### Scenario: tag push is the primary release trigger - -- **WHEN** the tag-release job pushes tag `v<version>` -- **THEN** it MUST NOT unconditionally dispatch `release.yml` -- **AND** it MAY dispatch `release.yml` only when polling shows no Release workflow run was created for the pushed tag - -#### Scenario: tag-release is a no-op when tag already exists - -- **WHEN** tag `v<version>` already points at the branch head release commit -- **THEN** the tag-release job MUST NOT create a duplicate tag -- **AND** it MAY relabel a stale `autorelease: pending` release PR to unblock release-please - -### Requirement: Protected branches SHALL require aligned status check contexts - -`main` and `beta` protected branches SHALL require status check contexts that match the consolidated CI workflow job names and actually run on pull requests: `lint`, `governance`, `test (ubuntu-latest)`, `test (windows-latest)`, and `test (macos-latest)`. The `classify` job SHALL NOT be a required context. The `sandbox-tests` workflow SHALL remain advisory and SHALL NOT be a required context. - -#### Scenario: main branch ruleset contexts - -- **WHEN** a maintainer inspects the `protect-main` ruleset -- **THEN** required status checks MUST include `lint`, `governance`, `test (ubuntu-latest)`, `test (windows-latest)`, and `test (macos-latest)` -- **AND** `classify` and `sandbox-tests` MUST NOT appear as required contexts - -#### Scenario: beta branch has matching protection - -- **WHEN** a maintainer inspects branch protection for `beta` -- **THEN** it MUST require the same five status check contexts as `main` - -### Requirement: Skipped required checks SHALL not block merge - -When a required status check job is legitimately skipped (for example, platform test jobs on process-only changes), GitHub ruleset semantics SHALL treat the skipped check as passing and MUST NOT block merge. - -#### Scenario: skipped platform test on process-only pull request - -- **WHEN** a process-only pull request skips a required platform test job -- **AND** other required checks pass -- **THEN** the pull request MUST remain mergeable - -## REMOVED Requirements - -### Requirement: Release tag backstop SHALL seal manually merged Release PRs - -**Reason**: The "backstop" framing described a fix-on-fix patch; tagging after a manually merged Release PR is the designed mechanism and is restated as `Release tagging SHALL seal merged Release PRs deterministically` with a single-fire trigger guarantee. - -**Migration**: Follow the renamed `tag-release` requirement and the `ci:tag-release` script; the `release-tag-backstop` name is retired. diff --git a/openspec/changes/archive/2026-08-05-redesign-project-workflow/tasks.md b/openspec/changes/archive/2026-08-05-redesign-project-workflow/tasks.md deleted file mode 100644 index e0c1d6e5..00000000 --- a/openspec/changes/archive/2026-08-05-redesign-project-workflow/tasks.md +++ /dev/null @@ -1,61 +0,0 @@ -# Tasks - -## 1. Script consolidation - -- [x] Merge `cargo/deno/uv-lifecycle-smoke.ts` into `scripts/pm-lifecycle-smoke.ts` (config table, argv-selected); update `scripts/lifecycle-smoke.ts`, `scripts/path-taxonomy.ts`, `test/lifecycle-smoke.test.ts`, `test/path-taxonomy.test.ts` -- [x] Merge `compress-release-binaries.ts` + `write-release-checksums.ts` + `generate-release-manifest.ts` + `verify-release-artifacts.ts` into `scripts/release-artifacts.ts`; update `package.json` `release:artifacts` -- [x] Merge `commit-trailer-policy.ts` + `pr-merge-commit-policy.ts` into `scripts/commit-policy.ts --mode push|pr`; update package scripts, `ci.yml`, and both test files -- [x] Merge `test-container.ts` + `test-sandbox.ts` into `scripts/test-isolation.ts --backend docker|modal`; update package scripts, `sandbox-tests.yml`, runbook -- [x] Fold `verify-v1-downstream.ts` into `verify-package-distribution.ts` -- [x] Convert `release-pr-policy.js` + `.d.ts` to `scripts/release-pr-policy.ts`; add major-bump guard (reject unless `Release-As` override declared); update tests -- [x] Fold `write-agent-catalog-schema.ts` into `write-agent-catalog-manifest.ts`; update `agent-catalog:generate` -- [x] Remove dead `test:readonly-smoke` package script - -## 2. New testable scripts - -- [x] Implement `scripts/ci-context.ts` (gh api files+commits, builtins-only) + `test/ci-context.test.ts` -- [x] Implement `scripts/release-candidate.ts` (CI-strict default, `--local` dry-run) + `release:dry-run` package script + `test/release-candidate.test.ts` -- [x] Implement `scripts/verify-release-candidate.ts` (download-check, npm-state, assets-check, registry-closure) + `test/verify-release-candidate.test.ts` - -## 3. CI workflows - -- [x] `ci.yml`: classify via `ci-context.ts`; lint + governance consume classify outputs (delete duplicated github-script blocks); windows test runs on PRs -- [x] `sandbox-tests.yml`: classify via `ci-context.ts`; header comment marks it advisory -- [x] `release-please.yml`: rename job to `tag-release`, drop dead `if`, single-fire via `git push` tag (no workflow_dispatch) -- [x] Rename `scripts/release-tag-backstop.ts` → `scripts/tag-release.ts` (`ci:tag-release`); assert git-push tagging in tests -- [x] `release.yml`: build-candidate collapses to `bun run release:candidate` + upload; publish heredocs become `verify-release-candidate.ts` subcommand calls - -## 4. Docs single-homing - -- [x] Delete `docs/sessions/2026-04-28-oxlint-oxfmt-migration.md` -- [x] Delete `docs/runbooks/quantex-task-start.md`; point referencers at the runtime skill -- [x] Shrink `docs/github-collaboration.md` to GitHub-surface topics + pointers -- [x] Merge `automation-playbook.md` into `output-contracts.md`; update `skills/quantex-cli/SKILL.md` -- [x] Trim `AGENTS.md` gate prose to pointers -- [x] Single-source bootstrap stubs from `skills/quantex-agent-runtime/bootstrap-stub.md`; extend `memory:check` with stub byte-parity -- [x] Update `docs/README.md`, `docs/runbooks/README.md`, `docs/releases.md`, `docs/runbooks/releasing-quantex.md`, `docs/runbooks/modal-sandbox-testing.md`, `docs/runbooks/release-and-self-upgrade-debugging.md` for renamed scripts and the new release flow -- [x] Add `docs/adr/0009-workflow-v2.md` - -## 5. OpenSpec consolidation - -- [x] Merge `release-governance` + `release-note-input` + `core-npm-release` into `openspec/specs/release-workflow/spec.md`; delete the three directories -- [x] Merge `ci-platform-coverage` into `openspec/specs/code-quality-tooling/spec.md` (with honest-gates update); delete `ci-platform-coverage` -- [x] Reframe `core-installation-soak` as `openspec/specs/installation-routing/spec.md` (routing contract without the soak time-box); delete `core-installation-soak` -- [x] De-duplicate `openspec/specs/project-memory/spec.md` (remove the second root-markdown allowlist requirement) -- [x] Slim `openspec/config.yaml` context to pointers -- [x] Update spec-name references in `AGENTS.md`, docs, issue templates, tests -- [x] Archive `fix-release-tag-automation` via `bun run openspec:archive-closure` - -## 6. Local chain - -- [x] Add `setup` package script (`simple-git-hooks`); document post-install step -- [x] `pre-commit` → `bunx lint-staged` only -- [x] Clean stale `.vscode` extension mapping if present - -## 7. Validation and delivery - -- [x] `bun run lint`, `bun run format:check`, `bun run typecheck` -- [x] `bun run test` -- [x] `bun run openspec:validate`, `bun run memory:check` -- [x] `bun run build`, `bun run release:dry-run` (new harness smoke) -- [x] Commit, push, PR with `pr:body:check`-validated body noting the required-checks maintainer action diff --git a/openspec/changes/archive/2026-08-06-align-governance-gates/.openspec.yaml b/openspec/changes/archive/2026-08-06-align-governance-gates/.openspec.yaml deleted file mode 100644 index 1c37182e..00000000 --- a/openspec/changes/archive/2026-08-06-align-governance-gates/.openspec.yaml +++ /dev/null @@ -1,2 +0,0 @@ -schema: spec-driven -created: 2026-08-05 diff --git a/openspec/changes/archive/2026-08-06-align-governance-gates/proposal.md b/openspec/changes/archive/2026-08-06-align-governance-gates/proposal.md deleted file mode 100644 index 0821794e..00000000 --- a/openspec/changes/archive/2026-08-06-align-governance-gates/proposal.md +++ /dev/null @@ -1,48 +0,0 @@ -# Proposal: align-governance-gates - -## Why - -A failure audit of ~130 CI runs since 2026-07-16 shows governance gates are the single largest source of CI failures — roughly 53 occurrences, ahead of Windows tests (30) and the release pipeline (13). Two structural defects account for almost all of them, and neither is a policy disagreement: in both cases the contributor is following the documented process and still fails. - -**The shipped PR template does not satisfy the PR body policy that guards it.** `openspec/specs/release-workflow/spec.md` requires that a PR body be written "based on `.github/pull_request_template.md`", but the template ships with an empty `## Linked Artifacts` section, and `validatePrBodyPolicy` rejects a body with no meaningful linked artifact. GitHub auto-populates that template into every new pull request, so every contributor starts from a state the validator rejects and can only discover the extra requirement by failing CI. This is reproducible today: - -``` -bun run pr:body:check -- --body-file .github/pull_request_template.md --title "chore: some change" --> PR body must link at least one issue, ADR, OpenSpec artifact, or discussion -``` - -Observed failures include both halves of this: bodies written from scratch that omit required sections, and bodies copied from the template that fail the linked-artifact check. - -**The commit-author gate has no local counterpart.** The dominant governance failure message is `uses author metadata that can be re-emitted as a Co-authored-by trailer by GitHub squash merge` — the commit's *author identity* (for example `cursoragent@cursor.com` or a `[bot]@users.noreply.github.com` address), not a trailer in the message. The existing `commit-msg` hook only rewrites message text, so by construction it cannot catch this; `code-quality-tooling` deliberately scopes that hook to Cursor's trailer formats only. The result is that a branch passes every local hook and is rejected only after a full CI round trip, at which point the fix requires re-authoring commits and force-pushing. - -Both defects share one shape: **a rule that is only enforced remotely, against inputs that are already knowable locally.** - -## What Changes - -- **Make the PR template satisfy its own validator.** Restate `## Linked Artifacts` using the option-list style the template already uses for `## Release Intent` (list the applicable forms, delete the ones that do not apply), so the shipped template passes `validatePrBodyPolicy` unmodified while still requiring the author to make a real declaration. The intake classification that `AGENTS.md` already requires of every PR becomes a first-class line rather than tribal knowledge. -- **Lock template/validator consistency with a test.** Add regression coverage asserting that the shipped `.github/pull_request_template.md` passes `validatePrBodyPolicy`, that it contains every entry of `requiredPrBodyHeadings`, and that both release-please `pull-request-header` templates still pass. Today nothing prevents an edit to either side from silently re-breaking the other; this converts a recurring discover-by-CI-failure into a build-time guarantee. -- **Give the commit policy a local mode.** Add `--mode local` to `scripts/ci/commit-policy.ts`, which resolves the commits on the current branch and runs the *same* `validatePullRequestMergeCommitPolicy` function that CI runs, and wire it into the `pre-push` hook. Because both paths call one shared validator, local and remote cannot drift. A contributor learns about a bot author identity or a prohibited trailer in under a second, before pushing, instead of after a CI round trip. -- Document the required author identity for agent-driven sessions so the gate is satisfiable by configuration rather than by after-the-fact re-authoring. - -Out of scope, recorded for follow-up rather than folded in: relaxing the single-commit rule to fire only on multiple distinct author identities, the Windows `ci-context` test flake, release seal-contract title matching, and moving `sandbox-tests` off per-PR triggering. - -## Capabilities - -- **New Capabilities**: none. -- **Modified Capabilities**: - - `release-workflow` — the PR template is required to satisfy PR body governance, and that agreement is regression-tested. - - `code-quality-tooling` — `pre-push` gains local commit-policy enforcement sharing the CI validator; the `commit-msg` hook's Cursor-only scope is unchanged and explicitly complemented rather than replaced. - -## Impact - -- `.github/pull_request_template.md` -- `scripts/ci/commit-policy.ts`, `package.json` (`pre-push` hook) -- `test/pr-body-policy.test.ts`, `test/commit-policy.test.ts` -- `openspec/specs/release-workflow/spec.md`, `openspec/specs/code-quality-tooling/spec.md` -- Contributor-facing docs covering local validation and author identity - -No CLI behavior, structured output, agent catalog, config, state, or release-artifact surface changes. - -## Intake classification - -Durable-process and governance-contract change affecting GitHub collaboration flow and the local validation chain; OpenSpec required. diff --git a/openspec/changes/archive/2026-08-06-align-governance-gates/specs/release-workflow/spec.md b/openspec/changes/archive/2026-08-06-align-governance-gates/specs/release-workflow/spec.md deleted file mode 100644 index d7a10e2c..00000000 --- a/openspec/changes/archive/2026-08-06-align-governance-gates/specs/release-workflow/spec.md +++ /dev/null @@ -1,25 +0,0 @@ -# release-workflow Delta - -## ADDED Requirements - -### Requirement: The shipped PR template MUST satisfy PR body governance - -Because contributors and agents are required to write PR bodies based on `.github/pull_request_template.md`, that template SHALL itself pass the repository PR body governance check without modification. The template SHALL present every section required by PR body governance, and SHALL present its `Linked Artifacts` section so that an unmodified template already declares at least one meaningful artifact line, following the same option-list convention the template uses for release intent. - -The agreement between the template and the governance check SHALL be enforced by automated regression coverage, so that editing either side without the other fails the test suite rather than surfacing later as a rejected pull request. - -#### Scenario: Shipped template is validated directly - -- **WHEN** the repository PR body governance command runs against `.github/pull_request_template.md` -- **THEN** it MUST report no policy issues - -#### Scenario: Required sections drift apart - -- **WHEN** a required PR body heading is added to or removed from PR body governance -- **AND** `.github/pull_request_template.md` is not updated to match -- **THEN** the repository test suite MUST fail - -#### Scenario: Generated Release PR headers stay covered - -- **WHEN** the release-please stable or beta `pull-request-header` template is validated by PR body governance -- **THEN** it MUST report no policy issues, so generated Release PRs pass the same gate as human pull requests diff --git a/openspec/changes/archive/2026-08-06-align-governance-gates/tasks.md b/openspec/changes/archive/2026-08-06-align-governance-gates/tasks.md deleted file mode 100644 index 47855187..00000000 --- a/openspec/changes/archive/2026-08-06-align-governance-gates/tasks.md +++ /dev/null @@ -1,34 +0,0 @@ -# Tasks - -## 1. PR template satisfies its own validator - -- [x] Restate `## Linked Artifacts` in `.github/pull_request_template.md` using the existing `## Release Intent` option-list style, so the shipped template passes `validatePrBodyPolicy` unmodified -- [x] Verify by hand: `bun run pr:body:check -- --body-file .github/pull_request_template.md --title "chore: some change"` passes - -## 2. Lock template/validator consistency - -- [x] `test/pr-governance.test.ts`: assert the shipped template contains every `requiredPrBodyHeadings` entry (it already owns the template/governance assertions) -- [x] `test/pr-governance.test.ts`: assert the shipped template passes `validatePrBodyPolicy` with no issues -- [x] `test/pr-governance.test.ts`: assert both `release-please-config.json` and `release-please-config.beta.json` `pull-request-header` values still pass -- [x] Confirm the lock can fail: reverting the template, and renaming a required heading, each turn the suite red - -## 3. Local commit-policy mode - -- [x] Extract `validateCommitAuthorPolicy` so local and CI enforcement share one implementation per rule -- [x] Add `--mode local` to `scripts/ci/commit-policy.ts`: resolve current-branch commits via git and run the shared validators -- [x] Scope local enforcement to the trailer and author-identity rules; leave the single-commit rule to merge-time governance so work-in-progress pushes are not blocked -- [x] Resolve the comparison base safely (missing remote, unresolvable base, or no commits must be a clean no-op, never a false failure) -- [x] Wire `ci:commit-policy -- --mode local` into the `pre-push` hook in `package.json` -- [x] `test/commit-policy.test.ts`: cover local-mode parsing, no-op cases, both rejection rules, and the merge-time-only scope of the single-commit rule - -## 4. Spec and docs - -- [x] Document the required author identity for agent-driven sessions in `docs/github-collaboration.md` -- [x] Spec deltas stay in `openspec/changes/align-governance-gates/specs/`; they sync into `openspec/specs/` during archive closure after merge - -## 5. Validation and delivery - -- [x] `bun run lint`, `bun run format:check`, `bun run typecheck` -- [x] `bun run test` -- [x] `bun run openspec:validate`, `bun run memory:check` -- [x] Commit, push, PR with a `pr:body:check`-validated body (#587, merged) diff --git a/openspec/changes/archive/2026-08-06-drop-windows-thread-pool/.openspec.yaml b/openspec/changes/archive/2026-08-06-drop-windows-thread-pool/.openspec.yaml deleted file mode 100644 index 84cfc124..00000000 --- a/openspec/changes/archive/2026-08-06-drop-windows-thread-pool/.openspec.yaml +++ /dev/null @@ -1,2 +0,0 @@ -schema: spec-driven -created: 2026-08-06 diff --git a/openspec/changes/archive/2026-08-06-drop-windows-thread-pool/proposal.md b/openspec/changes/archive/2026-08-06-drop-windows-thread-pool/proposal.md deleted file mode 100644 index c2a61403..00000000 --- a/openspec/changes/archive/2026-08-06-drop-windows-thread-pool/proposal.md +++ /dev/null @@ -1,42 +0,0 @@ -# Proposal: drop-windows-thread-pool - -## Why - -The `test (windows-latest)` job intermittently dies with `error: script "test" exited with code 5`. Every test file reports a pass, no assertion fails, and Vitest never prints its summary — the process disappears partway through. It always passes on re-run, so every occurrence costs a manual retry. - -An A/B experiment isolated the cause. Two branches from the same commit differed only in whether the Windows job passed `--pool=threads`, and each received independent CI runs: - -| arm | exit-5 rate | -| --- | ---: | -| `--pool=threads` (current) | **3 / 10** | -| default pool | **0 / 9** | - -Supporting evidence rules out the alternatives. Vitest never returns 5 — its source sets only `1` and `130` — so the code comes from the Node process itself. Vitest runs under Node 24, not Bun, so this is not a Bun `worker_threads` gap. The last test file printed differs between occurrences, so it is not one bad test. Node exits `134` on heap exhaustion, not `5`, so it is not a simple out-of-memory. - -`--pool=threads` runs every worker inside a single process sharing one V8 instance; the default `forks` pool gives each worker its own process. Windows was the only platform passing the flag and the only platform showing the failure, while macOS and Ubuntu run the same suite and the same Vitest without it. - -The override has no recorded justification. It was added on 2026-04-23 in `a4fcd05` with an empty commit body, and `code-quality-tooling` then wrote it into the contract as "the established thread-pool invocation" — pinning an undocumented accident as a requirement. - -## What Changes - -- **Remove `--pool=threads` from the Windows test job.** All three platform jobs now run the same `bun run test`. -- **Restate the Windows coverage requirement** so it no longer mandates a thread-pool invocation, records why the override was removed, and forbids reintroducing a platform-specific pool without a recorded reason and evidence. - -## Capabilities - -- **Modified Capabilities**: - - `code-quality-tooling` — Windows coverage no longer pins a pool override, and platform jobs are required to agree on the test command. - -## Impact - -- `.github/workflows/ci.yml`, `openspec/specs/code-quality-tooling/spec.md` - -No product code, test, or release-surface changes. - -## Honest limits - -0/9 against 3/10 is a directional result, not proof. It is consistent with every other observation — Windows-only, threads-only, no failing test, not Vitest's own exit path — but the sample cannot exclude a rarer cause that the pool change merely masks. If exit 5 appears again after this lands, the pool was not the whole story and the investigation should resume from that fact rather than from this conclusion. - -## Intake classification - -Durable CI contract change removing a pinned invocation from `code-quality-tooling`; OpenSpec required. diff --git a/openspec/changes/archive/2026-08-06-drop-windows-thread-pool/specs/code-quality-tooling/spec.md b/openspec/changes/archive/2026-08-06-drop-windows-thread-pool/specs/code-quality-tooling/spec.md deleted file mode 100644 index 086d37f6..00000000 --- a/openspec/changes/archive/2026-08-06-drop-windows-thread-pool/specs/code-quality-tooling/spec.md +++ /dev/null @@ -1,28 +0,0 @@ -# code-quality-tooling Delta - -## MODIFIED Requirements - -### Requirement: Windows coverage SHALL gate product-impacting pull requests - -For pull requests with product-matrix scope, CI SHALL run the full Vitest command in the `test (windows-latest)` job. Windows coverage MUST NOT be limited to post-merge runs. - -All three platform jobs SHALL invoke the same test command and SHALL NOT override the Vitest pool. Windows previously passed `--pool=threads`, which runs every worker inside one process and one V8 instance instead of the default per-worker processes. That override was the only difference between the Windows job and the other two, and it correlated with intermittent job deaths that reported no failing test. - -A platform-specific pool override SHALL NOT be reintroduced without a recorded reason and evidence that it does not reintroduce those deaths. - -#### Scenario: Product-impacting pull request runs Windows tests - -- **WHEN** a pull request changes files that require the product test matrix -- **THEN** the `test (windows-latest)` job invokes the full-test command -- **AND** a failure blocks merge through the active ruleset - -#### Scenario: Platform jobs agree on the test command - -- **WHEN** the platform test jobs are compared -- **THEN** none of them MAY pass a `--pool` override to Vitest - -#### Scenario: Process-only pull request skips Windows tests - -- **WHEN** a pull request is classified process-only -- **THEN** the `test (windows-latest)` job reports `skipped` -- **AND** merge remains allowed when other required checks pass diff --git a/openspec/changes/archive/2026-08-06-drop-windows-thread-pool/tasks.md b/openspec/changes/archive/2026-08-06-drop-windows-thread-pool/tasks.md deleted file mode 100644 index 39976bf9..00000000 --- a/openspec/changes/archive/2026-08-06-drop-windows-thread-pool/tasks.md +++ /dev/null @@ -1,28 +0,0 @@ -# Tasks - -## 1. Remove the override - -- [x] Drop `--pool=threads` from the `test (windows-latest)` job in `.github/workflows/ci.yml` -- [x] Confirm all three platform jobs now invoke the same command - -## 2. Contract - -- [x] Restate the Windows coverage requirement so it no longer mandates a thread-pool invocation -- [x] Record why the override was removed, so the next reader does not restore it as a fix -- [x] Require a recorded reason and evidence before any platform-specific pool override returns -- [x] Leave `openspec/specs/` untouched; the delta applies during archive closure - -## 3. Guard against silent reintroduction - -- [x] Assert in `test/workflow-classification.test.ts` that no platform job passes a `--pool` override - -## 4. Validation and delivery - -- [x] `bun run lint`, `bun run format:check`, `bun run typecheck` -- [x] `bun run test` -- [x] `bun run openspec:validate`, `bun run memory:check` -- [x] Commit, push, PR with a `pr:body:check`-validated body (#603, merged) - -## 5. Follow-up after merge - -- [x] Recorded as a standing watch item rather than a task to complete: if exit 5 recurs after this lands, the pool was not the whole cause and the investigation resumes from that observation diff --git a/openspec/changes/archive/2026-08-06-finish-governance-followups/.openspec.yaml b/openspec/changes/archive/2026-08-06-finish-governance-followups/.openspec.yaml deleted file mode 100644 index 84cfc124..00000000 --- a/openspec/changes/archive/2026-08-06-finish-governance-followups/.openspec.yaml +++ /dev/null @@ -1,2 +0,0 @@ -schema: spec-driven -created: 2026-08-06 diff --git a/openspec/changes/archive/2026-08-06-finish-governance-followups/proposal.md b/openspec/changes/archive/2026-08-06-finish-governance-followups/proposal.md deleted file mode 100644 index 8e497085..00000000 --- a/openspec/changes/archive/2026-08-06-finish-governance-followups/proposal.md +++ /dev/null @@ -1,43 +0,0 @@ -# Proposal: finish-governance-followups - -## Why - -Three open items remain from the structure and CI governance audit recorded in `docs/sessions/2026-08-05-project-structure-audit.md`. They are independent of each other but all change workflow triggers, so they land together rather than as three PRs conflicting over the same two files. - -**The beta channel publishes versions older than stable.** `origin/beta` is frozen at `1.8.2-beta` while `main` is past `1.8.6`, so `npm install quantex-cli@beta` resolves strictly below `@latest`. Three defects compound: the channel cuts a prerelease *of an already-shipped stable* (`v1.8.2-beta` was tagged 59 minutes before `v1.8.2`), so by SemVer precedence it sorts below its own release and is behind by construction; nothing is pushed to `beta`, so release-please has produced exactly one release there since 2026-08-04; and both channels key package `.` against the same `.release-please-manifest.json`, so the two cannot hold independent versions without a merge that clobbers the very files recording them. That last defect is why the branch froze rather than merely lagging. - -**CI has no concurrency group.** `ci.yml` fires on `pull_request` type `edited`, so every title or body edit starts a full run including the three-platform matrix, and nothing cancels the superseded one. All three release workflows declare a group; the two that run most often do not. - -**`sandbox-tests` costs a run per pull request and has never gated anything.** It is advisory by design, fork PRs skip it for lack of secrets, and its recent failures were all external Modal capacity rather than repository regressions. - -**`AGENTS.md` restates what it says it delegates.** Its own red lines say the full gate text lives only in the runtime skill and that only triggers belong inline, but the validation-routing matrix and the OpenSpec intake signal list appear in full in both files, with nothing checking that they agree. - -## What Changes - -- **Retire the standing beta branch and publish prereleases from `main`.** The release identity contract currently derives the target branch from the version shape (`prerelease ? 'beta' : 'main'`); it will always resolve to `main`, while the npm dist-tag continues to derive from the version so a prerelease still publishes to `@beta`. A preview is then cut by declaring `Release-As: <next-version>-beta.N` on a source PR, which previews the *next unreleased* version and therefore always sorts above `@latest`. `release-please-config.beta.json` is deleted, `beta` is removed from every workflow trigger and branch allowlist, and the release PR title pattern accepts prerelease versions on `main`. -- **Add concurrency groups** to `ci.yml` and `sandbox-tests.yml`, keyed on the pull request number or ref, cancelling superseded runs. -- **Move `sandbox-tests` off per-pull-request triggering** to its schedule and manual dispatch, keeping it advisory and keeping its coverage where it is actually read. -- **Compress the `AGENTS.md` validation and intake blocks to triggers**, matching what the file already does for PR body governance, and extend `memory:check` so the runtime skill must carry the routing detail that `AGENTS.md` points at. - -Not included: the frozen `v1.8.2-beta` git tag and the npm `beta` dist-tag it published. Removing or repointing a published dist-tag is a registry action for a maintainer, not a repository change. - -## Capabilities - -- **Modified Capabilities**: - - `release-workflow` — the beta branch ceases to be a release channel; prereleases are cut from `main` and keep publishing to the `beta` dist-tag. - - `code-quality-tooling` — CI and sandbox workflows gain concurrency groups; `sandbox-tests` stops running per pull request. - - `project-memory` — `memory:check` gains a routing-parity guard between `AGENTS.md` and the runtime skill. - -## Impact - -- `.github/workflows/{ci,release,release-please,sandbox-tests}.yml`, `release-please-config.beta.json` (deleted) -- `scripts/release/{release-seal-contract,tag-release}.ts`, `scripts/ci/{release-pr-policy,path-taxonomy,check-project-memory}.ts` -- `AGENTS.md`, `docs/releases.md`, `docs/github-collaboration.md`, `docs/runbooks/releasing-quantex.md` -- `openspec/specs/{release-workflow,code-quality-tooling,project-memory}/spec.md` -- Tests covering release identity, tag targeting, release PR policy, path taxonomy, and project memory - -No CLI behavior, structured output, agent catalog, config, or state surface changes. - -## Intake classification - -Durable-process and release-contract change affecting the published release channel, CI triggers, and project memory policy; OpenSpec required. diff --git a/openspec/changes/archive/2026-08-06-finish-governance-followups/specs/code-quality-tooling/spec.md b/openspec/changes/archive/2026-08-06-finish-governance-followups/specs/code-quality-tooling/spec.md deleted file mode 100644 index b6497055..00000000 --- a/openspec/changes/archive/2026-08-06-finish-governance-followups/specs/code-quality-tooling/spec.md +++ /dev/null @@ -1,47 +0,0 @@ -# code-quality-tooling Delta - -## ADDED Requirements - -### Requirement: Merge-gating and advisory workflows SHALL cancel superseded runs - -`ci.yml` and `sandbox-tests.yml` SHALL each declare a concurrency group that cancels superseded **pull request** runs. `ci.yml` triggers on the `edited` pull request activity type so that PR body governance re-validates an edited description; without a concurrency group, a burst of edits leaves several full three-platform matrices running against superseded content. - -Push runs SHALL NOT be cancelled. Release tagging only tags a release commit whose exact SHA has a successful `ci.yml` run, so a push run cancelled by a later merge leaves that SHA permanently without a successful run — and if the cancelled push was a Release PR merge, the release silently never happens. Keying push runs by commit rather than by ref keeps them from colliding at all. - -Release workflows are excluded from this requirement: they already declare non-cancelling groups, because cancelling a publication mid-flight is not safe. - -#### Scenario: Pull request is edited repeatedly - -- **WHEN** a contributor edits a pull request title or body while a CI run is in progress -- **THEN** the superseded run MUST be cancelled -- **AND** only the newest run MUST remain - -#### Scenario: Two merges land back to back - -- **WHEN** a push to `main` starts a CI run and a second merge lands before it finishes -- **THEN** the first run MUST NOT be cancelled -- **AND** both commits MUST end with their own CI conclusion, so release tagging can find a successful run at either SHA - -#### Scenario: Release runs are not cancelled - -- **WHEN** a release workflow is running -- **THEN** its concurrency group MUST NOT cancel in-progress runs - -## MODIFIED Requirements - -### Requirement: Modal-backed isolation workflow remains separate from merge-gating CI - -Modal-backed isolation coverage SHALL run on a schedule and on manual dispatch, and SHALL NOT run on pull requests. It SHALL remain advisory and SHALL NOT be a required status check. - -Per-pull-request execution was removed because the workflow never gated anything: it is advisory by design, fork pull requests skip it for lack of secrets, and its observed failures were external Modal capacity rather than repository regressions. Running it on every pull request paid a full run for a signal nothing consumed. - -#### Scenario: Pull request does not trigger sandbox tests - -- **WHEN** a pull request is opened or updated -- **THEN** the Modal-backed isolation workflow MUST NOT run - -#### Scenario: Scheduled and dispatched runs still provide coverage - -- **WHEN** the schedule fires, or a maintainer dispatches the workflow manually -- **THEN** the Modal-backed isolation coverage MUST run -- **AND** its result MUST remain advisory diff --git a/openspec/changes/archive/2026-08-06-finish-governance-followups/specs/project-memory/spec.md b/openspec/changes/archive/2026-08-06-finish-governance-followups/specs/project-memory/spec.md deleted file mode 100644 index 452c1350..00000000 --- a/openspec/changes/archive/2026-08-06-finish-governance-followups/specs/project-memory/spec.md +++ /dev/null @@ -1,15 +0,0 @@ -# project-memory Delta - -## ADDED Requirements - -### Requirement: Handbook routing SHALL be verified rather than restated - -`AGENTS.md` SHALL inline only the triggers that decide which validation commands and which intake path apply, and SHALL point at `skills/quantex-agent-runtime/SKILL.md` for the full routing detail, matching how it already delegates PR body governance. The project memory check SHALL verify that the runtime skill actually carries the detail the handbook defers to it, so a pointer cannot outlive its target. - -Restating the full validation matrix and the full intake signal list in both files is prohibited: the two drifted apart with nothing detecting it, which is the failure mode `AGENTS.md` already names in its own red lines. - -#### Scenario: Handbook defers routing detail - -- **WHEN** the project memory check runs -- **THEN** it MUST verify that `skills/quantex-agent-runtime/SKILL.md` carries the validation commands and intake signals that `AGENTS.md` points at -- **AND** it MUST fail when the runtime skill no longer carries them diff --git a/openspec/changes/archive/2026-08-06-finish-governance-followups/specs/release-workflow/spec.md b/openspec/changes/archive/2026-08-06-finish-governance-followups/specs/release-workflow/spec.md deleted file mode 100644 index cc56098d..00000000 --- a/openspec/changes/archive/2026-08-06-finish-governance-followups/specs/release-workflow/spec.md +++ /dev/null @@ -1,57 +0,0 @@ -# release-workflow Delta - -## MODIFIED Requirements - -### Requirement: Release-please SHALL run automatically on protected-branch push - -On push to `main`, a `release-please` workflow SHALL open or update the Release PR using `release-please-config.json`. `main` is the only release channel: there is no second protected branch holding an independent version, because both channels would key the same package path against the same manifest file and could not diverge without a merge that overwrites the version state recording the divergence. - -#### Scenario: push to main opens a Release PR - -- **WHEN** a commit is pushed to `main` that is not a release commit -- **THEN** the release-please workflow MUST run -- **AND** it MUST use `release-please-config.json` -- **AND** it MUST open or update a Release PR for the next version - -#### Scenario: no second release branch is configured - -- **WHEN** the release automation is inspected -- **THEN** no workflow trigger, branch allowlist, or release-please config file MAY designate a branch other than `main` as a release channel - -### Requirement: Protected branches SHALL require aligned status check contexts - -The `main` protected branch SHALL require status check contexts that match the consolidated CI workflow job names and actually run on pull requests: `lint`, `governance`, `test (ubuntu-latest)`, `test (windows-latest)`, and `test (macos-latest)`. The `classify` job SHALL NOT be a required context. The `sandbox-tests` workflow SHALL remain advisory and SHALL NOT be a required context. - -There is no second protected release branch to mirror: `beta` ceased to be a release channel under the prerelease-from-main requirement above. The frozen `v1.8.2-beta` tag and the npm `beta` dist-tag pointing at it are registry state rather than repository state; repointing that dist-tag is a separate maintainer action. - -#### Scenario: main branch protection matches CI job names - -- **WHEN** a maintainer inspects branch protection for `main` -- **THEN** the required contexts MUST be exactly the five consolidated CI job names -- **AND** `classify` and `sandbox-tests` MUST NOT appear among them - -## ADDED Requirements - -### Requirement: Prereleases SHALL be cut from main and preview the next unreleased version - -A prerelease SHALL be produced from `main` by declaring `Release-As: <version>` with a prerelease suffix on a source PR, and SHALL name the next unreleased version rather than a version that has already shipped. The release identity contract SHALL resolve the target branch to `main` for every release regardless of version shape, and SHALL continue to derive the npm dist-tag from the version so that a prerelease publishes to `beta` and a stable release publishes to `latest`. - -Because a prerelease previews an unreleased version, the published `beta` dist-tag SHALL always resolve above `latest` by SemVer precedence. Cutting a prerelease of an already-published version is prohibited: such a version sorts below the release it names. - -#### Scenario: prerelease is cut from main - -- **WHEN** a source PR declares `Release-As: 1.9.0-beta.1` and merges to `main` -- **THEN** release tagging MUST resolve the target branch to `main` -- **AND** publication MUST use the `beta` npm dist-tag -- **AND** the resulting version MUST sort above the current `latest` - -#### Scenario: stable release is unaffected - -- **WHEN** a release commit for a version without a prerelease suffix merges to `main` -- **THEN** release tagging MUST resolve the target branch to `main` -- **AND** publication MUST use the `latest` npm dist-tag - -#### Scenario: Release PR title carries a prerelease version - -- **WHEN** release-please opens a Release PR on `main` for a prerelease version -- **THEN** release PR governance MUST accept the prerelease title shape diff --git a/openspec/changes/archive/2026-08-06-finish-governance-followups/tasks.md b/openspec/changes/archive/2026-08-06-finish-governance-followups/tasks.md deleted file mode 100644 index b6255262..00000000 --- a/openspec/changes/archive/2026-08-06-finish-governance-followups/tasks.md +++ /dev/null @@ -1,46 +0,0 @@ -# Tasks - -## 1. Retire the beta channel (P0) - -- [x] `scripts/release/release-seal-contract.ts`: resolve `targetBranch` to `main` for every release; keep `channel` and `npmTag` deriving from the version shape -- [x] `scripts/release/tag-release.ts`: accept only `main` as the release branch -- [x] `scripts/ci/release-pr-policy.ts`: restrict release base branches to `main`; accept both stable and prerelease title shapes there -- [x] `scripts/ci/path-taxonomy.ts`: drop `release-please-config.beta.json` from the release manifest paths -- [x] `.github/workflows/release-please.yml`: trigger on `main` only; delete the config-select step -- [x] `.github/workflows/release.yml`: stop deriving a beta target branch -- [x] `.github/workflows/{ci,sandbox-tests}.yml`: drop `beta` from branch triggers -- [x] Delete `release-please-config.beta.json` -- [x] Update tests for release identity, tag targeting, release PR policy, and path taxonomy - -## 2. CI concurrency (P1) - -- [x] Add a cancelling concurrency group to `ci.yml` keyed on PR number or ref -- [x] Add a cancelling concurrency group to `sandbox-tests.yml` -- [x] Assert both groups in tests, and assert release workflows keep `cancel-in-progress: false` - -## 3. Sandbox tests off per-PR triggering (P2) - -- [x] `.github/workflows/sandbox-tests.yml`: keep schedule and dispatch, drop pull_request and push triggers -- [x] Removed the classify job outright: it only ever gated the per-PR run, and scheduled runs always saw a null diff -- [x] Update the runbook and tests that assert the per-PR trigger - -## 4. AGENTS.md routing parity (P2) - -- [x] Compress the `AGENTS.md` validation block to triggers pointing at the runtime skill -- [x] Intake-signal block: **no change needed**. It already opens with a pointer to the runtime skill and carries only trigger keywords, so the audit finding was overstated for this block; the validation matrix was the only genuine restatement -- [x] Extend `scripts/ci/check-project-memory.ts` to verify the runtime skill carries the deferred detail -- [x] Guard is exercised by `bun run memory:check` in pre-push and the CI lint job - -## 5. Docs - -- [x] `docs/releases.md`: describe the single channel and how a prerelease is cut from `main` -- [x] `docs/runbooks/releasing-quantex.md`: remove the beta release path -- [x] `docs/github-collaboration.md`: branch protection now covers `main` only - -## 6. Validation and delivery - -- [x] `bun run lint`, `bun run format:check`, `bun run typecheck` -- [x] `bun run test` -- [x] `bun run openspec:validate`, `bun run memory:check` -- [x] `bun run release:dry-run` -- [x] Commit, push, PR with a `pr:body:check`-validated body (#591, merged; concurrency defect corrected by #593) diff --git a/openspec/changes/archive/2026-08-06-fix-install-sh-state-corruption/.openspec.yaml b/openspec/changes/archive/2026-08-06-fix-install-sh-state-corruption/.openspec.yaml deleted file mode 100644 index e8209ffa..00000000 --- a/openspec/changes/archive/2026-08-06-fix-install-sh-state-corruption/.openspec.yaml +++ /dev/null @@ -1,2 +0,0 @@ -schema: spec-driven -created: 2026-07-28 diff --git a/openspec/changes/archive/2026-08-06-fix-install-sh-state-corruption/design.md b/openspec/changes/archive/2026-08-06-fix-install-sh-state-corruption/design.md deleted file mode 100644 index 5fd8fe21..00000000 --- a/openspec/changes/archive/2026-08-06-fix-install-sh-state-corruption/design.md +++ /dev/null @@ -1,43 +0,0 @@ -## Context - -`install.sh` is the public curl-bootstrap path for standalone binaries. After placing the binary it optionally records `self.installSource = "binary"` in `~/.quantex/state.json` via an inline Python snippet. - -Today that snippet: - -1. On parse failure, keeps an empty default object and overwrites the file — wiping agent lifecycle evidence. -2. Uses `Path.write_text`, which truncates the destination before the new JSON is fully written — torn JSON on interrupt. - -The CLI already obeys fail-closed and atomic-write rules in `openspec/specs/quantex-state/spec.md`. Bootstrap installers that mutate the same file must follow the same contract. - -## Goals / Non-Goals - -**Goals:** - -- Prevent `install.sh` from wiping or tearing `state.json` when recording the binary install source. -- Keep binary installation successful even when state recording is skipped due to corrupt existing state. -- Cover the safety shape with a static regression test. - -**Non-Goals:** - -- Adding state recording to `install.ps1` -- Cross-process locking for installer vs CLI races beyond atomic rename -- Changing Core install/ensure or self-upgrade detection logic - -## Decisions - -1. **Fail closed, do not fail the binary install** - If `state.json` exists but cannot be loaded into a safe object shape, leave it untouched, emit a warning, and still report binary install success. Self-upgrade can later detect a standalone binary from the executable path. - -2. **Atomic replace for successful updates** - Write complete JSON to a same-directory temporary file, then `os.replace` onto `state.json`. - -3. **Preserve existing evidence** - When updating a readable document, only set `self.installSource = "binary"` and preserve `installedAgents`, `lifecycleReceipts`, and schema metadata already present. - -4. **Static source test** - Assert `install.sh` contains fail-closed parse handling and temp-file/`os.replace` write shape, matching the approach used for other installer script regressions. - -## Risks / Trade-offs - -- [Risk] Users with corrupt state do not get `installSource` persisted by the installer → Mitigation: CLI standalone detection still classifies binary installs; warning tells the user state was left alone. -- [Risk] Concurrent CLI writers can still race with the installer → Mitigation: atomic rename removes truncate tears; full locking is out of scope for this narrow fix. diff --git a/openspec/changes/archive/2026-08-06-fix-install-sh-state-corruption/proposal.md b/openspec/changes/archive/2026-08-06-fix-install-sh-state-corruption/proposal.md deleted file mode 100644 index 58effd7a..00000000 --- a/openspec/changes/archive/2026-08-06-fix-install-sh-state-corruption/proposal.md +++ /dev/null @@ -1,26 +0,0 @@ -## Why - -The public `install.sh` bootstrap records `self.installSource = "binary"` by rewriting `~/.quantex/state.json` with a non-atomic truncate-write, and on JSON parse failure it substitutes empty default state. That can wipe recorded `installedAgents` / `lifecycleReceipts` or leave torn JSON, violating the existing `quantex-state` fail-closed and atomic-write contracts. - -## What Changes - -- Make `install.sh` fail closed when an existing `state.json` cannot be parsed or is not a safe object shape: leave the file untouched and continue the binary install. -- Make successful `install.sh` state updates write through a temporary file and atomic rename. -- Preserve existing installed-agent and receipt evidence when only recording the binary install source. -- Add a static regression test that locks the fail-closed and atomic-write shape in `install.sh`. - -## Capabilities - -### New Capabilities - -- None - -### Modified Capabilities - -- `quantex-state`: Extend the fail-closed and atomic-write requirements so public bootstrap installers that mutate `state.json` obey the same safety contract as the CLI. - -## Impact - -- Affected files: `install.sh`, `openspec/specs/quantex-state/spec.md` (via delta), `test/install-scripts.test.ts` -- Work-intake classification: configuration/state mutation safety for a product-facing installer — OpenSpec required -- Non-goals: Windows `install.ps1` state recording (it does not write state today), Core staged install/ensure, release workflow changes diff --git a/openspec/changes/archive/2026-08-06-fix-install-sh-state-corruption/specs/quantex-state/spec.md b/openspec/changes/archive/2026-08-06-fix-install-sh-state-corruption/specs/quantex-state/spec.md deleted file mode 100644 index 82f368f9..00000000 --- a/openspec/changes/archive/2026-08-06-fix-install-sh-state-corruption/specs/quantex-state/spec.md +++ /dev/null @@ -1,29 +0,0 @@ -## ADDED Requirements - -### Requirement: Bootstrap installers that mutate state MUST fail closed and write atomically - -Public Quantex bootstrap installers that update `state.json` MUST obey the same fail-closed and atomic-write safety contract as the CLI: they MUST NOT substitute empty default state over an unreadable or unsafe existing file, and they MUST replace `state.json` only after a complete temporary write. - -#### Scenario: install.sh leaves corrupt state untouched - -- **GIVEN** `~/.quantex/state.json` exists with previously recorded `installedAgents` or lifecycle evidence -- **AND** the file contents are not valid JSON or are not a JSON object -- **WHEN** `install.sh` attempts to record `self.installSource = "binary"` -- **THEN** it leaves the existing `state.json` contents unchanged -- **AND** it does not overwrite the file with empty default state -- **AND** the standalone binary installation itself still completes - -#### Scenario: install.sh updates readable state through atomic replace - -- **GIVEN** a readable object-shaped `state.json` already exists under the Quantex config directory -- **WHEN** `install.sh` records `self.installSource = "binary"` -- **THEN** it preserves existing `installedAgents` and lifecycle evidence fields -- **AND** it writes the updated document to a temporary file in the same directory first -- **AND** it replaces `state.json` only via an atomic rename of that completed temporary file - -#### Scenario: install.sh creates missing state safely - -- **GIVEN** no `state.json` exists under the Quantex config directory -- **WHEN** `install.sh` records `self.installSource = "binary"` -- **THEN** it may create a new state document that sets `self.installSource` to `binary` -- **AND** it still writes that document through a temporary file and atomic rename diff --git a/openspec/changes/archive/2026-08-06-fix-install-sh-state-corruption/tasks.md b/openspec/changes/archive/2026-08-06-fix-install-sh-state-corruption/tasks.md deleted file mode 100644 index cd8dc44e..00000000 --- a/openspec/changes/archive/2026-08-06-fix-install-sh-state-corruption/tasks.md +++ /dev/null @@ -1,15 +0,0 @@ -## 1. Installer safety - -- [x] 1.1 Rewrite `install.sh` state recording to fail closed on unreadable/unsafe existing `state.json` -- [x] 1.2 Make successful `install.sh` state updates use a same-directory temp file and atomic replace -- [x] 1.3 Preserve existing installed-agent and lifecycle evidence when recording `self.installSource` - -## 2. Regression coverage - -- [x] 2.1 Add `test/install-scripts.test.ts` assertions for fail-closed parse handling and atomic replace -- [x] 2.2 Add a focused behavioral check that corrupt state is left untouched by the Python recorder path - -## 3. Validation - -- [x] 3.1 Run `bun run lint`, `bun run format:check`, `bun run typecheck`, and `bun run test` -- [x] 3.2 Run `bun run openspec:validate` and `bun run memory:check` diff --git a/openspec/changes/archive/2026-08-06-fix-uninstall-path-residual-state-corruption/.openspec.yaml b/openspec/changes/archive/2026-08-06-fix-uninstall-path-residual-state-corruption/.openspec.yaml deleted file mode 100644 index f205fc72..00000000 --- a/openspec/changes/archive/2026-08-06-fix-uninstall-path-residual-state-corruption/.openspec.yaml +++ /dev/null @@ -1,2 +0,0 @@ -schema: spec-driven -created: 2026-07-29 diff --git a/openspec/changes/archive/2026-08-06-fix-uninstall-path-residual-state-corruption/design.md b/openspec/changes/archive/2026-08-06-fix-uninstall-path-residual-state-corruption/design.md deleted file mode 100644 index 38fb4722..00000000 --- a/openspec/changes/archive/2026-08-06-fix-uninstall-path-residual-state-corruption/design.md +++ /dev/null @@ -1,37 +0,0 @@ -## Context - -Managed uninstall removes the bound provider package and clears installed-agent state inside `uninstallInstalledAgentOutcome`. The uninstall command then polls until both the bound provider is absent and the agent binary leaves `PATH`. Dual installs of the same binary (for example npm-managed plus another PATH copy) make the PATH half of that postcondition fail even after the managed package is gone. Today's failure path always restores installed-agent state, reinventing ownership for an already-removed package and permanently trapping later uninstalls in `conflicting-source`. - -## Goals / Non-Goals - -**Goals:** - -- Restore evidence only when the bound managed package is still present or provider evidence is inconclusive. -- When the bound provider is conclusively absent after successful removal, clear lifecycle tracking and treat any residual `PATH` binary as untracked rather than Quantex-owned. -- Keep cancellation and provider-still-present verification failures on the current retain-evidence path. - -**Non-Goals:** - -- Removing residual untracked binaries from `PATH`. -- Changing script/binary state-only uninstall behavior. -- Solving concurrent update/uninstall races outside this postcondition restore path. -- Broad redesign of uninstall error taxonomy. - -## Decisions - -1. **Re-observe the bound provider after postcondition failure before restoring state.** - - Alternative: always restore state (current). Rejected because it recreates false ownership when the provider is already absent. - - Alternative: never restore state. Rejected because provider-still-present failures must keep retry evidence. - -2. **Clear receipt and leave installed state absent when provider absence is conclusive.** - - `uninstallInstalledAgentOutcome` already deleted installed state on success; skipping restore keeps that truth. - - Clearing the receipt prevents the next uninstall from seeing receipt + absent provider + live PATH as a permanent conflict; retry becomes unmanaged/PATH-only. - -3. **Return `conflicting-source` for the residual-PATH outcome.** - - Matches the planning-time classification for the same evidence shape (provider absent + live PATH). - - Keeps structured failure distinct from unmanaged and provider-failure outcomes. - -## Risks / Trade-offs - -- [User sees failure even though the managed package was removed] → Mitigation: message states the managed package was removed and another PATH copy remains; tracking is cleared so `inspect`/`uninstall` can classify the residual binary as unmanaged. -- [Indeterminate provider observation after removal] → Mitigation: keep retain-evidence / verification-failed behavior when provider evidence is not conclusively absent. diff --git a/openspec/changes/archive/2026-08-06-fix-uninstall-path-residual-state-corruption/proposal.md b/openspec/changes/archive/2026-08-06-fix-uninstall-path-residual-state-corruption/proposal.md deleted file mode 100644 index 4a89b4c7..00000000 --- a/openspec/changes/archive/2026-08-06-fix-uninstall-path-residual-state-corruption/proposal.md +++ /dev/null @@ -1,27 +0,0 @@ -## Why - -After a managed provider uninstall succeeds, Quantex still requires the agent binary to disappear from `PATH`. When another unrelated install of the same binary remains on `PATH`, postcondition verification fails and the uninstall command restores the just-cleared installed-agent state. That rewrites stale ownership for a package that is already gone, so the next `quantex uninstall` permanently returns `conflicting-source` and the lifecycle cannot be repaired without manual state edits. - -## What Changes - -- After a successful managed provider uninstall, re-check bound provider presence before restoring evidence on verification failure. -- When the bound provider is conclusively absent but a residual `PATH` binary remains, do **not** restore installed-agent state; clear the lifecycle receipt and classify the residual binary as untracked/conflicting rather than Quantex-owned. -- Keep the existing retain-evidence behavior when the bound provider is still present or provider evidence is indeterminate. -- Add a regression test for the dual-install / residual-`PATH` failure mode. - -## Capabilities - -### New Capabilities - -- (none) - -### Modified Capabilities - -- `agent-uninstall`: distinguish residual untracked `PATH` binaries from failed managed-package removal when deciding whether to restore uninstall evidence. - -## Impact - -- `src/commands/uninstall.ts` postcondition failure handling -- `openspec/specs/agent-uninstall/spec.md` (via delta) -- `test/commands/uninstall.test.ts` -- Work-intake classification: observable CLI uninstall/state behavior → OpenSpec required diff --git a/openspec/changes/archive/2026-08-06-fix-uninstall-path-residual-state-corruption/specs/agent-uninstall/spec.md b/openspec/changes/archive/2026-08-06-fix-uninstall-path-residual-state-corruption/specs/agent-uninstall/spec.md deleted file mode 100644 index 10bb7547..00000000 --- a/openspec/changes/archive/2026-08-06-fix-uninstall-path-residual-state-corruption/specs/agent-uninstall/spec.md +++ /dev/null @@ -1,27 +0,0 @@ -## ADDED Requirements - -### Requirement: Residual PATH binaries MUST NOT restore cleared managed uninstall evidence - -After a successful managed provider uninstall, Quantex MUST re-check the bound provider before restoring lifecycle evidence on postcondition failure. When the bound provider conclusively reports the managed package absent and only a residual live executable remains on `PATH`, Quantex MUST NOT restore the installed-agent state that the provider uninstall already cleared, MUST clear the lifecycle receipt for that agent, and MUST classify the residual executable as untracked rather than Quantex-owned. Quantex MUST still retain installed-agent state and receipt evidence when the bound provider remains present or provider evidence is indeterminate. - -#### Scenario: Residual PATH binary after conclusive managed package removal - -- **GIVEN** an agent has managed installed-agent state and a receipt for a bound provider package -- **AND** the provider uninstall removes that package successfully -- **AND** post-uninstall provider observation conclusively reports the bound package absent -- **AND** another copy of the agent executable remains on `PATH` -- **WHEN** the user runs `qtx uninstall <agent>` -- **THEN** Quantex does not restore the cleared installed-agent state -- **AND** it clears the lifecycle receipt -- **AND** it returns a conflicting-source uninstall failure distinct from unmanaged and provider-failure outcomes -- **AND** a later uninstall without restored managed evidence classifies the residual executable as unmanaged or untracked - -#### Scenario: Provider still present after uninstall still retains evidence - -- **GIVEN** an agent has managed installed-agent state and a receipt for a bound provider package -- **AND** the provider uninstall reports success -- **AND** post-uninstall provider observation still reports the bound package present -- **WHEN** the user runs `qtx uninstall <agent>` -- **THEN** Quantex restores or retains the installed-agent state needed for retry -- **AND** it retains the lifecycle receipt -- **AND** it returns a verification-failed uninstall failure diff --git a/openspec/changes/archive/2026-08-06-fix-uninstall-path-residual-state-corruption/tasks.md b/openspec/changes/archive/2026-08-06-fix-uninstall-path-residual-state-corruption/tasks.md deleted file mode 100644 index ff9a3382..00000000 --- a/openspec/changes/archive/2026-08-06-fix-uninstall-path-residual-state-corruption/tasks.md +++ /dev/null @@ -1,16 +0,0 @@ -## 1. Regression coverage - -- [x] 1.1 Add an uninstall regression that simulates successful managed removal, conclusive provider absence, and residual PATH presence -- [x] 1.2 Assert installed-agent state is not restored, the lifecycle receipt is cleared, and the result is conflicting-source -- [x] 1.3 Keep existing provider-still-present and cancellation retain-evidence regressions green - -## 2. Uninstall postcondition restore path - -- [x] 2.1 After postcondition failure, re-observe the bound provider before restoring evidence -- [x] 2.2 When the provider is conclusively absent, skip state restore, clear the receipt, and return conflicting-source -- [x] 2.3 When the provider remains present or evidence is indeterminate, retain installed-agent state and return verification-failed - -## 3. Validation - -- [x] 3.1 Run `bun run lint`, `bun run format:check`, `bun run typecheck`, and `bun run test` -- [x] 3.2 Run `bun run openspec:validate` diff --git a/openspec/changes/archive/2026-08-06-remove-author-governance/.openspec.yaml b/openspec/changes/archive/2026-08-06-remove-author-governance/.openspec.yaml deleted file mode 100644 index 84cfc124..00000000 --- a/openspec/changes/archive/2026-08-06-remove-author-governance/.openspec.yaml +++ /dev/null @@ -1,2 +0,0 @@ -schema: spec-driven -created: 2026-08-06 diff --git a/openspec/changes/archive/2026-08-06-remove-author-governance/proposal.md b/openspec/changes/archive/2026-08-06-remove-author-governance/proposal.md deleted file mode 100644 index 6edd3912..00000000 --- a/openspec/changes/archive/2026-08-06-remove-author-governance/proposal.md +++ /dev/null @@ -1,48 +0,0 @@ -# Proposal: remove-author-governance - -## Why - -The repository enforces three linked rules whose only purpose is keeping `Co-authored-by` trailers out of `main`: newly introduced commits may not contain the trailer, a pull request may not carry a commit authored by a bot or agent identity, and a non-release pull request may not contain more than one commit. The archived `block-coauthored-by-trailers` proposal records the original motivation — merged history had picked up trailers that did not match the project's intended authorship policy, and remediation was expensive because it was only discovered after merge and required force-pushing a protected branch. - -The measurement does not support keeping them. - -**They are the largest source of CI failures.** Across roughly 130 runs since 2026-07-16, governance steps account for about 53 failures, ahead of Windows tests (30) and the release pipeline (13). The most frequent single message is `uses author metadata that can be re-emitted as a Co-authored-by trailer by GitHub squash merge`. - -**They do not achieve their goal.** The trailer rule has been enforced since 2026-05-04, and `main` has accepted at least nine commits carrying a real `Co-authored-by:` trailer since — `fix(lifecycle): clear tracked script/binary uninstall state (#497)`, `docs(openspec): archive remove-superpowers-runtime (#499)`, `chore: release 1.6.0 (#538)`, and `chore: release 1.7.1` among them. The trailers that land credit the maintainer's own GitHub noreply identity and the repository's own release bot. They are added by GitHub at merge time — squash attribution with `squash_merge_commit_message=COMMIT_MESSAGES`, and web-UI operations — which a check that reads the pull request's branch commits structurally cannot observe. - -So the gates reject the branch commits an agent authored, while the trailers that actually reach `main` come from the merge itself and pass untouched. The cost is a recurring merge-blocking failure; the benefit is not realized. - -The single-commit rule has no independent justification. It was added two days after the trailer rule (`ci: block squash coauthor trailer risk before merge`) purely to prevent GitHub from synthesizing trailers when squashing a multi-author branch, and its own failure message says so. Removing the trailer policy leaves it defending nothing. - -## What Changes - -- **Remove the commit trailer policy.** `validateCommitTrailerPolicy` and the `Validate commit trailer policy` step in the `lint` job of `ci.yml` are deleted. -- **Remove the commit author identity policy.** `validateCommitAuthorPolicy` and its risky-identity patterns are deleted, along with the local `--mode local` pre-push enforcement added by `align-governance-gates` before that change was archived. -- **Remove the single-commit rule.** Pull requests may again contain more than one commit. -- **Remove the local Cursor trailer hook.** `scripts/ci/strip-cursor-coauthor.ts`, its test, and the `commit-msg` hook entry are deleted; with no remote trailer policy, a local stripper has nothing to serve. -- **Reduce `scripts/ci/commit-policy.ts` to its one remaining rule**: a source pull request that declares `Release-As` in its body must carry the same footer in a commit, since release-please consumes the footer from the merged commit. The `--mode` flag disappears with the modes it distinguished, and the check fails closed only when a `Release-As` declaration cannot be verified rather than on every metadata-free invocation. -- Update `docs/github-collaboration.md` and `docs/runbooks/releasing-quantex.md`, which documented re-authoring release branches to satisfy the removed author gate. - -Attribution on `main` is instead addressed where the trailers are actually produced, by repository merge settings rather than by a pre-merge branch check. - -## Capabilities - -- **New Capabilities**: none. -- **Modified Capabilities**: - - `release-workflow` — the protected-branch co-author trailer requirement is removed; `Release-As` commit-footer consistency remains. - - `code-quality-tooling` — the local `commit-msg` Cursor trailer requirement is removed; `pre-push` returns to the repository-wide workflow gates. - -## Impact - -- `scripts/ci/commit-policy.ts`, `scripts/ci/strip-cursor-coauthor.ts` (deleted) -- `package.json` (`simple-git-hooks`), `.github/workflows/ci.yml` -- `test/commit-policy.test.ts`, `test/pr-governance.test.ts`, `test/strip-cursor-coauthor.test.ts` (deleted) -- `openspec/specs/release-workflow/spec.md`, `openspec/specs/code-quality-tooling/spec.md` -- `docs/github-collaboration.md`, `docs/runbooks/releasing-quantex.md` -- `openspec/changes/align-governance-gates/specs/code-quality-tooling/spec.md` (deleted): that change is merged but not yet archived, and its pre-push commit-policy requirement is superseded here before it was ever synced into `openspec/specs/`. Its PR-template requirement is unaffected and still archives normally. - -No CLI behavior, structured output, agent catalog, config, state, or release-artifact surface changes. - -## Intake classification - -Durable-process and governance-contract change removing merge-gating requirements from two specs; OpenSpec required. diff --git a/openspec/changes/archive/2026-08-06-remove-author-governance/specs/code-quality-tooling/spec.md b/openspec/changes/archive/2026-08-06-remove-author-governance/specs/code-quality-tooling/spec.md deleted file mode 100644 index 61bace1d..00000000 --- a/openspec/changes/archive/2026-08-06-remove-author-governance/specs/code-quality-tooling/spec.md +++ /dev/null @@ -1,9 +0,0 @@ -# code-quality-tooling Delta - -## REMOVED Requirements - -### Requirement: Local commit-msg hook MUST remove Cursor attribution trailers before commit creation - -**Reason**: The hook existed solely to keep commits from tripping the remote co-author trailer policy. That policy is removed, so the hook rewrites commit messages to satisfy a rule that no longer exists. - -**Migration**: `scripts/ci/strip-cursor-coauthor.ts`, its test, and the `commit-msg` hook entry in `package.json` are deleted. `pre-commit` and `pre-push` are unchanged apart from dropping the commit-policy step that `align-governance-gates` added; `pre-push` continues to run lint, format check, typecheck, OpenSpec validation, and the project memory check. diff --git a/openspec/changes/archive/2026-08-06-remove-author-governance/specs/release-workflow/spec.md b/openspec/changes/archive/2026-08-06-remove-author-governance/specs/release-workflow/spec.md deleted file mode 100644 index dec93ace..00000000 --- a/openspec/changes/archive/2026-08-06-remove-author-governance/specs/release-workflow/spec.md +++ /dev/null @@ -1,9 +0,0 @@ -# release-workflow Delta - -## REMOVED Requirements - -### Requirement: Protected-branch CI MUST reject prohibited co-author trailers in new commits - -**Reason**: The rule did not achieve its goal and was the largest single source of merge-blocking CI failures. Enforced since 2026-05-04, it still allowed at least nine commits carrying a real `Co-authored-by:` trailer onto `main`, because those trailers are added by GitHub at merge time — squash attribution and web-UI operations — which a check reading the pull request's branch commits cannot observe. The trailers that landed credit the maintainer's own GitHub noreply identity and the repository's release bot, not the third-party tooling the rule was written for. - -**Migration**: Attribution on `main` is addressed through repository merge settings, where the trailers are actually produced. The pull-request commit shape requirements that existed only to keep GitHub from synthesizing these trailers — the bot and agent author identity rejection, and the single-commit limit for non-release pull requests — are removed with it. `Release-As` commit-footer consistency is unaffected and continues to be enforced, because release-please reads that footer from the merged commit. diff --git a/openspec/changes/archive/2026-08-06-remove-author-governance/tasks.md b/openspec/changes/archive/2026-08-06-remove-author-governance/tasks.md deleted file mode 100644 index 470a943c..00000000 --- a/openspec/changes/archive/2026-08-06-remove-author-governance/tasks.md +++ /dev/null @@ -1,37 +0,0 @@ -# Tasks - -## 1. Remove the author-related gates - -- [x] Delete `validateCommitTrailerPolicy` and the `Validate commit trailer policy` step from the `lint` job in `ci.yml` -- [x] Delete `validateCommitAuthorPolicy`, its risky-identity patterns, and the `--mode local` pre-push enforcement -- [x] Delete the single-commit rule for non-release pull requests -- [x] Delete `scripts/ci/strip-cursor-coauthor.ts`, its test, and the `commit-msg` hook entry -- [x] Reduce `scripts/ci/commit-policy.ts` to the `Release-As` footer consistency check and drop the now-meaningless `--mode` flag -- [x] Rename the governance step to `Validate PR commit policy` and update its invocation - -## 2. Specs and docs - -- [x] Remove the co-author trailer requirement from `openspec/specs/release-workflow/spec.md` -- [x] Remove the commit-msg hook requirement from `openspec/specs/code-quality-tooling/spec.md` -- [x] Drop the superseded pre-push delta from the merged-but-unarchived `align-governance-gates` change before it syncs into specs -- [x] Remove the `Commit authorship` section from `docs/github-collaboration.md` -- [x] Update `docs/runbooks/releasing-quantex.md`, which required re-authoring the release branch to satisfy the removed gate - -## 3. Tests - -- [x] Rewrite `test/commit-policy.test.ts` around the surviving `Release-As` rule -- [x] Add regression coverage asserting the removed gates stay removed (no trailer pattern, no agent identity list, no squash instruction, no `commit-msg` hook) -- [x] Update `test/pr-governance.test.ts` for the renamed step - -## 4. Repository merge settings - -- [x] Disable merge commits, which `release-workflow` already forbids, so the platform enforces the documented preference -- [x] Investigate squash message settings: rejected. GitHub only accepts `PR_BODY` together with `PR_TITLE`, and moving the squash body off the branch commit messages changes what release-please reads from the merged commit, including the `BEGIN_COMMIT_OVERRIDE` block. The observed trailers come from GitHub's automatic co-author attribution rather than message text, so the change carries release risk for negligible benefit -- [x] Record that rebase merge, not squash, is what preserved a bot commit author on `main`; the linear-history preference in `release-workflow` is the path that produced the attribution it was trying to avoid - -## 5. Validation and delivery - -- [x] `bun run lint`, `bun run format:check`, `bun run typecheck` -- [x] `bun run test` -- [x] `bun run openspec:validate`, `bun run memory:check` -- [x] Commit, push, PR with a `pr:body:check`-validated body (#588, merged) diff --git a/openspec/changes/archive/2026-08-06-retire-prerelease-channel/.openspec.yaml b/openspec/changes/archive/2026-08-06-retire-prerelease-channel/.openspec.yaml deleted file mode 100644 index 84cfc124..00000000 --- a/openspec/changes/archive/2026-08-06-retire-prerelease-channel/.openspec.yaml +++ /dev/null @@ -1,2 +0,0 @@ -schema: spec-driven -created: 2026-08-06 diff --git a/openspec/changes/archive/2026-08-06-retire-prerelease-channel/proposal.md b/openspec/changes/archive/2026-08-06-retire-prerelease-channel/proposal.md deleted file mode 100644 index 18c15223..00000000 --- a/openspec/changes/archive/2026-08-06-retire-prerelease-channel/proposal.md +++ /dev/null @@ -1,36 +0,0 @@ -# Proposal: retire-prerelease-channel - -## Why - -`release-workflow` currently states that a prerelease is cut by declaring `Release-As: <version>` with a prerelease suffix on a source PR. That does not work, and the requirement was written without being exercised. - -Merging #517 with `Release-As: 1.8.7-beta.1` on the commit produced a Release PR for stable `1.8.7`, not `1.8.7-beta.1`. release-please emits prerelease versions only when its config declares them — the retired `release-please-config.beta.json` carried `versioning: prerelease`, `prerelease: true`, and `prerelease-type: beta`, which is why the old branch could produce `-beta` versions at all. `release-please-config.json` carries none of those, so the suffix is normalized away. - -The requirement passed review because validation checked the wrong half. `release:dry-run` exercises the build and staging chain and confirmed the publish side derives the `beta` dist-tag from a prerelease version; it never touches release-please's version computation, which is the half that had to work. One half was verified and the other assumed. - -Rather than build a third mechanism, the channel goes away. Across 102 published versions, 12 are prereleases and 11 of those are from the pre-1.0 `0.0.x` period. The entire 1.x line has produced exactly one — `1.8.2-beta`, published 2026-08-04, abandoned immediately, and the source of the inversion this workstream has been chasing. There is no demonstrated need for a prerelease channel, and every iteration spent designing one has cost more than the feature has ever returned. - -## What Changes - -- **Remove the prerelease requirement** from `release-workflow`. `main` is the only release line and publishes to `latest`. -- **Keep the version-to-dist-tag derivation** in the release identity contract as a fail-safe rather than a feature: if a version carrying a prerelease suffix is ever produced, publication still routes it to the `beta` dist-tag so it cannot displace `latest`. This is stated so the mapping is not later removed as dead code. -- **Drop the `Prereleases` section** from `docs/releases.md`. - -No mechanism replaces the channel. If a preview need appears later, it can be designed against that need — and verified against release-please's actual behaviour before being written into a contract. - -Out of scope, and a maintainer action this change cannot perform: the npm `beta` dist-tag still points at `1.8.2-beta`. It is registry state, and removing it requires publish credentials. - -## Capabilities - -- **Modified Capabilities**: - - `release-workflow` — the prerelease channel requirement is removed; the dist-tag fail-safe is retained explicitly. - -## Impact - -- `openspec/specs/release-workflow/spec.md`, `docs/releases.md` - -No code changes. `scripts/release/release-seal-contract.ts` keeps deriving the dist-tag from the version shape, which is the retained fail-safe. - -## Intake classification - -Durable release-contract change removing a published requirement; OpenSpec required. diff --git a/openspec/changes/archive/2026-08-06-retire-prerelease-channel/specs/release-workflow/spec.md b/openspec/changes/archive/2026-08-06-retire-prerelease-channel/specs/release-workflow/spec.md deleted file mode 100644 index 1389f11d..00000000 --- a/openspec/changes/archive/2026-08-06-retire-prerelease-channel/specs/release-workflow/spec.md +++ /dev/null @@ -1,30 +0,0 @@ -# release-workflow Delta - -## REMOVED Requirements - -### Requirement: Prereleases SHALL be cut from main and preview the next unreleased version - -**Reason**: The stated mechanism does not work and was never exercised before being written down. Merging a commit carrying `Release-As: 1.8.7-beta.1` produced a Release PR for stable `1.8.7`: release-please emits prerelease versions only when its config declares `versioning: prerelease` / `prerelease: true` / `prerelease-type`, which `release-please-config.json` does not. `release:dry-run` verified the publish side and never touched version computation, so the requirement passed validation that could not have caught it. - -The channel is also unused. Of 102 published versions, 12 are prereleases and 11 predate 1.0; the 1.x line produced exactly one, `1.8.2-beta`, which was abandoned immediately and is the inversion this workstream has been chasing. - -**Migration**: No mechanism replaces it. `main` is the only release line and publishes to `latest`. The npm `beta` dist-tag is retired by a maintainer through `npm dist-tag rm quantex-cli beta`; it is registry state, not repository state. - -## ADDED Requirements - -### Requirement: A prerelease version SHALL never be published to the latest dist-tag - -There is no prerelease channel. If a version carrying a prerelease suffix is ever produced, publication SHALL route it to the `beta` npm dist-tag rather than `latest`, so that a preview build can never displace the current stable release for ordinary installs. - -This is a fail-safe rather than a feature: nothing in the repository is expected to produce such a version. It is stated so the version-to-dist-tag derivation in the release identity contract is not removed later as unreachable code. - -#### Scenario: Stable release publishes to latest - -- **WHEN** a release commit for a version without a prerelease suffix is published -- **THEN** publication MUST use the `latest` npm dist-tag - -#### Scenario: A prerelease version is published defensively - -- **WHEN** a version carrying a prerelease suffix reaches publication -- **THEN** publication MUST use the `beta` npm dist-tag -- **AND** it MUST NOT be published to `latest` diff --git a/openspec/changes/archive/2026-08-06-retire-prerelease-channel/tasks.md b/openspec/changes/archive/2026-08-06-retire-prerelease-channel/tasks.md deleted file mode 100644 index d98254f7..00000000 --- a/openspec/changes/archive/2026-08-06-retire-prerelease-channel/tasks.md +++ /dev/null @@ -1,28 +0,0 @@ -# Tasks - -## 1. Remove the prerelease channel from the contract - -- [x] Write the `release-workflow` delta removing the prerelease requirement, with the reason and the evidence that disproved it -- [x] Retain the version-to-dist-tag mapping as an explicit fail-safe requirement so it is not later deleted as unreachable code -- [x] Leave `openspec/specs/` untouched; the delta applies during archive closure, so the removal is not applied twice - -## 2. Docs - -- [x] Drop the `Prereleases` section from `docs/releases.md` -- [x] Confirm no other doc still describes cutting a preview build - -## 3. Confirm no code change is needed - -- [x] `scripts/release/release-seal-contract.ts` keeps deriving the dist-tag from the version shape; that is the retained fail-safe -- [x] `scripts/ci/release-pr-policy.ts` keeps accepting a prerelease title shape, which stays harmless with nothing producing one - -## 4. Validation and delivery - -- [x] `bun run lint`, `bun run format:check`, `bun run typecheck` -- [x] `bun run test` -- [x] `bun run openspec:validate`, `bun run memory:check` -- [x] Commit, push, PR with a `pr:body:check`-validated body (#598, merged) - -## 5. Maintainer action, outside this change - -- [x] `npm dist-tag rm quantex-cli beta` — done by the maintainer; `dist-tags` is now `{ latest: 1.8.7 }` and `@beta` resolves to nothing diff --git a/openspec/changes/archive/2026-08-06-sync-docs-with-current-contract/.openspec.yaml b/openspec/changes/archive/2026-08-06-sync-docs-with-current-contract/.openspec.yaml deleted file mode 100644 index 84cfc124..00000000 --- a/openspec/changes/archive/2026-08-06-sync-docs-with-current-contract/.openspec.yaml +++ /dev/null @@ -1,2 +0,0 @@ -schema: spec-driven -created: 2026-08-06 diff --git a/openspec/changes/archive/2026-08-06-sync-docs-with-current-contract/design.md b/openspec/changes/archive/2026-08-06-sync-docs-with-current-contract/design.md deleted file mode 100644 index 2ed3d22d..00000000 --- a/openspec/changes/archive/2026-08-06-sync-docs-with-current-contract/design.md +++ /dev/null @@ -1,50 +0,0 @@ -## Context - -`origin/main` is now at v1.8.8. The repository release contract has one maintained line, `main`; the former beta branch and npm `beta` dist-tag are retired. The CLI still exposes a `beta` self-upgrade selector for an explicitly published prerelease, so documentation must distinguish that compatibility surface from the repository's normal release process. - -The latest uninstall fix also makes an important ownership boundary observable: when the managed provider package is conclusively gone but a different executable remains on `PATH`, Quantex clears its managed receipt and reports a conflicting source instead of restoring stale managed state. The behavior is already implemented and covered by the active uninstall change; this change supplies the missing user-facing recovery guidance. - -## Goals / Non-Goals - -**Goals:** - -- Make current release and branch guidance say `main` only, with the defensive prerelease-to-`beta` mapping clearly labeled as a fail-safe. -- Make README upgrade examples and configuration language accurate without removing the existing CLI `beta` selector. -- Explain managed uninstall ownership and residual `PATH` recovery in both product languages and the troubleshooting runbook. -- Keep current OpenSpec contracts, runtime instructions, and project-memory statements internally consistent. - -**Non-Goals:** - -- Do not change release workflows, npm dist-tags, CLI flags, uninstall logic, state schema, or provider behavior. -- Do not rewrite historical ADRs or past session evidence; only correct a session's current-status follow-up where it now claims a still-open maintainer action. -- Do not add a new preview-release mechanism or turn Quantex into a workflow orchestration platform. - -## Decisions - -1. **Use current contracts as the source of truth.** Update current OpenSpec specs, the central runtime, and active runbooks; leave superseded ADR decisions intact as historical records. This avoids erasing why the beta design was retired while preventing agents from following it as current policy. - -2. **Retain but qualify the self-upgrade selector.** The source and compatibility surface still accept `qtx upgrade --channel beta`, so the README will not claim that the flag was removed. It will say that stable is the normal line and beta is only an explicit selector for a prerelease that actually exists; no beta release is maintained by this repository. - -3. **Document ownership, not implementation details.** The README and troubleshooting runbook will state that Quantex removes tracked managed packages, does not delete an independently owned `PATH` executable, and reports the residual as a conflicting source when the managed package is gone. Recovery points users to `inspect`/`resolve` and the owner of the remaining executable. - -4. **Avoid hardcoding a version in onboarding docs.** The live npm registry was checked as part of the audit and currently reports only `latest: 1.8.8`; docs will describe the stable/latest relationship rather than embedding `1.8.8`, so the next release does not immediately make README text stale. - -5. **Keep the release identity fail-safe comment aligned.** The release-seal comment will describe the beta mapping as defensive publication routing, matching the current release spec, without changing executable code. - -## Risks / Trade-offs - -- [Risk] A future maintainer may reintroduce a beta branch without updating all current docs → keep branch scope in release, CI, and project-memory specs and validate OpenSpec/memory checks together. -- [Risk] Users may interpret the retained beta selector as a guaranteed available release → explicitly state that no beta channel is maintained and that the selector can have no matching release. -- [Risk] A residual executable may still be mistaken for a failed managed uninstall → document the distinct `conflicting-source` case and the `inspect`/`resolve` diagnostic path. -- [Trade-off] Historical ADRs will still contain old beta wording → label the audit scope and preserve them as historical decisions rather than editing archaeology. - -## Migration Plan - -1. Add the proposal, design, delta specs, and task list. -2. Update current README, runbook, runtime, spec, session, and release-comment text. -3. Run formatting, lint, typecheck, tests, OpenSpec validation, and project-memory checks. -4. Commit and push the documentation change from its dedicated branch; no runtime migration or rollback is required. Reverting the commit restores the previous wording without changing user state. - -## Open Questions - -None. The CLI behavior and current registry state are known; this change only aligns the written contracts with them. diff --git a/openspec/changes/archive/2026-08-06-sync-docs-with-current-contract/proposal.md b/openspec/changes/archive/2026-08-06-sync-docs-with-current-contract/proposal.md deleted file mode 100644 index 1b5c113a..00000000 --- a/openspec/changes/archive/2026-08-06-sync-docs-with-current-contract/proposal.md +++ /dev/null @@ -1,31 +0,0 @@ -## Why - -The latest `main` source is v1.8.8 and has retired the beta release branch and npm dist-tag while tightening uninstall reconciliation. Several current README, runtime, runbook, and OpenSpec passages still describe beta as a maintained release path or do not explain why a residual `PATH` copy can remain after a managed uninstall, so users and agents can follow outdated guidance. - -## What Changes - -- Align current release, CI, project-memory, runtime, and worktree documentation with `main` as the only maintained release line. -- Keep the CLI's existing `--channel beta` self-upgrade selector documented as a compatibility/explicit-preview selector, without presenting it as a repository release channel. -- Add English and Simplified Chinese README guidance explaining that uninstall removes Quantex-tracked managed installs and does not remove separately owned `PATH` copies. -- Add troubleshooting guidance for the `conflicting-source` uninstall result caused by a residual `PATH` executable after conclusive managed-package removal. -- Correct the current release spec and audit session's retired npm `beta` dist-tag status; preserve historical ADR wording as historical record. -- Update stale `beta` branch references in current CI, runtime, project-memory, release, and worktree guidance. - -## Capabilities - -### New Capabilities - -None. - -### Modified Capabilities - -- `product-readme`: document the retired release channel distinction and managed-uninstall ownership boundary. -- `release-workflow`: align the current protected-branch contract with the retired beta branch and dist-tag state. -- `code-quality-tooling`: scope current CI gate requirements to the only maintained release branch, `main`. -- `project-memory`: keep archive-closure guidance aligned with the current protected-branch model. - -## Impact - -This is a documentation and contract-alignment change across README files, current runbooks, the central contributor runtime, current OpenSpec specifications, and one stale release-contract comment. It does not change CLI behavior, public APIs, dependencies, release automation, or uninstall implementation; it makes the already-shipped behavior and current release state explicit. - -Intake classification: OpenSpec required because the work changes product-facing documentation and durable release/project-memory contracts. diff --git a/openspec/changes/archive/2026-08-06-sync-docs-with-current-contract/specs/code-quality-tooling/spec.md b/openspec/changes/archive/2026-08-06-sync-docs-with-current-contract/specs/code-quality-tooling/spec.md deleted file mode 100644 index 00de88e1..00000000 --- a/openspec/changes/archive/2026-08-06-sync-docs-with-current-contract/specs/code-quality-tooling/spec.md +++ /dev/null @@ -1,50 +0,0 @@ -## MODIFIED Requirements - -### Requirement: CI lint and format gate - -CI workflows that gate merges to `main` (such as `ci.yml` and the manually dispatched `release.yml`) SHALL run both `bun run lint` and `bun run format:check`. CI MUST fail when either command exits non-zero. - -#### Scenario: Pull request CI runs lint and format checks - -- **WHEN** a pull request targets `main` -- **THEN** CI executes `bun run lint` -- **AND** CI executes `bun run format:check` -- **AND** the workflow status is `failure` if either command exits non-zero - -### Requirement: CI SHALL collect change context once through a shared script - -Merge-gating workflows SHALL collect changed-file and commit metadata through the shared `ci:context` script instead of inline `github-script` blocks, and downstream jobs SHALL consume the classification outputs rather than re-calling the GitHub API. - -#### Scenario: pull request context is computed once - -- **WHEN** a pull request targets `main` -- **THEN** the `classify` job computes changed files, commits, and pull request trust exactly once -- **AND** lint, governance, and test jobs consume those outputs through job dependencies -- **AND** no workflow duplicates the file- or commit-listing logic inline in YAML - -### Requirement: CI SHALL run on consolidated workflow entry points - -Lint, governance, and test jobs SHALL be defined in a consolidated `ci.yml` workflow. PR body validation SHALL run within `ci.yml` rather than a separate `pr-governance.yml` workflow. - -#### Scenario: single CI workflow for merge gates - -- **WHEN** a PR targets `main` -- **THEN** `ci.yml` MUST provide lint, test matrix, and PR governance validation jobs -- **AND** `pr-governance.yml` MUST NOT exist as a separate workflow - -### Requirement: Merge-gating CI scopes cross-platform execution by change impact - -The merge-gating CI workflow SHALL classify pull requests and protected-branch pushes as either product-impacting or process-only with the canonical repository taxonomy before deciding whether to run expensive cross-platform test jobs. Process-only changes MAY skip the protected-branch test matrix, but the workflow MUST still execute the required lint and format validation, MUST still publish the same required test job contexts expected by GitHub rulesets, and MUST still run a minimal build guard on Ubuntu. - -#### Scenario: Process-only pull request targets main - -- **WHEN** a pull request targeting `main` changes only workflow, documentation, OpenSpec, or release-process metadata -- **THEN** merge-gating CI executes the always-on validation jobs for the repository -- **AND** it runs `bun run build` on Ubuntu as a minimal execution guard -- **AND** the `test (ubuntu-latest)`, `test (macos-latest)`, and `test (windows-latest)` contexts are reported without running the full cross-platform test workload - -#### Scenario: Product-impacting pull request targets main - -- **WHEN** a pull request targeting `main` changes product-impacting files such as `src/**`, install surfaces, package metadata, or runtime scripts -- **THEN** merge-gating CI runs the required test jobs for Ubuntu, macOS, and Windows -- **AND** any failing platform context blocks merge through the existing ruleset diff --git a/openspec/changes/archive/2026-08-06-sync-docs-with-current-contract/specs/product-readme/spec.md b/openspec/changes/archive/2026-08-06-sync-docs-with-current-contract/specs/product-readme/spec.md deleted file mode 100644 index b7b11d5a..00000000 --- a/openspec/changes/archive/2026-08-06-sync-docs-with-current-contract/specs/product-readme/spec.md +++ /dev/null @@ -1,23 +0,0 @@ -## ADDED Requirements - -### Requirement: README distinguishes the maintained stable release line from self-upgrade selectors - -The English and Simplified Chinese product READMEs SHALL identify stable/`main` as the normal Quantex release line and SHALL NOT present a maintained beta release channel. If the READMEs mention `qtx upgrade --channel beta`, they MUST explain that it is an explicit compatibility selector for a prerelease that actually exists, not a repository release workflow. - -#### Scenario: User follows README upgrade guidance - -- **GIVEN** a user reads the upgrade examples in either product README -- **WHEN** the user chooses a normal Quantex self-upgrade -- **THEN** the documented default path targets the stable release line -- **AND** any beta selector example is clearly qualified as optional and not guaranteed to have a matching release - -### Requirement: README explains managed uninstall ownership and residual PATH copies - -The English and Simplified Chinese product READMEs SHALL explain that `uninstall` removes an install tracked by Quantex's recorded managed source, does not delete an independently owned executable that remains on `PATH`, and may report a conflicting-source failure after the managed package is conclusively removed but another copy remains. - -#### Scenario: User reviews the uninstall command - -- **GIVEN** a user reads the common command or lifecycle guidance -- **WHEN** the user runs `qtx uninstall <agent>` for an agent with another copy on `PATH` -- **THEN** the README explains that the other copy is not removed as Quantex-owned state -- **AND** it directs the user to inspect or resolve the executable and remove or manage the remaining copy through its actual owner diff --git a/openspec/changes/archive/2026-08-06-sync-docs-with-current-contract/specs/project-memory/spec.md b/openspec/changes/archive/2026-08-06-sync-docs-with-current-contract/specs/project-memory/spec.md deleted file mode 100644 index cd1552dc..00000000 --- a/openspec/changes/archive/2026-08-06-sync-docs-with-current-contract/specs/project-memory/spec.md +++ /dev/null @@ -1,19 +0,0 @@ -## MODIFIED Requirements - -### Requirement: Completed OpenSpec changes MUST reach archive closure - -When a non-trivial change is tracked in OpenSpec, the project SHALL treat implementation merge and archive closure as separate lifecycle moments, and SHALL close the change by archiving it after its accepted spec delta is synced. Archive closure SHALL be owned by the agent-driven delivery workflow instead of repository automation that automatically opens and merges archive PRs. - -#### Scenario: Completed change lands on the protected main branch - -- **WHEN** an OpenSpec-backed implementation PR merges to the protected `main` branch -- **THEN** the project keeps the merged code as implemented work -- **AND** an agent using the Quantex runtime follows up by syncing accepted spec deltas and archiving the completed change -- **AND** the agent reports whether archive closure is complete or still pending - -#### Scenario: Agent performs archive follow-up - -- **WHEN** an agent resumes archive closure for a completed OpenSpec change -- **THEN** it MUST run the relevant OpenSpec status and archive commands -- **AND** it MUST run `bun run openspec:validate` -- **AND** it MUST deliver the archive change through the normal commit, push, and PR path when protected branches prevent direct closure diff --git a/openspec/changes/archive/2026-08-06-sync-docs-with-current-contract/specs/release-workflow/spec.md b/openspec/changes/archive/2026-08-06-sync-docs-with-current-contract/specs/release-workflow/spec.md deleted file mode 100644 index aec60ed2..00000000 --- a/openspec/changes/archive/2026-08-06-sync-docs-with-current-contract/specs/release-workflow/spec.md +++ /dev/null @@ -1,13 +0,0 @@ -## MODIFIED Requirements - -### Requirement: Protected branches SHALL require aligned status check contexts - -The `main` protected branch SHALL require status check contexts that match the consolidated CI workflow job names and actually run on pull requests: `lint`, `governance`, `test (ubuntu-latest)`, `test (windows-latest)`, and `test (macos-latest)`. The `classify` job SHALL NOT be a required context. The `sandbox-tests` workflow SHALL remain advisory and SHALL NOT be a required context. - -There is no second protected release branch to mirror: `beta` ceased to be a release channel, and the prerelease-from-main requirement was removed after its release-please mechanism was disproved. The frozen `v1.8.2-beta` tag is registry state rather than repository state; the npm `beta` dist-tag was removed by a maintainer, so no preview dist-tag is currently maintained. - -#### Scenario: main branch protection matches CI job names - -- **WHEN** a maintainer inspects branch protection for `main` -- **THEN** the required contexts MUST be exactly the five consolidated CI job names -- **AND** `classify` and `sandbox-tests` MUST NOT appear among them diff --git a/openspec/changes/archive/2026-08-06-sync-docs-with-current-contract/tasks.md b/openspec/changes/archive/2026-08-06-sync-docs-with-current-contract/tasks.md deleted file mode 100644 index ee3e255f..00000000 --- a/openspec/changes/archive/2026-08-06-sync-docs-with-current-contract/tasks.md +++ /dev/null @@ -1,21 +0,0 @@ -## 1. OpenSpec contract - -- [x] 1.1 Create the proposal and design for current release/uninstall documentation alignment -- [x] 1.2 Add delta specs for product README, release workflow, code-quality tooling, and project-memory contracts - -## 2. Product-facing guidance - -- [x] 2.1 Update `README.md` and `README.zh-CN.md` with stable-line/beta-selector clarification -- [x] 2.2 Document managed uninstall ownership and residual `PATH` behavior in both product READMEs -- [x] 2.3 Add the `conflicting-source` residual-PATH recovery path to the troubleshooting runbook - -## 3. Current repository guidance - -- [x] 3.1 Remove stale beta-branch references from the central runtime, current CI/project-memory specs, and worktree/release runbooks -- [x] 3.2 Correct the current release spec, audit-session follow-up, and release-seal contract comment without rewriting historical ADRs - -## 4. Validation and handoff - -- [x] 4.1 Run `bun run lint`, `bun run format:check`, and `bun run typecheck` -- [x] 4.2 Run `bun run test`, `bun run openspec:validate`, and `bun run memory:check` -- [x] 4.3 Confirm the dedicated branch is based on `origin/main`, the primary `main` worktree remains clean and synchronized, and report commit/push/PR/archive closure states explicitly diff --git a/openspec/changes/archive/2026-08-07-fix-stderr-version-probe/.openspec.yaml b/openspec/changes/archive/2026-08-07-fix-stderr-version-probe/.openspec.yaml deleted file mode 100644 index 878dc315..00000000 --- a/openspec/changes/archive/2026-08-07-fix-stderr-version-probe/.openspec.yaml +++ /dev/null @@ -1,2 +0,0 @@ -schema: spec-driven -created: 2026-08-07 diff --git a/openspec/changes/archive/2026-08-07-fix-stderr-version-probe/design.md b/openspec/changes/archive/2026-08-07-fix-stderr-version-probe/design.md deleted file mode 100644 index acdad92b..00000000 --- a/openspec/changes/archive/2026-08-07-fix-stderr-version-probe/design.md +++ /dev/null @@ -1,54 +0,0 @@ -## Context - -Quantex has two installed-executable version probe paths. The shared utility path uses `readProcessOutput`/`readProcessOutputWithContext`, while the production core observation path uses `runReadOnlyCommand`. Both capture stdout and stderr, but both currently parse stdout only. A successful Pi probe can therefore return exit code 0 with the version only on stderr and be exposed as an unknown installed version. - -The fix crosses these two observation implementations but does not change the lifecycle evidence model: PATH executable evidence remains distinct from provider/package evidence, and existing version parser and exit-code semantics remain authoritative. - -## Goals / Non-Goals - -**Goals:** - -- Make successful version probes resilient to CLIs that emit their version on stderr. -- Preserve stdout as the preferred evidence when both streams are populated. -- Apply identical fallback semantics to the shared and core probe paths. -- Cover default parsing, custom parser fallback, stdout precedence, and non-zero exits with focused regression tests. - -**Non-Goals:** - -- Do not concatenate stdout and stderr, because warnings from one stream could contaminate the version value from the other. -- Do not change the parser's existing first-line and version-pattern behavior. -- Do not merge provider-observed package versions into PATH executable inspection. -- Do not add agent-specific catalog metadata or a managed package fallback. - -## Decisions - -1. **Parse stdout first, then stderr only when stdout returns no version.** - - This preserves the current behavior for agents that use stdout and supports stderr-only agents without changing the public version shape. - - Alternative: concatenate both streams. Rejected because diagnostics or warnings could become a false version or alter custom-parser input. - - Alternative: add a per-agent stream setting. Rejected because the failure is a valid generic probe behavior and would require unnecessary catalog schema/API surface. - -2. **Reuse the existing parser independently for each stream.** - - A custom parser receives one stream at a time, and returning `undefined` from the stdout attempt enables the stderr attempt. - - Alternative: introduce a new parser callback with both streams. Rejected because it breaks the existing probe contract and is unnecessary for the reported failure. - -3. **Keep non-zero exits authoritative.** - - A process that fails is not a successful version probe even if stderr happens to contain a version-like string. - - Alternative: parse stderr on failure. Rejected because it could convert error messages or partial output into installed-version evidence. - -4. **Test both implementations at their existing boundaries.** - - `getInstalledVersion` is covered through its existing mocked process tests, and core observation is covered through a temporary executable and `createProductionCoreReadPorts`. - - This proves the two code paths do not drift while avoiding changes to public APIs. - -## Risks / Trade-offs - -- [A CLI writes a warning as the only stdout line and a valid version to stderr] → The existing parser treats a non-empty first line as a value, so stdout remains authoritative; this preserves backward compatibility but may require an agent-specific parser if that CLI is encountered. -- [A custom parser is not safe for stderr input] → The existing callback contract is stream-text based and tests will require undefined stdout results to permit stderr fallback; catalog-specific parsers remain responsible for their accepted input. -- [A probe emits a version only on stderr with a non-zero exit] → The result remains unknown, preserving the success gate and avoiding false installed evidence. - -## Migration Plan - -No data migration or dependency change is required. Ship the code and focused tests with the implementation PR; existing state files and structured output fields remain compatible. Rollback is a code revert if a probe-specific parser depends on stdout-only invocation behavior. - -## Open Questions - -None for this change. Future stream-specific probe behavior can be introduced as a separate catalog contract if a CLI needs semantics beyond independent stdout/stderr parsing. diff --git a/openspec/changes/archive/2026-08-07-fix-stderr-version-probe/proposal.md b/openspec/changes/archive/2026-08-07-fix-stderr-version-probe/proposal.md deleted file mode 100644 index 75cf9370..00000000 --- a/openspec/changes/archive/2026-08-07-fix-stderr-version-probe/proposal.md +++ /dev/null @@ -1,38 +0,0 @@ -## Why - -Some supported agent CLIs, including Pi, report a successful version probe on stderr instead of stdout. Quantex currently treats an empty stdout stream as an unknown installed version, so `qtx list` and `qtx inspect` lose reliable version evidence even though the executable is installed and the probe succeeded. - -This is an observable CLI behavior change requested as a continuation of the investigated `qtx upgrade`/listing issue, so it passes the OpenSpec intake gate before implementation. - -## What Changes - -- Parse a successful version probe from stdout first. -- When stdout does not yield a version, parse stderr as an independent fallback. -- Preserve stdout precedence when both streams contain version-like output. -- Keep non-zero probe exits unsuccessful, and do not concatenate stdout and stderr before parsing. -- Apply the same fallback contract to the core observation path and the shared installed-version path. -- Add regression coverage for stderr-only output, stdout precedence, custom parsers, and non-zero exits. - -Non-goals: - -- Do not merge provider/package version evidence into PATH executable inspection. -- Do not add a Pi-specific probe or managed-package fallback. -- Do not change version comparison, install-source identity, update strategy, or structured output fields. - -## Capabilities - -### New Capabilities - -- `agent-version-probing`: define how successful installed-agent version probes select and parse stdout/stderr evidence. - -### Modified Capabilities - -- (none) - -## Impact - -- `src/utils/version.ts` shared installed-version probing -- `src/core/production-observation.ts` core PATH executable inspection -- `test/utils/version.test.ts` and `test/core/production-observation.test.ts` -- New version-probing OpenSpec capability and its implementation tasks -- No dependency, public schema, or state-file changes diff --git a/openspec/changes/archive/2026-08-07-fix-stderr-version-probe/specs/agent-version-probing/spec.md b/openspec/changes/archive/2026-08-07-fix-stderr-version-probe/specs/agent-version-probing/spec.md deleted file mode 100644 index 472c74ea..00000000 --- a/openspec/changes/archive/2026-08-07-fix-stderr-version-probe/specs/agent-version-probing/spec.md +++ /dev/null @@ -1,39 +0,0 @@ -## ADDED Requirements - -### Requirement: Successful installed-version probes parse stdout before stderr - -Quantex SHALL parse a successful installed-agent version probe from stdout first. When stdout does not produce a version, Quantex SHALL independently parse stderr as the fallback stream. - -#### Scenario: Version is emitted only on stderr - -- **WHEN** an installed agent version command exits with code 0, emits no parseable value on stdout, and emits a version on stderr -- **THEN** Quantex reports the version parsed from stderr - -#### Scenario: Version is emitted on stdout and stderr - -- **WHEN** an installed agent version command exits with code 0 and both stdout and stderr contain parseable values -- **THEN** Quantex reports the version parsed from stdout - -#### Scenario: A custom parser needs stderr fallback - -- **WHEN** a configured version parser returns no version for stdout and returns a version for stderr -- **THEN** Quantex invokes the parser independently for stderr and reports the stderr result - -### Requirement: Version probe failures do not become installed-version evidence - -Quantex MUST treat a non-zero version command exit as an unsuccessful probe and MUST NOT report a version from either output stream. - -#### Scenario: A failed command writes a version-like stderr message - -- **WHEN** an installed agent version command exits with a non-zero code and writes a version-like value to stderr -- **THEN** Quantex reports no installed version - -### Requirement: Version probe stream fallback preserves existing parser boundaries - -Quantex MUST pass stdout and stderr to the existing version parser independently and MUST NOT concatenate the streams before parsing. - -#### Scenario: Stderr contains diagnostics alongside a valid version - -- **WHEN** stdout does not produce a version and stderr contains the version output plus unrelated diagnostic lines -- **THEN** Quantex applies the existing first-line/parser semantics to stderr alone -- **AND** it does not prepend or append stdout content to the parser input diff --git a/openspec/changes/archive/2026-08-07-fix-stderr-version-probe/tasks.md b/openspec/changes/archive/2026-08-07-fix-stderr-version-probe/tasks.md deleted file mode 100644 index 4fc7ec60..00000000 --- a/openspec/changes/archive/2026-08-07-fix-stderr-version-probe/tasks.md +++ /dev/null @@ -1,21 +0,0 @@ -## 1. Version probe implementation - -- [x] 1.1 Update the shared installed-version probe to parse stdout first and independently fall back to stderr only when stdout produces no version. -- [x] 1.2 Update the production core executable probe with the same stdout-first/stderr-fallback behavior while preserving non-zero exit handling. - -## 2. Regression coverage - -- [x] 2.1 Extend shared version-probe process fixtures and tests for stderr-only output, stdout precedence, custom parser fallback, and non-zero exits. -- [x] 2.2 Add a production core observation regression for an executable that emits its version only on stderr. - -## 3. Validation and contract closure - -- [x] 3.1 Run `bun run openspec:validate` and confirm the change artifacts satisfy the agent-version-probing contract. -- [x] 3.2 Run `bun run lint`, `bun run format:check`, `bun run typecheck`, and `bun run test`. -- [x] 3.3 Review the final diff, update completed task checkboxes, and verify the worktree contains no unrelated changes. - -## 4. Repository and PR delivery - -- [x] 4.1 Commit the implementation and OpenSpec change on the dedicated `codex/fix-stderr-version-probe` branch. -- [x] 4.2 Push the branch and create a PR using the repository template plus `bun run pr:body:check`. -- [x] 4.3 Inspect the PR checks and report local implementation, repository delivery, PR delivery, merge delivery, release closure, and OpenSpec archive closure separately. diff --git a/openspec/changes/archive/2026-08-14-verify-install-scripts-release/.openspec.yaml b/openspec/changes/archive/2026-08-14-verify-install-scripts-release/.openspec.yaml deleted file mode 100644 index 4af86417..00000000 --- a/openspec/changes/archive/2026-08-14-verify-install-scripts-release/.openspec.yaml +++ /dev/null @@ -1,2 +0,0 @@ -schema: spec-driven -created: 2026-08-14 diff --git a/openspec/changes/archive/2026-08-14-verify-install-scripts-release/design.md b/openspec/changes/archive/2026-08-14-verify-install-scripts-release/design.md deleted file mode 100644 index 50128302..00000000 --- a/openspec/changes/archive/2026-08-14-verify-install-scripts-release/design.md +++ /dev/null @@ -1,64 +0,0 @@ -## Context - -The release candidate pipeline already builds compressed standalone archives, generates `manifest.json` and `SHA256SUMS.txt`, smoke-tests the current runner's archive, and verifies the uploaded GitHub Release assets. Those checks use the repository's release-artifact constants. The documented installers independently derive their archive names, so a constant or archive migration can leave the release pipeline green while a user-facing installer returns a 404. - -The installer check must therefore use the public download URLs of the exact release being published. It must cover the hosted Linux, macOS, and Windows environments, avoid touching a runner's normal user installation, and leave an actionable release status when a platform-specific check fails. - -## Goals / Non-Goals - -**Goals:** - -- Exercise the versioned `install.sh` and `install.ps1` files end to end against the exact public GitHub Release. -- Cover Linux and macOS with `install.sh`, and Windows with `install.ps1`. -- Verify the installed executable and its documented alias, including that the executable reports the expected release version. -- Make the overall release workflow fail when any installer leg fails and identify the failing installer and runner. -- Define a retry and remediation policy that does not move or delete an immutable published release. - -**Non-Goals:** - -- Changing either installer, the release asset matrix, archive formats, or native Windows ARM64 support. -- Replacing the existing local release-artifact smoke test or static installer tests. -- Testing arbitrary developer operating systems or third-party runner images beyond the hosted matrix. -- Adding a new repository-local workflow wrapper or runtime dependency. - -## Decisions - -### 1. Use a post-publish matrix job in `release.yml` - -The installer URLs intentionally target the public release download endpoint, so the check cannot run before the GitHub Release is made non-draft. A job that depends on the existing publish job keeps the check attached to the same release workflow and makes its result visible as part of release closure. A separate `release: published` workflow would be asynchronous and would not make the publication workflow itself fail; the existing local `release:smoke` command cannot exercise public URLs at all. - -The matrix runs with `fail-fast: false` so Linux, macOS, and Windows report independently when more than one platform is broken. - -### 2. Pin both the installer source and download target to the immutable tag - -Each matrix leg checks out the exact `v<version>` tag and sets `QUANTEX_REPO` and `QUANTEX_VERSION` to the same release identity. This verifies the installer that belongs to the release rather than `main` or whichever version is currently `latest`, and it makes a rerun deterministic. - -### 3. Use native runner shells and scratch paths - -The POSIX legs invoke `bash ./install.sh`; the Windows leg invokes `pwsh -File ./install.ps1`. No Bun setup or new dependency is needed for the installer check. `QUANTEX_INSTALL_DIR` points into `runner.temp`, and all post-install assertions use that path. The smoke commands run both the primary executable and the `qtx` alias and require the expected version in their output. - -### 4. Treat failure as a post-publish gate, not a rollback trigger - -The GitHub Release, tag, and npm publication remain intact if the matrix fails: deleting or moving an immutable release after users may have downloaded it is not a safe recovery mechanism. The workflow is nevertheless failed and the error names the installer and runner. Maintainers must inspect whether the failure is transient or a real compatibility defect, fix the source, and rerun `release.yml` at the same tag when the public assets are still valid. A real asset or installer mismatch requires normal corrective release work; it must not be hidden by retagging the existing version. - -### 5. Keep static regression coverage beside release workflow tests - -The workflow test will assert that the job depends on the public-release closure, covers all three hosted runner families, pins the repository and tag, uses a scratch directory, and invokes both installer files. This protects the contract without pretending that a Linux unit-test process can emulate macOS or Windows hosted runners. - -## Risks / Trade-offs - -- **[Public release is visible before the final check]** → Keep the post-publish failure policy explicit, fail the overall workflow, preserve the immutable release, and support a same-tag rerun after remediation. -- **[Hosted-runner networking or GitHub CDN transiently fails]** → Run all matrix legs independently, include the installer and runner in the error, and rerun the same tag before changing release content. -- **[Hosted macOS architecture changes]** → Use the standard `macos-latest` image and let the real installer resolve the platform architecture; the existing release matrix and installer failure message remain the source of evidence if no matching asset exists. -- **[The checked-out script and public assets drift in a future workflow change]** → Pin checkout to the release tag and keep the workflow wiring under regression tests; any drift is surfaced as a failed installer leg. - -## Migration Plan - -1. Merge the workflow, regression test, runbook, and OpenSpec change. -2. The next tag-triggered `release.yml` run will publish as before and then execute the three installer legs. -3. If a leg fails, preserve the tag and public release, inspect the named installer failure, and rerun the same release workflow only after deciding whether the failure was transient or needs a corrective change. -4. After the implementation is merged and accepted, sync the delta into `openspec/specs/release-workflow/spec.md` through the normal archive-closure flow. - -## Open Questions - -None. The required failure policy is the explicit post-publish, fail-the-workflow, no-retag policy above. diff --git a/openspec/changes/archive/2026-08-14-verify-install-scripts-release/proposal.md b/openspec/changes/archive/2026-08-14-verify-install-scripts-release/proposal.md deleted file mode 100644 index e51034b3..00000000 --- a/openspec/changes/archive/2026-08-14-verify-install-scripts-release/proposal.md +++ /dev/null @@ -1,32 +0,0 @@ -## Why - -Issue #645 exposed a release-verification blind spot: the published `install.sh` and `install.ps1` can request a different asset name from the one the release pipeline publishes, while local archive checks continue to pass. The release pipeline needs a real post-publication check that exercises the documented installers against the exact tagged GitHub Release before treating installer compatibility as closed. - -Work-intake classification: non-trivial release-process and durable behavior change, so this change requires an OpenSpec contract before implementation. - -## What Changes - -- Add a post-publish release job with Linux, macOS, and Windows matrix legs. -- Run the exact tagged `install.sh` on Linux and macOS and the exact tagged `install.ps1` on Windows against the just-published release, using an isolated installation directory. -- Verify that each installer creates its documented entry points and that the installed executable reports the release version. -- Make a failed installer leg fail the release workflow with the installer name visible in the failure, while retaining the already-public release and requiring remediation or a same-tag rerun rather than retagging. -- Add regression coverage for the workflow wiring and document the post-publish failure and recovery policy in the release runbook. - -The change does not alter installer behavior, release asset names, archive formats, supported build targets, or the existing static installer tests. - -## Capabilities - -### New Capabilities - -None. - -### Modified Capabilities - -- `release-workflow`: require end-to-end verification of the documented standalone installers against every published CLI release. - -## Impact - -- `.github/workflows/release.yml` gains a post-publish cross-platform installer smoke job. -- Release workflow regression tests will pin the matrix, exact release identity, scratch install path, and failure ordering. -- `docs/runbooks/releasing-quantex.md` will describe the new gate and same-tag recovery path. -- No new runtime or package dependency is required; the check uses the existing hosted runner shells and the checked-in installer scripts. diff --git a/openspec/changes/archive/2026-08-14-verify-install-scripts-release/specs/release-workflow/spec.md b/openspec/changes/archive/2026-08-14-verify-install-scripts-release/specs/release-workflow/spec.md deleted file mode 100644 index 328c3f79..00000000 --- a/openspec/changes/archive/2026-08-14-verify-install-scripts-release/specs/release-workflow/spec.md +++ /dev/null @@ -1,44 +0,0 @@ -# release-workflow Delta - -## ADDED Requirements - -### Requirement: Published releases MUST exercise the documented standalone installers - -After the release workflow makes the exact GitHub Release public, it SHALL run a non-cancelling matrix against that same immutable `v<version>` release. The matrix MUST run the versioned `install.sh` on at least one hosted Linux runner and one hosted macOS runner, and MUST run the versioned `install.ps1` on a hosted Windows runner. Each leg SHALL set the repository and release tag explicitly, install into an isolated scratch directory, and verify that the installed primary executable and documented alias run successfully and report the expected release version. - -#### Scenario: A published stable release exercises every documented installer - -- **WHEN** `release.yml` completes public GitHub Release closure for `v<version>` -- **THEN** it MUST run the release-tagged `install.sh` on Linux and macOS -- **AND** it MUST run the release-tagged `install.ps1` on Windows -- **AND** each installer MUST download from the exact `v<version>` release rather than an unpinned `latest` release - -#### Scenario: POSIX installer smoke succeeds - -- **GIVEN** the public release contains the platform archive and `SHA256SUMS.txt` -- **WHEN** a Linux or macOS matrix leg runs `install.sh` in its scratch directory -- **THEN** the installer MUST complete successfully -- **AND** both `quantex` and `qtx` in that directory MUST execute successfully -- **AND** their output MUST include the expected release version - -#### Scenario: Windows installer smoke succeeds - -- **GIVEN** the public release contains `quantex-windows-x64.exe.zip` and `SHA256SUMS.txt` -- **WHEN** the Windows matrix leg runs `install.ps1` in its scratch directory -- **THEN** the installer MUST complete successfully -- **AND** both `quantex.exe` and `qtx.exe` in that directory MUST execute successfully -- **AND** their output MUST include the expected release version - -#### Scenario: An installer cannot consume the published release - -- **WHEN** any installer matrix leg cannot download, verify, extract, or execute the exact release -- **THEN** that leg MUST fail the release workflow -- **AND** its failure MUST identify the installer and hosted runner that failed -- **AND** the other matrix legs MUST still be allowed to report their own result - -#### Scenario: Post-publish installer verification fails - -- **WHEN** the installer matrix fails after the GitHub Release, tag, or npm version is public -- **THEN** the release workflow MUST remain failed and report the release as not fully verified -- **AND** it MUST NOT delete, move, or retag the immutable release to hide the failure -- **AND** maintainers MUST be able to rerun the same tag after transient remediation or a corrective change diff --git a/openspec/changes/archive/2026-08-14-verify-install-scripts-release/tasks.md b/openspec/changes/archive/2026-08-14-verify-install-scripts-release/tasks.md deleted file mode 100644 index d115d36b..00000000 --- a/openspec/changes/archive/2026-08-14-verify-install-scripts-release/tasks.md +++ /dev/null @@ -1,23 +0,0 @@ -## 1. OpenSpec Contract - -- [x] 1.1 Record the Issue #645 motivation, scope, work-intake classification, and affected release-workflow capability in `proposal.md`. -- [x] 1.2 Record the post-publish matrix design, exact-tag pinning, scratch-directory isolation, and no-retag failure policy in `design.md`. -- [x] 1.3 Add the release-workflow delta requirements and scenarios for Linux, macOS, Windows, failure identification, and post-publish recovery. - -## 2. Release Workflow Implementation - -- [x] 2.1 Add a non-cancelling `release.yml` matrix job that depends on public GitHub Release closure and covers Ubuntu, macOS, and Windows hosted runners. -- [x] 2.2 Check out the immutable release tag and pass the exact repository, tag, and scratch installation directory to every installer leg. -- [x] 2.3 Invoke the real `install.sh` on POSIX runners and `install.ps1` on Windows, failing with the installer and runner name when installation, verification, extraction, or execution fails. -- [x] 2.4 Verify both documented entry points and the expected release version in every matrix leg without changing the installers or release asset matrix. - -## 3. Regression Coverage and Documentation - -- [x] 3.1 Add static regression assertions for the release workflow dependency, runner matrix, exact release identity, scratch path, installer commands, and failure ordering. -- [x] 3.2 Update `docs/runbooks/releasing-quantex.md` with the post-publish installer gate, failure interpretation, and same-tag recovery policy. - -## 4. Validation - -- [x] 4.1 Run `bun run openspec:validate` and `bun run memory:check` after the OpenSpec and runbook changes. -- [x] 4.2 Run `bun run lint`, `bun run format:check`, `bun run typecheck`, and `bun run test`. -- [x] 4.3 Review the final git diff and report local implementation, OpenSpec, commit, remote, PR, release, and archive-closure states separately. diff --git a/openspec/changes/archive/2026-08-15-remove-macos-desktop-client/.openspec.yaml b/openspec/changes/archive/2026-08-15-remove-macos-desktop-client/.openspec.yaml deleted file mode 100644 index 0c73c8f5..00000000 --- a/openspec/changes/archive/2026-08-15-remove-macos-desktop-client/.openspec.yaml +++ /dev/null @@ -1,2 +0,0 @@ -schema: spec-driven -created: 2026-08-15 diff --git a/openspec/changes/archive/2026-08-15-remove-macos-desktop-client/design.md b/openspec/changes/archive/2026-08-15-remove-macos-desktop-client/design.md deleted file mode 100644 index 7b23d1d6..00000000 --- a/openspec/changes/archive/2026-08-15-remove-macos-desktop-client/design.md +++ /dev/null @@ -1,52 +0,0 @@ -## Context - -`origin/main` 当前包含桌面客户端主体 PR #557、其 OpenSpec 归档 PR #647、外观模式 PR #649 和归档 PR #651。主体 PR 同时引入了 `apps/desktop`、桌面 sidecar 和 CI、workspace/依赖变更,以及仅由桌面端使用的 managed-only 更新 CLI 扩展;外观模式是建立在主体客户端上的增量。 - -目标是让 Quantex 回到单一 CLI 产品面,同时保留已发布提交的历史可追溯性。主分支受保护,因此实现必须从当前 `origin/main` 建立分支,通过 PR 合入,不能重写主分支历史或移动版本 tag。 - -## Goals / Non-Goals - -**Goals:** - -- 完整移除桌面客户端的源码、构建、测试、依赖、CI 和 package/release 入口。 -- 删除桌面专用的 managed-only 更新模式,恢复桌面特性之前的 CLI 行为和契约。 -- 通过显式 Revert 提交保留对 #557、#647、#649、#651 的历史关联。 -- 用 OpenSpec 记录产品边界收缩及后续 archive closure 所需的契约变化。 - -**Non-Goals:** - -- 不回退普通 CLI 生命周期能力、已有 `update --all` 语义或非桌面相关的更新修复。 -- 不删除 Git 历史、移动 tag、回滚 v1.10.0 release commit 或手工改写历史 changelog。 -- 不引入新的 GUI 替代方案,也不把 CLI 改造成 workflow orchestration platform。 - -## Decisions - -1. **按合入逆序回滚四个相关 PR。** 先回滚 #651、#649,再回滚 #647、#557,并对每个 merge commit 使用主线父节点作为主线基准。这样可以先撤掉外观模式和归档,再撤掉产生它们的实现与主体,最大限度复原桌面前状态。 - - 替代方案是手工挑选文件删除或回退整个 release commit;前者容易遗漏 CLI 契约和锁文件,后者会误伤无关发布内容,因此不采用。 - -2. **OpenSpec change 与 Revert 提交同 PR 交付。** 新 change 以 delta 形式记录桌面能力及三个受影响现有 capability 的移除,合并后按运行时规则执行 archive closure。 - - 替代方案是只删除源码、不记录契约变化;这会留下过时的产品边界和 OpenSpec 依据,因此不采用。 - -3. **保留历史发布记录。** 不从 `CHANGELOG.md` 删除已经发生的 v1.10.0 条目,也不移动 tag;回滚行为交给后续 release automation 生成新的 release 记录。 - -## Risks / Trade-offs - -- [Revert 上下文冲突] 后续提交可能修改了桌面特性触及的共享文件 → 先核对四个 merge commit 的文件差异和后续路径历史;如有冲突只保留非桌面 CLI 变更,并用测试确认。 -- [误删 CLI 更新能力] 主体 PR 同时改动了 `update` → 对比桌面前父提交,保留普通单 agent/全量更新和现有生命周期逻辑,运行 CLI test 与结构化契约测试。 -- [锁文件残留桌面依赖] 只回退源码而不回退 workspace lock 会继续扩大安装面 → 以 `package.json`、`bun.lock`、workspace 校验和 `rg` 交叉检查,并使用 frozen install 验证。 -- [归档后 spec 漂移] 删除归档产物可能让当前规格与实现不一致 → 在 PR 中保留 removal change,合并后执行 OpenSpec archive closure,不保留已不存在能力的当前 spec。 - -## Migration Plan - -1. 从 `origin/main` 创建 `codex/revert-desktop-ui`。 -2. 生成 removal OpenSpec artifacts。 -3. 按 #651、#649、#647、#557 的顺序生成 Revert 提交,并审查最终 diff。 -4. 运行 lint、format check、typecheck、test、OpenSpec 和 memory 校验。 -5. 提交、推送并创建 PR;等待受保护分支 CI 通过后按仓库策略合入。 -6. 合并后从干净主线执行 OpenSpec archive closure,并确认没有桌面源码、构建入口或现行 capability 残留。 - -## Open Questions - -无。桌面 UI 的后续产品方向不在本次回滚范围内;如果未来重新提出,应作为新的产品决策和 OpenSpec change 评估。 diff --git a/openspec/changes/archive/2026-08-15-remove-macos-desktop-client/proposal.md b/openspec/changes/archive/2026-08-15-remove-macos-desktop-client/proposal.md deleted file mode 100644 index bdd55c35..00000000 --- a/openspec/changes/archive/2026-08-15-remove-macos-desktop-client/proposal.md +++ /dev/null @@ -1,34 +0,0 @@ -## Why - -Quantex 的核心产品边界是轻量的 agent lifecycle CLI;已合入的 macOS 桌面客户端引入了第二套 UI、构建发布链路和仅供桌面端使用的 CLI 扩展。现在移除这条产品线,可以恢复 CLI 的单一交付面,降低依赖、维护和发布复杂度。 - -本请求属于 observable behavior 和产品边界变更,因此按 OpenSpec intake gate 建立本 change 后实施。 - -## What Changes - -- **BREAKING** 移除 macOS Tauri/React 桌面客户端及其界面、原生宿主、测试、构建和开发入口。 -- **BREAKING** 移除仅由桌面客户端消费的 managed-only 批量更新发现模式和 `--managed` 结构化契约。 -- 移除桌面 sidecar 准备、桌面 workspace、桌面专用依赖、CI/macOS 打包检查和相关 npm workspace 放行规则。 -- 恢复桌面特性合入前的 `agent-update`、`cli-contract-registry` 和 `package-distribution` 契约。 -- 保留 CLI 现有的单 agent 更新、普通 `update --all`、安装、检查、确保、卸载、执行、自升级和结构化输出能力。 - -## Capabilities - -### New Capabilities - -None. - -### Modified Capabilities - -- `macos-desktop-client`: 移除整个 macOS 桌面客户端能力及其所有行为要求。 -- `agent-update`: 移除仅供桌面端使用的 managed-only 批量发现要求,保留普通批量更新。 -- `cli-contract-registry`: 移除 `update --managed` 选项和 `data.scope: "managed"` 契约。 -- `package-distribution`: 移除桌面 sidecar 打包和桌面私有 workspace 的发布契约。 - -## Impact - -- 删除 `apps/desktop` 及其 Tauri/Rust、React、mock 和测试文件。 -- 恢复根 `package.json`、`bun.lock`、TypeScript/lint/format 配置、CI workflow、release/package 校验和 sidecar 脚本。 -- 恢复 `src/command-contract`、`src/commands/update.ts`、生命周期更新服务及其测试/fixture。 -- 清理桌面 OpenSpec active/archive 产物;本 change 本身保留为合并后 archive closure 的依据。 -- 不回退 v1.10.0 或其他后续 release commit;下一次版本由正常 release automation 记录此 breaking removal。 diff --git a/openspec/changes/archive/2026-08-15-remove-macos-desktop-client/specs/agent-update/spec.md b/openspec/changes/archive/2026-08-15-remove-macos-desktop-client/specs/agent-update/spec.md deleted file mode 100644 index dd3ede3e..00000000 --- a/openspec/changes/archive/2026-08-15-remove-macos-desktop-client/specs/agent-update/spec.md +++ /dev/null @@ -1,6 +0,0 @@ -## REMOVED Requirements - -### Requirement: Managed-only batch update discovery MUST use recorded agent state - -**Reason**: The managed-only batch scope was introduced solely for the removed Desktop background update client. -**Migration**: Use the existing `quantex update --all` behavior, which retains its normal catalog-wide contract and recorded install-source planning. diff --git a/openspec/changes/archive/2026-08-15-remove-macos-desktop-client/specs/cli-contract-registry/spec.md b/openspec/changes/archive/2026-08-15-remove-macos-desktop-client/specs/cli-contract-registry/spec.md deleted file mode 100644 index f1511c87..00000000 --- a/openspec/changes/archive/2026-08-15-remove-macos-desktop-client/specs/cli-contract-registry/spec.md +++ /dev/null @@ -1,6 +0,0 @@ -## REMOVED Requirements - -### Requirement: Update discovery MUST describe the managed batch scope - -**Reason**: The `--managed` option and managed structured scope were Desktop-only contract extensions. -**Migration**: Consumers MUST use the existing `update` command contract and its `all` or `single` result scopes. diff --git a/openspec/changes/archive/2026-08-15-remove-macos-desktop-client/specs/macos-desktop-client/spec.md b/openspec/changes/archive/2026-08-15-remove-macos-desktop-client/specs/macos-desktop-client/spec.md deleted file mode 100644 index f848f247..00000000 --- a/openspec/changes/archive/2026-08-15-remove-macos-desktop-client/specs/macos-desktop-client/spec.md +++ /dev/null @@ -1,41 +0,0 @@ -## REMOVED Requirements - -### Requirement: Desktop client MUST use the bundled CLI as its lifecycle boundary - -**Reason**: The macOS desktop client is being removed from Quantex. -**Migration**: Use the Quantex CLI directly for lifecycle operations. - -### Requirement: Desktop updates MUST require explicit user confirmation - -**Reason**: The desktop update surface no longer exists. -**Migration**: Use explicit CLI update commands and the existing CLI confirmation/automation contract. - -### Requirement: Desktop MUST cover the primary agent lifecycle - -**Reason**: Agent lifecycle management remains a CLI responsibility rather than a desktop UI responsibility. -**Migration**: Use the existing `install`, `ensure`, `update`, `uninstall`, `list`, `info`, and `exec` commands. - -### Requirement: Desktop MUST expose diagnostics and Quantex configuration - -**Reason**: The desktop diagnostics and settings surfaces are removed with the client. -**Migration**: Use the existing CLI diagnostics, capabilities, and configuration commands. - -### Requirement: Desktop background operation MUST remain lightweight and user-controlled - -**Reason**: No resident desktop host or background desktop update check remains. -**Migration**: Invoke CLI commands explicitly when lifecycle work is needed. - -### Requirement: Browser UI development MUST use deterministic mock data - -**Reason**: The browser-only Desktop workspace is removed. -**Migration**: Validate CLI behavior through the repository CLI tests and structured output contracts. - -### Requirement: Desktop MUST keep self-upgrade and developer contracts out of scope - -**Reason**: There is no longer a Desktop surface whose scope needs to exclude these commands. -**Migration**: The CLI remains the sole surface for its existing self-upgrade, commands, and schema contracts. - -### Requirement: Desktop MUST provide system, light, and dark appearance modes - -**Reason**: Appearance preferences belong to the removed desktop client. -**Migration**: No desktop appearance preference is persisted or exposed by Quantex. diff --git a/openspec/changes/archive/2026-08-15-remove-macos-desktop-client/specs/package-distribution/spec.md b/openspec/changes/archive/2026-08-15-remove-macos-desktop-client/specs/package-distribution/spec.md deleted file mode 100644 index e2005a31..00000000 --- a/openspec/changes/archive/2026-08-15-remove-macos-desktop-client/specs/package-distribution/spec.md +++ /dev/null @@ -1,11 +0,0 @@ -## REMOVED Requirements - -### Requirement: Desktop bundles MUST consume architecture-matched release sidecars - -**Reason**: Quantex will no longer build or distribute a Desktop bundle. -**Migration**: Consume the published CLI package or standalone CLI release artifacts through their existing CLI distribution contracts. - -### Requirement: The private Desktop workspace MUST coexist with the private Core workspace - -**Reason**: The `apps/desktop` workspace is removed. -**Migration**: The root workspace retains only the existing CLI/Core package distribution rules. diff --git a/openspec/changes/archive/2026-08-15-remove-macos-desktop-client/tasks.md b/openspec/changes/archive/2026-08-15-remove-macos-desktop-client/tasks.md deleted file mode 100644 index 535c399f..00000000 --- a/openspec/changes/archive/2026-08-15-remove-macos-desktop-client/tasks.md +++ /dev/null @@ -1,21 +0,0 @@ -## 1. OpenSpec and rollback preparation - -- [x] 1.1 Record the removal proposal, design, delta specs, and delivery checklist in `remove-macos-desktop-client` -- [x] 1.2 Confirm the rollback targets are merged PRs #557, #647, #649, and #651 and that unrelated release commits remain out of scope - -## 2. Product and source rollback - -- [x] 2.1 Revert merged PR #651 and remove the archived appearance-mode OpenSpec artifacts -- [x] 2.2 Revert merged PR #649 and remove the Desktop appearance-mode implementation -- [x] 2.3 Revert merged PR #647 and remove the archived macOS Desktop OpenSpec artifacts -- [x] 2.4 Revert merged PR #557 and remove the Desktop app, sidecar pipeline, Desktop workspace, and Desktop-only CLI extensions -- [x] 2.5 Verify ordinary CLI lifecycle commands and non-Desktop update contracts remain present - -## 3. Validation and delivery - -- [x] 3.1 Confirm no active source, package, workflow, test, or release entry still exposes the removed Desktop product -- [x] 3.2 Run `bun run lint`, `bun run format:check`, `bun run typecheck`, and `bun run test` -- [x] 3.3 Run `bun run openspec:validate` and `bun run memory:check` -- [x] 3.4 Commit the explicit Revert changes and OpenSpec removal change on the dedicated branch -- [x] 3.5 Push the branch, validate the PR body, and open the rollback PR against protected `main` -- [x] 3.6 Review remote CI and report PR, merge, release, and archive-closure state separately diff --git a/openspec/changes/archive/2026-08-16-validate-lifecycle-receipt-contract/.openspec.yaml b/openspec/changes/archive/2026-08-16-validate-lifecycle-receipt-contract/.openspec.yaml deleted file mode 100644 index 0c73c8f5..00000000 --- a/openspec/changes/archive/2026-08-16-validate-lifecycle-receipt-contract/.openspec.yaml +++ /dev/null @@ -1,2 +0,0 @@ -schema: spec-driven -created: 2026-08-15 diff --git a/openspec/changes/archive/2026-08-16-validate-lifecycle-receipt-contract/design.md b/openspec/changes/archive/2026-08-16-validate-lifecycle-receipt-contract/design.md deleted file mode 100644 index ac81b8ee..00000000 --- a/openspec/changes/archive/2026-08-16-validate-lifecycle-receipt-contract/design.md +++ /dev/null @@ -1,57 +0,0 @@ -## Context - -The lifecycle smoke currently installs a selected real agent and immediately calls `qtx update`. For a package-provider agent, the freshly installed package is already at the registry's latest version, so `decideUpdate` returns `up-to-date` and `src/services/lifecycle-updates.ts` never persists the receipt produced after a managed update. PR #632 exposed that the install writers and update writer intentionally persist different executable-name shapes, while uninstall must accept both shapes. - -The validation must stay inside Quantex's lifecycle scope, remain disposable in CI, and avoid making the canary depend on a hard-coded historical package version that may disappear from a registry. - -## Goals / Non-Goals - -**Goals:** - -- Make the real-agent canary reach a managed-provider `upgrade` outcome and persist the update receipt before uninstall. -- Make a deterministic unit/contract test cover the actual legacy install, Core install, and update receipt construction paths for every first-party provider type. -- Keep the existing fallback-aware reader as the compatibility boundary; the change must detect regressions rather than normalize persisted shapes. - -**Non-Goals:** - -- Do not change receipt writers to emit a uniform executable-name field. -- Do not change `conflicting-source`, `UNINSTALL_FAILED`, or any CLI schema/error contract. -- Do not widen the legacy/Core differential gate to update or uninstall. -- Do not add a new external dependency or a new root-level workflow wrapper. - -## Decisions - -### Use `opencode` as the real-upgrade canary anchor - -The quick matrix already includes `opencode`, its Linux Bun candidate is the selected provider, and its package declares an installed-version probe. The smoke path therefore runs on pull requests as well as full scheduled/manual canaries. The scenario is guarded by both the agent name and selected provider so it cannot silently claim coverage for a different source. - -### Resolve the seed version from npm metadata at runtime - -The smoke fetches the package metadata from the official npm registry, selects the highest valid stable SemVer lower than the current `latest`, and installs that exact version with Bun. This avoids pinning a version that upstream may remove while still guaranteeing that the following update has a lower installed version. A missing/invalid predecessor is a canary failure, not a skip. - -### Keep the provider registry path real - -The seed is installed through the same Bun global environment used by the canary, then `qtx install opencode` adopts the existing package. The smoke runs `qtx update --refresh`, asserts the result is `updated`, reads the state receipt, and invokes `qtx uninstall`. It does not mock provider commands or replace the registry with a local fake, so reverting the uninstall fallback makes the canary fail at the actual user-facing boundary. - -### Test each production writer through its existing composition - -The contract test captures a receipt from `reconcileAgentInstallation` for the legacy install path, from `createProductionCoreInstallationPorts().prepareRecord` for the Core install path, and from `executeSingleAgentLifecycleUpdate` for the update path. For each provider in `firstPartyProviderIds`, it resolves the installed-state and receipt bindings and asserts the uninstall comparator accepts them with the agent's declared default executable name. The test also checks persisted-binding reconstruction so the same evidence remains usable by lifecycle observation/update readers. - -### Keep provider fixtures explicit - -The test matrix supplies provider-appropriate target kinds, package arguments, commands, and executable names. It does not derive the expected result from the reader itself; each writer's persisted receipt is captured first, then fed into the reader. This keeps a removed fallback or a writer drift observable. - -## Risks / Trade-offs - -- [Risk] The selected package may have no valid older stable release or the registry may be unavailable. → Fail the advisory canary with the package and registry reason; do not convert missing upgrade evidence into a passing no-op. -- [Risk] Directly seeding a global package could leave an artifact if the later Quantex operation fails. → Run inside the disposable canary HOME/`BUN_INSTALL` and retain the existing in-flight cleanup stack; the hosted runner is destroyed after the job. -- [Risk] A provider-specific receipt shape can be added later without the test matrix being updated. → Drive the matrix from `firstPartyProviderIds` and assert that every provider has an explicit fixture. -- [Risk] The contract test can become coupled to unrelated provider mutation behavior. → Capture receipts at the writer boundaries with injected observation/mutation ports; do not execute real external provider commands in the unit suite. - -## Migration Plan - -No persisted-data migration is required. Land the smoke and contract test with the OpenSpec delta, run the local validation suite, then rely on the advisory canary to exercise the real upgrade. Rollback is a source revert; existing receipts remain readable because the runtime uninstall behavior is unchanged. - -## Open Questions - -None for this change. A broader update/uninstall legacy/Core differential gate remains a separate follow-up as stated by issue #633. diff --git a/openspec/changes/archive/2026-08-16-validate-lifecycle-receipt-contract/proposal.md b/openspec/changes/archive/2026-08-16-validate-lifecycle-receipt-contract/proposal.md deleted file mode 100644 index 55f4cd0a..00000000 --- a/openspec/changes/archive/2026-08-16-validate-lifecycle-receipt-contract/proposal.md +++ /dev/null @@ -1,30 +0,0 @@ -## Why - -PR #632 fixed a real `qtx uninstall` failure caused by an update-written lifecycle receipt carrying the agent's default executable name while package-provider state omitted it. The existing canary appears to cover `install -> update -> uninstall`, but the install is already at the registry latest version, so update is always a no-op and never exercises the receipt-writing branch. - -## What Changes - -- Add a focused real-agent canary path for the `opencode` Bun package provider that seeds the highest available stable version below `latest`, adopts it through Quantex, performs a real `qtx update --refresh`, verifies that update wrote the executable-bearing lifecycle receipt, and lets the following uninstall consume that receipt. -- Add one lifecycle-receipt contract test that exercises the legacy install writer, Core install writer, and update writer across every first-party provider type, then validates each persisted receipt through the provider-binding readers and default-executable reconciliation used by uninstall. -- Record the real-upgrade and writer/reader contract requirements in the existing `agent-canary-validation` OpenSpec capability. - -No CLI schema, persisted receipt format, provider classification, or uninstall error contract changes. - -## Capabilities - -### New Capabilities - -None. - -### Modified Capabilities - -- `agent-canary-validation`: require a real provider upgrade in update coverage and a cross-writer lifecycle-receipt contract gate. - -## Impact - -- Affected source: `scripts/smoke/lifecycle-smoke.ts`. -- Affected tests: lifecycle receipt/provider-binding contract coverage and static smoke scenario assertions. -- Affected durable artifact: `openspec/specs/agent-canary-validation/spec.md` through the change delta. -- Runtime dependencies remain unchanged; the canary uses the existing npm registry and Bun toolchain already required by the selected provider. - -Work-intake classification: non-trivial validation workflow and durable canary contract change; OpenSpec is required before implementation. diff --git a/openspec/changes/archive/2026-08-16-validate-lifecycle-receipt-contract/specs/agent-canary-validation/spec.md b/openspec/changes/archive/2026-08-16-validate-lifecycle-receipt-contract/specs/agent-canary-validation/spec.md deleted file mode 100644 index 896ef121..00000000 --- a/openspec/changes/archive/2026-08-16-validate-lifecycle-receipt-contract/specs/agent-canary-validation/spec.md +++ /dev/null @@ -1,42 +0,0 @@ -## ADDED Requirements - -### Requirement: Real package-provider update coverage MUST exercise a receipt-writing upgrade - -The real-agent lifecycle smoke MUST include a disposable package-provider scenario that seeds a selected smoke agent at a valid stable version lower than the registry's current `latest`, adopts that installation through Quantex, and runs `qtx update` with refreshed version metadata. The scenario MUST require an `updated` result, verify that the update-written lifecycle receipt is present, and pass that receipt directly into the following `qtx uninstall` operation. A missing predecessor version, unavailable registry, no-op update, or failed receipt-consuming uninstall MUST fail the canary rather than be reported as skipped coverage. - -#### Scenario: Quick canary reaches the managed update receipt branch - -- **GIVEN** the quick matrix selects the `opencode` Bun package provider in a fresh disposable HOME -- **WHEN** the lifecycle probe resolves a stable package version below the current registry `latest`, installs that version, and asks Quantex to adopt it -- **THEN** `qtx update` MUST report an actual `updated` result after refreshing version metadata -- **AND** the persisted lifecycle receipt MUST contain the agent's executable name -- **AND** the subsequent `qtx uninstall opencode` MUST succeed and remove the installation - -#### Scenario: Upgrade evidence cannot be downgraded to a no-op pass - -- **GIVEN** the selected package has no valid lower stable SemVer or its registry metadata cannot be read -- **WHEN** the real-upgrade scenario prepares its seeded installation -- **THEN** the canary MUST fail with the package/registry reason -- **AND** it MUST NOT claim successful lifecycle coverage from an `up-to-date` result - -### Requirement: Lifecycle receipt writers MUST remain compatible with uninstall readers for every provider type - -The repository contract suite MUST capture the receipt emitted by each lifecycle receipt writer—the legacy install engine, the Core install engine, and the managed update path—for every provider in the first-party provider registry. For each captured receipt, the suite MUST resolve the corresponding installed-state and receipt bindings and assert that the uninstall reconciliation comparator accepts matching provider, target identity, target kind, and the agent's default executable name. The suite MUST continue to reject a genuinely different executable name as a source conflict. - -#### Scenario: Package-provider install and update shapes reconcile - -- **GIVEN** a package-provider installed state omits its default executable name -- **WHEN** a legacy/Core install writer emits a receipt without that optional field and the update writer emits a receipt that includes it -- **THEN** both receipts MUST be accepted by the uninstall reader for the same provider target - -#### Scenario: Explicit executable providers remain covered - -- **GIVEN** a deno, script, or binary provider state records an explicit executable identity -- **WHEN** each install and update writer emits its receipt -- **THEN** the receipt MUST reconcile with the installed-state binding without losing the explicit executable identity - -#### Scenario: A genuinely different executable remains a conflict - -- **GIVEN** a receipt names an executable different from the agent's declared default and the installed-state binding -- **WHEN** the uninstall reader compares the two bindings -- **THEN** the contract test MUST fail that comparison as a conflicting source diff --git a/openspec/changes/archive/2026-08-16-validate-lifecycle-receipt-contract/tasks.md b/openspec/changes/archive/2026-08-16-validate-lifecycle-receipt-contract/tasks.md deleted file mode 100644 index 1a58fca6..00000000 --- a/openspec/changes/archive/2026-08-16-validate-lifecycle-receipt-contract/tasks.md +++ /dev/null @@ -1,24 +0,0 @@ -## 1. OpenSpec contract - -- [x] 1.1 Add the proposal, design, and `agent-canary-validation` delta for issue #633. -- [x] 1.2 Record the selected `opencode` real-upgrade anchor, failure semantics, and writer/reader matrix in the change artifacts. - -## 2. Real-upgrade canary - -- [x] 2.1 Resolve a valid lower stable package version dynamically for the selected smoke agent. -- [x] 2.2 Seed and adopt the older package in the disposable canary environment. -- [x] 2.3 Assert a refreshed `qtx update` is a real upgrade, inspect the written receipt, and let uninstall consume it. -- [x] 2.4 Add focused smoke-source assertions for the real-upgrade scenario and cleanup/error behavior. - -## 3. Writer/reader contract test - -- [x] 3.1 Capture legacy install receipts across all first-party provider fixtures. -- [x] 3.2 Capture Core install receipts across all first-party provider fixtures. -- [x] 3.3 Capture update receipts across all first-party provider fixtures and reconcile all captured outputs through the uninstall reader bindings. -- [x] 3.4 Assert explicit executable conflicts remain rejected. - -## 4. Validation and delivery - -- [x] 4.1 Run `bun run lint`, `bun run format:check`, `bun run typecheck`, and `bun run test`. -- [x] 4.2 Run `bun run openspec:validate` and `bun run memory:check`. -- [x] 4.3 Review git diff/status and report local implementation, repository delivery, PR delivery, release, and archive-closure states separately. diff --git a/src/lifecycle/uninstall-postcondition.ts b/src/lifecycle/uninstall-postcondition.ts index 25d2c632..619bf312 100644 --- a/src/lifecycle/uninstall-postcondition.ts +++ b/src/lifecycle/uninstall-postcondition.ts @@ -1,5 +1,6 @@ // Kept after P0 (#702) / P1 zero-ref scan: still used by Core uninstall-executor. // Keep: product-path touch so pure openspec archive PRs still run the macOS test matrix. +// Keep: product-path touch so the post-1.12 openspec/changes/archive cleanup PR still runs the macOS test matrix. export interface ExecutableAbsenceWaitOptions { readonly attempts?: number readonly delay?: (milliseconds: number) => Promise<void>