Skip to content

fix: address hands-on testing findings (v4 init, draft visibility, --fix routing, honest exits)#285

Merged
0xLeif merged 2 commits into
mainfrom
fix/hands-on-findings
Jun 11, 2026
Merged

fix: address hands-on testing findings (v4 init, draft visibility, --fix routing, honest exits)#285
0xLeif merged 2 commits into
mainfrom
fix/hands-on-findings

Conversation

@0xLeif

@0xLeif 0xLeif commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes seven bugs found in hands-on testing of the v4.4.0 release binary, plus two smaller CLI paper cuts:

  • Fresh specsync init creates the v4 layout — writes .specsync/config.toml, a 4.0.0 version stamp, .specsync/.gitignore, and the lifecycle//changes//archive/ directories (mirroring specsync migrate) instead of a legacy root-level specsync.json. A brand-new project no longer hits the "Legacy 3.x layout detected" nag on its first check.
  • init-registry respects the v4 layout — writes .specsync/registry.toml in v4 projects instead of recreating the legacy root-level specsync-registry.toml (which re-triggered the nag post-migration). New registry::local_registry_path is also used by load_registry/register_module; un-migrated 3.x projects keep the legacy path.
  • Draft specs no longer skip validation silentlycheck now prints "⊘ Section validation skipped (status: draft)" / "⊘ Export validation skipped (status: draft)" instead of misleading "✓ All required sections present" lines, plus a summary hint ("N draft spec(s) skipped section and export validation — set status: active to enable full checks"). The skipping behavior itself is unchanged (by design).
  • check --fix routes exports to the matching table — functions/values go to the "… Functions"/"… Methods" table and type exports to the "… Types" table (previously add/subtract landed in "Exported Types"). Rows are padded to the target table's column count.
  • generate exits non-zero on AI generation failure — the template fallback still happens, but the failures are re-printed prominently on stderr after the check report and the command exits 1 (was: buried mid-output, exit 0). JSON and MCP output gain ai_errors; both generation entry points now return a GenerationOutcome.
  • watch footer reflects actual results — it parses the child check's summary line instead of trusting the exit code (0 under default enforcement = warn), so "All checks passed!" is never printed under "… 1 failed".
  • Failing checks render negated labels — "✗ Frontmatter invalid" instead of "✗ Frontmatter valid".
  • check <name> with an unmatched filter exits 1 without the contradictory "No spec files found in specs/" message.
  • --root /nonexistent errors with exit 2 (was: silent exit 0).

11 spec files updated to keep the strict self-check green (export tables, invariants, scenarios, versions, change logs).

Test Plan

  • 12 new integration tests (tests/integration.rs): v4 init layout + no-nag check, v4/legacy init-registry routing + idempotency, draft skip notices + summary hint, --fix function/type table routing + re-check idempotency, negated frontmatter label, unmatched-filter exit, nonexistent --root, AI-failure exit codes
  • New unit tests: write_v4_layout, fresh-init-not-legacy, watch summary-line parsing + ANSI stripping
  • cargo test — 763 tests pass (621 unit + 142 integration)
  • cargo fmt --check and cargo clippy -- -D warnings clean
  • Self-check passes: cargo run --release -- check --strict --require-coverage 100 --force → 58 specs, 0 warnings, 0 failed, 100% coverage
  • Manual smoke tests with the release binary: fresh init+check (no nag), draft check output, --fix routing, generate --provider anthropic without key (exit 1, error last), watch footer for both failing and passing specs

🤖 Generated with Claude Code

…and watch

- init: create the v4 .specsync/ layout (config.toml, version stamp,
  .gitignore, lifecycle/changes/archive dirs) instead of legacy
  specsync.json, so a fresh project never sees the migration nag
- init-registry: write .specsync/registry.toml in v4 projects (legacy
  root path only for un-migrated 3.x layouts); add
  registry::local_registry_path and use it in load_registry /
  register_module
- check: draft specs print explicit "skipped (status: draft)" notices
  and a summary hint instead of misleading green checkmarks; failing
  frontmatter renders "✗ Frontmatter invalid"; unmatched spec filters
  exit 1 without the contradictory "No spec files found" message
- check --fix: route function/value exports to the functions table and
  type exports to the types table, padding rows to the target table's
  column count
- generate: exit 1 when AI generation fails (template fallback), with
  the failures re-printed last on stderr; JSON/MCP output gains
  ai_errors; both generation entry points return GenerationOutcome
- watch: footer parses the child check's summary line so it never
  prints "All checks passed!" under a failing report
- cli: --root pointing at a nonexistent path errors with exit 2

Updated the affected specs (11) and added 12 integration tests plus
unit tests for the new helpers.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@0xLeif 0xLeif requested a review from a team as a code owner June 11, 2026 14:22
@0xLeif 0xLeif requested review from 0xGaspar, Kyntrin and tofu-ux June 11, 2026 14:22

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request introduces the v4 layout for specsync, migrating configuration and registry files to the .specsync/ directory. It enhances CLI robustness by validating the --root path, exiting non-zero on AI generation failures, and ensuring unmatched spec filters result in an error. Additionally, draft specs now explicitly report skipped validation, and the auto-fix feature routes functions and types to their respective tables. Feedback was provided to expand the types-table matching logic in src/commands/check.rs to include other common type-related keywords (such as class, struct, interface, etc.) to ensure robust routing across all supported languages.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread src/commands/check.rs
Comment on lines +893 to +895
let type_target = export_subs
.iter()
.rposition(|(header, _, _)| header.contains("type"));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

The types-table matching logic currently only checks if the header contains the substring
"type". However, in many supported languages (like Rust, Swift, Java, Kotlin, Python, Ruby), type-related tables are commonly named using other keywords such as Classes, Structs, Traits, Protocols, Interfaces, or Enums (e.g., ### Exported Classes or ### Structs & Enums).\n\nBecause these headers do not contain "type", type_target will resolve to None, causing type exports to be incorrectly routed to the functions/methods table or the last table in the section.\n\nWe should expand the substring check to include other common type-related keywords to ensure robust routing across all supported languages.

                let type_target = export_subs\n                    .iter()\n                    .rposition(|(header, _, _)| {\n                        header.contains(\"type\")\n                            || header.contains(\"class\")\n                            || header.contains(\"interface\")\n                            || header.contains(\"enum\")\n                            || header.contains(\"struct\")\n                            || header.contains(\"trait\")\n                            || header.contains(\"protocol\")\n                    });

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

❌ Corvin says...

      _
    <(;\  .oO(oh no...)
     |/(\
      \(\\
      " "\\

"Even the dumpster of code seems empty today."

CI Summary

Check Status
Validate action.yml ✅ Passed
Dependency Audit ✅ Passed
Code Coverage ✅ Passed
Format Check ✅ Passed
Docs Site ✅ Passed
Spec Validation ✅ Passed
Tests (build, test, clippy) ❌ failure
VS Code Extension ✅ Passed
📋 Spec Validation Details

✅ SpecSync: Passed

Metric Value
Specs checked 58
Passed 58
Errors 0
Warnings 0
File coverage 100% (74/74)
LOC coverage 100% (33498/33498)

Generated by specsync · Run specsync check --format github to reproduce


Powered by corvid-pet

The init_registry_uses_v4_path_in_migrated_project test failed on
windows-latest because the created-file message rendered the relative
path with backslashes. Normalize the display string so output is
consistent with the tool's forward-slash path style on every platform.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actions github-actions Bot dismissed their stale review June 11, 2026 15:01

Superseded by updated review.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ Corvin says...

      _
    <(^\  .oO(Caw! ^v^)
     |/(\
      \(\\
      " "\\

"Caw! Found a shiny new spec!"

CI Summary

Check Status
Validate action.yml ✅ Passed
Dependency Audit ✅ Passed
Code Coverage ✅ Passed
Format Check ✅ Passed
Docs Site ✅ Passed
Spec Validation ✅ Passed
Tests (build, test, clippy) ✅ Passed
VS Code Extension ✅ Passed
📋 Spec Validation Details

✅ SpecSync: Passed

Metric Value
Specs checked 58
Passed 58
Errors 0
Warnings 0
File coverage 100% (74/74)
LOC coverage 100% (33500/33500)

Generated by specsync · Run specsync check --format github to reproduce


Powered by corvid-pet

@0xLeif 0xLeif merged commit 703d1f3 into main Jun 11, 2026
16 checks passed
@0xLeif 0xLeif deleted the fix/hands-on-findings branch June 11, 2026 15:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant