fix: address hands-on testing findings (v4 init, draft visibility, --fix routing, honest exits)#285
Conversation
…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>
There was a problem hiding this comment.
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.
| let type_target = export_subs | ||
| .iter() | ||
| .rposition(|(header, _, _)| header.contains("type")); |
There was a problem hiding this comment.
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 });There was a problem hiding this comment.
❌ 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>
There was a problem hiding this comment.
✅ 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
Summary
Fixes seven bugs found in hands-on testing of the v4.4.0 release binary, plus two smaller CLI paper cuts:
specsync initcreates the v4 layout — writes.specsync/config.toml, a4.0.0version stamp,.specsync/.gitignore, and thelifecycle//changes//archive/directories (mirroringspecsync migrate) instead of a legacy root-levelspecsync.json. A brand-new project no longer hits the "Legacy 3.x layout detected" nag on its firstcheck.init-registryrespects the v4 layout — writes.specsync/registry.tomlin v4 projects instead of recreating the legacy root-levelspecsync-registry.toml(which re-triggered the nag post-migration). Newregistry::local_registry_pathis also used byload_registry/register_module; un-migrated 3.x projects keep the legacy path.checknow 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 — setstatus: activeto enable full checks"). The skipping behavior itself is unchanged (by design).check --fixroutes exports to the matching table — functions/values go to the "… Functions"/"… Methods" table and type exports to the "… Types" table (previouslyadd/subtractlanded in "Exported Types"). Rows are padded to the target table's column count.generateexits 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 gainai_errors; both generation entry points now return aGenerationOutcome.watchfooter reflects actual results — it parses the child check's summary line instead of trusting the exit code (0 under defaultenforcement = warn), so "All checks passed!" is never printed under "… 1 failed".check <name>with an unmatched filter exits 1 without the contradictory "No spec files found in specs/" message.--root /nonexistenterrors 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
tests/integration.rs): v4 init layout + no-nag check, v4/legacyinit-registryrouting + idempotency, draft skip notices + summary hint,--fixfunction/type table routing + re-check idempotency, negated frontmatter label, unmatched-filter exit, nonexistent--root, AI-failure exit codeswrite_v4_layout, fresh-init-not-legacy, watch summary-line parsing + ANSI strippingcargo test— 763 tests pass (621 unit + 142 integration)cargo fmt --checkandcargo clippy -- -D warningscleancargo run --release -- check --strict --require-coverage 100 --force→ 58 specs, 0 warnings, 0 failed, 100% coverageinit+check(no nag), draft check output,--fixrouting,generate --provider anthropicwithout key (exit 1, error last),watchfooter for both failing and passing specs🤖 Generated with Claude Code