Skip to content

fix(archive): make the scenario-drift check fence-aware, plus release-audit follow-ups - #1475

Merged
clay-good merged 23 commits into
mainfrom
fix/pre-170-audit-followups
Jul 29, 2026
Merged

fix(archive): make the scenario-drift check fence-aware, plus release-audit follow-ups#1475
clay-good merged 23 commits into
mainfrom
fix/pre-170-audit-followups

Conversation

@clay-good

@clay-good clay-good commented Jul 28, 2026

Copy link
Copy Markdown
Collaborator

Status: LGTM — pre-1.7.0 audit follow-ups from three full audit passes; every fix has a failing-then-passing test or a direct E2E repro. Full suite: 3,378 passing; CI green on macOS/Linux/Windows.

Three rounds over v1.6.0..main (88 commits): (1) clean-build + full suite, E2E, security review, per-commit review of everything since 2026-07-23; (2) adversarial re-review of parser/archive/validation and stores/init/update/completions plus E2E torture tests; (3) an adversarial review of THIS PR's own diff, a coverage-gap sweep (release mechanics, all 78 changesets parsed, docs-vs-CLI accuracy, dep-major compatibility, workflows), and triage of CodeRabbit's findings. No blockers or majors exist on main; this PR fixes everything real that any round found.

What was wrong / how it was fixed (one commit per fix; changesets included)

Round one

  1. Fence-blind drift check — archive's parseScenarioBlocks didn't mask code fences while validate's countScenarios does: a fenced #### Scenario: example false-aborted archives, and a fenced name masked a genuinely dropped scenario. Now uses the shared fence mask.
  2. Update-check budget vs redirects — the 1.5s budget timer closed over the first hop's request; a redirect to a trickling endpoint escaped it. The timer now tears down whichever request is open.
  3. 18 missing changesets — ZCode/Hermes/CodeArts/Kimi-rename/Codex-skills-only/skills.sh/nested-specs and 11 more were absent from the pending 1.7.0 notes.
  4. Gemini TOML escaping — description/prompt were interpolated raw into TOML strings (same class fix(adapters): escape YAML frontmatter values consistently across all command adapters #1447 fixed for YAML). Now escaped in both contexts, including control characters; output verified with a real TOML parser.
  5. Install-detection hardening — a directory literally named volta stole the upgrade hint (now requires volta's full tools+image layout); the Windows npm-ownership check was trivially true (now corroborates the openspec.cmd shim); https→http registry redirect downgrades are refused.
  6. zcodeAdapter barrel export; stale instructions completion description.

Round two
7. BOM broke delta parsing## ADDED Requirements reported "No delta sections found" (Windows editors, Out-File). Both normalizers now strip the BOM.
8. MODIFIED never no-op-aware — a fully early-synced change with a MODIFIED delta rewrote the file and claimed ~ N modified where its ADDED/REMOVED/RENAMED twins print "Specs already in sync". Now counts only real replacements.
9. RENAMED near-miss guard — an already-synced rename silently skipped even when a case variant of the source (a typo) still existed; now aborts like REMOVED does, while case-only renames still no-op.
10. Validator masked unreadable specs dirs as "no deltas found"; only ENOENT/ENOTDIR are tolerated now.
11. Silent skills wipedelivery: commands deleted the skills of adapterless tools (Hermes, Kimi Code, Vibe, CodeArts, ForgeCode) with no message, then tool detection re-suggested an init that would also generate nothing. Update now prints init's configuration correction. (Init's generate-nothing-plus-correction design is deliberate and tested; only update's silence was the bug.)
12. zsh completions ignored $ZSH — custom OMZ locations got a ~/.oh-my-zsh tree nothing loads; $ZSH/$ZSH_CUSTOM are honored everywhere, the fpath advice greps the real directory, and the installer tests now isolate both variables (the #1400 leakage class).
13. Static welcome screen printed "Press Enter to select tools..." and returned immediately, letting the Enter submit the tool picker sight-unseen (#1462 widened exposure). It now waits in a TTY and drops the line otherwise.
14. Feedback discarded text on issues-disabled/network/rate-limit gh failures; the manual fallback (formatted text + pre-filled URL) now shows on every gh failure, with test coverage.
15. ENAMETOOLONG errno dump for 300-char change names → clean "too long (200 characters max)" validation error.

Round three (review of this PR's own diff + CodeRabbit triage)
16. Volta corroboration was OR where the comment said AND (/srv/volta/tools/... still misclassified) — fixed with both-segments requirement + test.
17. Gemini multiline prompts didn't escape C0 control characters — fixed + test.
18. Hermes/zcode changeset texts misdescribed shipped behavior (hermes is skills-only; zcode registers /opsx:*, not /opsx-*) — corrected.
19. CodeRabbit's "contradictory update messages" finding was verified false (the two message lists are capability-disjoint) — no change.

Replication / proof

  • Fixes 1, 2, 8, 9, 13: tests written first against the old build and observed failing (fix 8's test showed the file being rewritten; fix 1's showed a real scenario silently dropped), then passing.
  • Fixes 4, 7, 15, 16, 17: E2E or direct repro before, verified after (tomllib parses the generated TOML; BOM change validates; /srv/volta/tools/... now → npm).
  • Coverage sweep: all 78 pending changesets parse (69 patch + 9 minor → v1.7.0); release workflows verified; every command/flag in changed docs exists in the CLI; zero dead doc links; ora 8→9 verified at all 18 call sites.
  • Full suite after all commits: 115 files / 3,378 tests green.

Notes / follow-ups deliberately not in this PR (design calls or pre-existing behavior too risky right before a release)

  • Windsurf→Devin migration skips its consent prompt in non-TTY runs — documented as intended in the commit; contradicts migration.ts's "offered, not taken" comment; maintainer's call.
  • Pre-existing: drift-guard scenario regex (#### Scenario:) is narrower than the validator's (#### = any h4); aligning changes abort behavior — own PR.
  • Pre-existing: duplicate ## ADDED Requirements sections silently keep only the last — own PR.
  • Contrived order-dependence in the new RENAMED near-miss guard (a delta whose rename creates a fold-variant of a later rename's FROM can false-abort; aborts pre-write, no data loss).
  • Nits left alone: store doctor exits 0 on a broken store; archive Purpose spacing/alphabetical ordering; config.yaml warn-vs-silent inconsistency; pwsh-on-POSIX detection; uncancelable DNS lookup can outlive the update-check budget promise; bare /og/docs website route asymmetry.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added workflow support for CodeArts Agent, Hermes Agent, and ZCode.
    • Published workflow skills via the skills ecosystem.
    • Improved discovery for nested and symlinked specifications.
  • Bug Fixes

    • Enhanced archive drift detection (including fenced scenarios), rename/near-miss handling, and accurate no-op reporting.
    • Improved feedback submission fallback when CLI submission fails.
    • Hardened update checks and redirects; improved Windows input, local date handling, BOM parsing, validation, and TOML generation.
  • User Experience

    • Added clearer warnings for incomplete or zero-artifact workflow installations.
    • Refined multi-select checkbox UI and welcome-screen behavior; updated Kimi Code naming and Zsh completion paths.

clay-good and others added 3 commits July 28, 2026 16:29
parseScenarioBlocks matched #### Scenario: headers on raw lines while the
validator's countScenarios masks fenced code blocks (#1151). The drift
check (#1391) inherited the raw scan, so a fenced scenario example in the
current spec aborted an archive that validate had passed, and a fenced
name in the MODIFIED block counted as keeping a scenario the block had
actually dropped. Build the shared code-fence mask and skip masked lines
in both the header scan and the block-end scan.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The overall request budget was armed inside the first send() and its
callback closed over that hop's request. After a redirect the timer
destroyed the already-dead first request, so a redirect target that
trickled bytes kept resetting its idle timeout and held the socket open
until the body-size cap. Track the in-flight request and have the budget
timer destroy whichever one is open.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…he 1.7.0 notes

18 feat/fix commits merged since v1.6.0 without a changeset, so the
pending Version Packages PR would have released them silently: five tool
integrations (ZCode, Hermes, CodeArts, Kimi Code rename, Codex
skills-only), skills.sh distribution, symlinked schema dirs, nested spec
discovery, drift multiplicity, checkbox markers, Windows welcome input,
npx avoidance, doctor store drift, local dates, missing-core-workflows
warning, store-aware main specs, open-questions guidance, and spec
content guidance. Plus changesets for this branch's two fixes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@clay-good
clay-good requested a review from a team as a code owner July 28, 2026 21:34
@clay-good
clay-good requested review from alfred-openspec and removed request for a team July 28, 2026 21:34
@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The PR hardens archive scenario handling, parsing, validation, version checks, CLI/UI behavior, command generation, completion paths, and release metadata for @fission-ai/openspec.

Changes

OpenSpec behavior and release updates

Layer / File(s) Summary
Archive application and drift detection
src/core/specs-apply.ts, test/core/archive.test.ts
Fenced scenarios are ignored, effective MODIFIED counts are corrected, and near-miss RENAMED headers produce targeted errors with regression coverage.
Parsing, validation, and version checks
src/core/parsers/*, src/core/validation/validator.ts, src/core/version-check.ts, src/utils/change-utils.ts, test/core/version-check.test.ts
BOM input, unreadable directories, long names, redirects, npm detection, and Volta path handling are addressed.
CLI, UI, and completion behavior
src/commands/feedback.ts, src/core/update.ts, src/ui/welcome-screen.ts, src/core/completions/installers/zsh-installer.ts
Feedback fallback details, zero-artifact warnings, static welcome input, and configurable Oh My Zsh paths are updated.
Command generation and exports
src/core/command-generation/adapters/*, src/core/completions/command-registry.ts
Gemini TOML output is escaped, the ZCode adapter is exported, and instruction text includes archive operations.
Release metadata
.changeset/*
Changesets record the package’s tool, workflow, parser, archive, CLI, validation, completion, and update-check changes.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related issues

Possibly related PRs

Suggested reviewers: alfred-openspec, tabishb

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly reflects the main archive fix and the broader audit follow-up scope.
Docstring Coverage ✅ Passed Docstring coverage is 84.62% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/pre-170-audit-followups

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

clay-good and others added 11 commits July 28, 2026 16:43
The gemini adapter interpolated the description into a TOML basic string
and the body into a multiline basic string with no escaping. Every
current template value happens to be safe; the first description with a
double quote or backslash would silently produce invalid TOML for all
Gemini command files. Escape both contexts (#1447 fixed the same class
for the YAML adapters but scoped itself to YAML).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Three follow-ups from the release audit:
- A path segment literally named volta (a user or project directory)
  classified the install as volta-managed and swallowed the upgrade
  offer. The undotted spelling now requires volta's own tools/image
  layout, matching how pnpm and yarn already demand corroboration.
- The Windows npm-ownership fallback checked that the npm prefix exists,
  which is true of any X\node_modules\pkg tree, hand-copied ones
  included. Corroborate with the openspec.cmd shim npm actually writes.
- A https registry redirecting to plain http was followed; a MITM on
  that reply controls the newer-version answer. Refuse the downgrade.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… description

zcode was registered but missing from the adapters barrel (its test
imported the module directly), and the completion registry still carried
the pre-#1062 description for the instructions command.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A BOM-prefixed delta spec (Windows editors, PowerShell Out-File) failed
validate and archive with 'No delta sections found' because the first
line never matched '## ADDED Requirements'. Strip the BOM in both
normalizers, the same way tool detection already does.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A 300-character change name surfaced two raw ENAMETOOLONG errno dumps
from stat and mkdir. Bound the name at 200 characters in
validateChangeName so the failure is a normal validation error.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Two asymmetries left over from the #1376/#1386/#1437 no-op work:

- MODIFIED counted every delta as applied even when the block was
  byte-equal to the main spec, so a fully early-synced change rewrote
  the file (normalization churn), printed '~ N modified', and reported
  specsUpdated: true where its ADDED/REMOVED/RENAMED twins print 'Specs
  already in sync; no files changed.' Count only real replacements.
- RENAMED's already-synced skip (source gone, target present) had no
  near-miss guard: a case/whitespace variant of the source still in the
  spec means a typo'd header, and REMOVED already hard-aborts on that
  signal. Apply the same guard, excluding the target itself so a
  case-only rename still no-ops.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The delta-validation loop swallowed every error as 'if no specs dir,
treat as no deltas', so an EACCES capability folder produced the
misleading 'Change must have at least one delta' while archive let the
same error propagate. Tolerate only ENOENT and ENOTDIR (a stray specs
file); anything else stays loud, matching discoverSpecFiles' documented
fail-loud contract.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Under delivery: commands, update removed the skills of adapterless
skills-only tools (Hermes, Kimi Code, Vibe, CodeArts, ForgeCode) without
a word — leaving zero OpenSpec artifacts while the tool's detection dir
kept re-suggesting an init that would also generate nothing. Print the
same per-tool configuration correction init already prints, pointing at
'openspec config set delivery both'.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The installer used a set $ZSH only as an is-installed signal and then
wrote to ~/.oh-my-zsh regardless, so a custom OMZ location got a
freshly created ~/.oh-my-zsh tree that no shell ever loads — and
isInstalled/uninstall looked in the same wrong place. Route every path
through the $ZSH/$ZSH_CUSTOM-aware helpers.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The static branch printed 'Press Enter to select tools...' and returned
immediately, so the Enter landed in the tool picker and submitted the
pre-selected set sight-unseen. #1462 routed reduced-motion,
OPENSPEC_NO_ANIMATION, --no-animation, NO_COLOR, and narrow-terminal
users onto this path. Wait in a TTY; drop the prompt line when there is
no TTY to wait on.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Only missing-gh and unauthenticated flows showed the formatted feedback
and pre-filled submission URL; issues-disabled, network, or rate-limit
failures printed gh's stderr and discarded the path to submit what the
user had already typed. Route those through the same manual fallback,
preserving gh's exit code.

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/core/command-generation/adapters/gemini.ts`:
- Around line 35-36: Update escapeTomlMultilineBasicString to escape
TOML-invalid C0 control characters using TOML_CONTROL_CHARS or the appropriate
TOML basic-string variant, while preserving intentional tabs, newlines, and
carriage returns. Add regression coverage for values containing NUL and vertical
tab to ensure generated multiline strings remain valid.

In `@src/core/completions/installers/zsh-installer.ts`:
- Around line 57-58: Update generateOhMyZshFpathGuidance() to derive its fpath
check from completionsDir, so custom ohMyZshCustomDir() installations reference
the actual <custom>/completions path instead of the literal default path. Add
cross-platform regression coverage with a custom ZSH_CUSTOM value, using
path.join(...) for filesystem expectations.

In `@src/core/update.ts`:
- Around line 292-298: Update the skills removal flow in the update logic around
shouldGenerateCommandsForTool and the later skillsInvocableCommandSkips handling
so tools recorded in zeroArtifactTools for commands-only delivery are not also
added to the generic “Commands skipped ... (uses skills)” message. Preserve the
existing skip reporting for tools whose skills remain, and add or update a test
asserting the contradictory message is absent.

In `@src/core/version-check.ts`:
- Around line 452-455: Update the undotted Volta detection condition in the
version-check logic to require both `tools` and `image` segments independently,
while preserving the existing `.volta` check. Add regression coverage for paths
containing `volta` with only `tools` and only `image`, ensuring neither is
classified as Volta.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 16a6f9bd-ff3f-4e32-81e8-586a6d6e608d

📥 Commits

Reviewing files that changed from the base of the PR and between 0984400 and 16594f0.

📒 Files selected for processing (31)
  • .changeset/bom-delta-parsing.md
  • .changeset/change-name-length.md
  • .changeset/feedback-manual-fallback.md
  • .changeset/gemini-toml-escaping.md
  • .changeset/modified-noop-counting.md
  • .changeset/renamed-near-miss-guard.md
  • .changeset/static-welcome-waits.md
  • .changeset/update-check-detection-hardening.md
  • .changeset/update-zero-artifact-notice.md
  • .changeset/validator-unreadable-specs.md
  • .changeset/zsh-completions-custom-omz.md
  • src/commands/feedback.ts
  • src/core/command-generation/adapters/gemini.ts
  • src/core/command-generation/adapters/index.ts
  • src/core/completions/command-registry.ts
  • src/core/completions/installers/zsh-installer.ts
  • src/core/parsers/markdown-parser.ts
  • src/core/parsers/requirement-blocks.ts
  • src/core/specs-apply.ts
  • src/core/update.ts
  • src/core/validation/validator.ts
  • src/core/version-check.ts
  • src/ui/welcome-screen.ts
  • src/utils/change-utils.ts
  • test/core/archive.test.ts
  • test/core/command-generation/adapters.test.ts
  • test/core/parsers/requirement-blocks.test.ts
  • test/core/update.test.ts
  • test/core/version-check.test.ts
  • test/ui/welcome-screen.test.ts
  • test/utils/change-utils.test.ts

Comment thread src/core/command-generation/adapters/gemini.ts Outdated
Comment thread src/core/completions/installers/zsh-installer.ts
Comment thread src/core/update.ts
Comment on lines +292 to +298
// A tool with no command adapter now has zero OpenSpec artifacts;
// say so like init does, rather than deleting its skills silently
// and letting tool detection re-suggest an init that would also
// generate nothing under this delivery setting.
if (!shouldGenerateCommandsForTool(tool.value, delivery)) {
zeroArtifactTools.push(tool.name);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Suppress the contradictory “uses skills” message.

For a skills-only tool in commands delivery, these lines remove its skills and record it as zero-artifact. The later skillsInvocableCommandSkips path at Line [318] still reports “Commands skipped ... (uses skills),” so users receive both contradictory messages. Avoid adding that generic skip entry when commands-only delivery removes the skills, and cover the absence of the misleading message in the test.

Also applies to: 359-368

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/core/update.ts` around lines 292 - 298, Update the skills removal flow in
the update logic around shouldGenerateCommandsForTool and the later
skillsInvocableCommandSkips handling so tools recorded in zeroArtifactTools for
commands-only delivery are not also added to the generic “Commands skipped ...
(uses skills)” message. Preserve the existing skip reporting for tools whose
skills remain, and add or update a test asserting the contradictory message is
absent.

Comment thread src/core/version-check.ts Outdated
clay-good and others added 6 commits July 28, 2026 17:26
The ownership corroboration now checks for the openspec.cmd shim npm
writes beside node_modules; the Homebrew-prefix fixture built the layout
without it, so the test failed on windows-pwsh. Write the shim in the
fixture and pin the inverse: the same shape with nothing npm wrote (a
hand-copied portable tree) is not an npm install.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… spelling

The corroboration used has('tools', 'image'), which is some() — volta
AND (tools OR image) — so /srv/volta/tools/apps/... still classified as
a Volta install and swallowed the upgrade offer. Require both segments,
matching the real %LOCALAPPDATA%\Volta\tools\image layout.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
escapeTomlMultilineBasicString handled backslashes and quote-triples but
not the C0 controls that are as invalid in a multiline basic string as
in a single-line one. Reuse TOML_CONTROL_CHARS, applied last so the
escapes it introduces are not re-doubled.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The fpath verification advice still grepped the literal
custom/completions, which a relocated $ZSH_CUSTOM need never contain —
grep the actual directory instead. The installer tests cleared only
$ZSH, so on a machine exporting $ZSH_CUSTOM they would have written
into (and deleted from) the developer's real OMZ custom dir — the same
leakage class #1400 fixed for $ZSH. Clear/restore both, and pin the
custom-location paths with two new tests.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Hermes is skills-only (no command adapter), and zcode's namespaced
commands register /opsx:<id>, not /opsx-* — the release notes must not
reintroduce the invocation-spelling confusion #1471 removed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The new reportGhFailure output (formatted feedback + pre-filled URL) had
no coverage; the network-failure test now asserts it.

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
test/commands/feedback.test.ts (1)

347-356: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Assert that the typed feedback is preserved.

These checks only prove that generic fallback text and a URL are printed. A regression that drops the submitted title/body would still pass. Assert the formatted title (for example, Title: Feedback: Test) and the encoded title in the manual URL; also prefer the full https://github.com/... prefix.

This directly covers the PR objective that feedback failures retain manual submission data.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/commands/feedback.test.ts` around lines 347 - 356, Strengthen the
assertions in the manual-submission fallback test so they verify the submitted
feedback is preserved, not just that generic instructions appear. Alongside the
existing fallback check, assert the formatted title such as “Title: Feedback:
Test” and the encoded title in the manual URL, using the full
“https://github.com/Fission-AI/OpenSpec/issues/new” prefix.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/core/completions/installers/zsh-installer.ts`:
- Around line 346-348: Update the fpath check in the zsh installer to treat
completionsDir as a literal value: emit fpath entries via printf '%s\n' with
"$fpath", use grep -F, and shell-escape the completionsDir before embedding it
in the displayed command so quotes, backslashes, and regex characters remain
safe.

---

Nitpick comments:
In `@test/commands/feedback.test.ts`:
- Around line 347-356: Strengthen the assertions in the manual-submission
fallback test so they verify the submitted feedback is preserved, not just that
generic instructions appear. Alongside the existing fallback check, assert the
formatted title such as “Title: Feedback: Test” and the encoded title in the
manual URL, using the full “https://github.com/Fission-AI/OpenSpec/issues/new”
prefix.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: fe3dc428-381b-450a-8c1f-7f23a461a68f

📥 Commits

Reviewing files that changed from the base of the PR and between fd89858 and 40657aa.

📒 Files selected for processing (9)
  • .changeset/add-hermes-tool.md
  • .changeset/add-zcode-tool.md
  • src/core/command-generation/adapters/gemini.ts
  • src/core/completions/installers/zsh-installer.ts
  • src/core/version-check.ts
  • test/commands/feedback.test.ts
  • test/core/command-generation/adapters.test.ts
  • test/core/completions/installers/zsh-installer.test.ts
  • test/core/version-check.test.ts
🚧 Files skipped from review as they are similar to previous changes (5)
  • .changeset/add-zcode-tool.md
  • .changeset/add-hermes-tool.md
  • src/core/command-generation/adapters/gemini.ts
  • test/core/version-check.test.ts
  • src/core/version-check.ts

Comment thread src/core/completions/installers/zsh-installer.ts Outdated

@alfred-openspec alfred-openspec left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The multiline TOML escaper still emits a bare carriage return: geminiAdapter.formatFile({ ...content, body: "a\rb" }) is rejected by Python 3.13 tomllib with Illegal character '\r'. Please normalize CRLF and escape a lone CR, then add a parser-backed regression so the new “control characters cannot produce invalid TOML” guarantee holds.

…idance

The verification advice interpolated the completions dir into
grep "<dir>" where regex metacharacters make the check unreliable and
quotes could break the displayed command. Print one fpath entry per
line and match with grep -F on a shell-quoted literal.

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

@alfred-openspec alfred-openspec left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Rechecked exact head 3de75e0: the zsh follow-up is sound, but the previously requested Gemini fix is not in this head and the same a\rb output still fails Python 3.13 tomllib. Keeping this changes-requested until CRLF is normalized, a lone CR is escaped, and parser-backed regression coverage is added.

A lone CR is illegal in a multiline basic string — Python 3.13 tomllib
rejects the file — and the control-char pass deliberately skipped it on
the assumption it only appears as CRLF. Normalize CRLF to LF and escape
any remaining CR as \r. The escaping guarantee is now parser-backed:
smol-toml (new devDependency) round-trips every hostile body in the
regression matrix (lone CR, CRLF, CR before a quote run, NUL/VT/FF,
trailing backslash, four- and five-quote runs), and the same outputs
were verified against Python tomllib.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The lockfile changed, so the fixed-output derivation hash moved; value
taken from the CI mismatch report.

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

@alfred-openspec alfred-openspec left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Verified the requested Gemini fix at exact head 6049821: CRLF is normalized, lone CR is escaped, and parser-backed hostile-body coverage round-trips correctly. Local build, lint, 1,121 focused tests, an additional 185-document Python tomllib sweep, and the hosted CI/security/Nix matrix all pass.

@clay-good
clay-good added this pull request to the merge queue Jul 28, 2026
Merged via the queue into main with commit 17af60c Jul 29, 2026
16 checks passed
@clay-good
clay-good deleted the fix/pre-170-audit-followups branch July 29, 2026 00:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants