github Priivacy-ai/spec-kitty v3.2.0rc44

pre-release8 hours ago

✨ Added

  • ToolSurfaceContract unified registry (mission tool-surface-contract-01KV2K2P, PR #1948):
    src/specify_cli/tool_surface/ is now the bounded context for configured tool surface policy.
    spec-kitty doctor tool-surfaces --json reports stable findings and repair commands across command
    skills, doctrine skills, session/context surfaces, native agent profile projections, and plugin
    bundle surfaces. doctor skills --json remains backward-compatible, legacy agent config flows
    still work through the new contract, and fresh clones now get actionable generated-surface repair
    plans instead of silent missing .agents/skills/ drift.
  • Branch-strategy recommendation in /specify (issue #765): spec-kitty agent mission branch-context
    now resolves the repository's primary branch and emits a recommendation payload (primary_branch,
    current_is_primary, recommended_strategy, reason). The software-dev specify prompt consumes it to
    proactively recommend starting on a dedicated feature branch; mission create --start-branch now
    creates/switches before any mission artifacts are written when the operator is on the primary branch and
    expects a later PR; staying on the current branch remains an explicit, supported choice (wiring --pr-bound
    branch-strategy gate into the operator flow). The recommendation fields are additive and opt-in: callers
    that do not resolve a primary branch receive the byte-identical legacy branch contract.

🐛 Fixed

  • Docs: corrected the retired spec-kitty agent workflow implement command (issue #1874): the
    agent workflow command group no longer exists (the canonical form is spec-kitty agent action implement / … review). Updated the user-facing docs/how-to/implement-work-package.md and the
    AGENTS.md testing note. (The same stale command also appears in the PowerShell toolguide and the
    documentation/research per-WP task-prompt templates; those are rendered into the twelve-agent command
    snapshots, whose baselines are already drifted on main, so that replacement is left to the
    cli-reference-audit sweep which can regenerate the baselines in one pass.)
  • spec-kitty upgrade no longer churns metadata.yaml on a no-op (issue #1871): the "stamp
    last_upgraded_at only on material change" rule lived in three divergent idioms, and the migrations-applied
    root path plus _stamp_schema_version rewrote metadata.yaml (and advanced the timestamp / mtime) even when
    every migration was already recorded. ProjectMetadata.save() now does a masked compare-before-write
    (skipping the write when only the volatile last_upgraded_at/schema_version would change) and
    _stamp_schema_version skips its re-dump when the rendered bytes already match disk. A genuine
    version/migration/environment change still writes with a fresh timestamp; a no-op upgrade — including across a
    fully-recorded version range, on both the root and worktree paths — is now zero writes. This closes the class
    at the write boundary for upgrade/doctor/regeneration instead of adding a fourth per-path guard.
  • agent tasks map-requirements --json no longer crashes on auto-commit (issue #1891, Finding 1): the
    command stored the CommitResult returned by safe_commit() directly in the --json payload, so on the
    auto-commit success path json.dumps failed with "Object of type CommitResult is not JSON serializable"
    the mapping succeeded but agents got an unparseable error instead of the result. committed is now a bool
    and the resulting commit_sha (or null) is exposed alongside it. (Findings 2 and 3 — agent action implement --json and setup-plan/finalize-tasks JSON preamble — are tracked separately.)
  • accept --lenient now relaxes mission path conventions (issue #1892): spec-kitty accept / agent mission accept validated a mission's declared paths (src/, tests/, contracts/ for software-dev)
    unconditionally, so repos with a non-default layout (e.g. a Go service using internal/ with no top-level
    tests/) failed acceptance even with --lenient — the only workaround was creating throwaway empty
    directories. Path conventions now block only in strict mode; under --lenient an unmet convention is
    surfaced as a non-blocking warning. (A per-project paths override remains a possible follow-up.)
  • Name-vs-authority remediation (mission #133; closes #1889, #1860, #1865, #1866, #1867, #1863, #1896, #1898, #1904, #1684, #1906): (#1884/#1883/#1885 were independently fixed by PR #1910 and are verified-already-fixed here, not re-closed)
    binds the two remaining "a name/string shape is trusted as authority without cross-checking the declared authority"
    seams and ratchets them closed, and clears the live 3.2.0 release-blocker P0s rooted in that class. Topology
    authority seam (WorktreeTopology + classify_worktree_topology + is_registered_coord_worktree in
    coordination/surface_resolver.py, wrapping the git worktree list --porcelain registry) and branch-identity
    authority seam (mission_branch_name_required + structured BranchIdentityUnresolved in lanes/branch_naming.py,
    dual-era: legacy \d{3}- AND mid8 names both resolve) replace the convention predicates at their consumer sites;
    the (slug.replace('-','')+"00000000")[:8] mid8-fabrication idiom is eradicated (routed through
    resolve_transaction_mid8, fail-closed). P0s fixed: setup-plan's committed-spec gate verifies against the
    placement authority's ref not primary HEAD (#1884); the accept gate is idempotent across all modes via
    accept-owned-path exclusion (#1883); unresolvable mission handles raise a structured MissionNotFoundError
    (code + next_step, #1911) instead of a silent mission=unknown stub (#1885 residual). #1889's coordination-branch-deleted
    case becomes a distinct loud CoordinationBranchDeleted (decision-table row R3). An architectural ratchet
    (test_topology_resolution_boundary.py) keeps coord predicates, unbackstopped kitty/mission-{slug} composes, and
    the fabrication idiom from regrowing outside the blessed seam modules. Doctrine refinements (#1865/#1866/#1867) and
    the DRG extractor styleguide/toolguide references walk (#1863) ride along; the authority-path default flips
    architecture/2.x/adr3.x/adr. Cross-lane dependency code propagation (#1684): allocate_lane_worktree
    now merges approved dependency-lane tips (fresh creation + lane re-entry) so a dependent WP in a sibling lane sees
    its approved dependency's code, instead of branching from the bare mission branch.
  • _branch_exists/ref_exists consolidation (#1904): the duplicated git rev-parse --verify branch/ref
    existence idiom across coordination/status_transition.py, missions/_create.py, lanes/worktree_allocator.py,
    and lanes/merge.py is unified into lanes/_git.py (env-parameterized so the merge path's environment composes).

🧹 Maintenance

  • SonarCloud hygiene on mission #133 surfaces: raised new-code coverage on the authored seam/allocator/query
    files; reduced cognitive-complexity (extract-method) and duplicate-literal smells across doctrine.py,
    sync/daemon.py, sync/owner.py, drg/validator.py, org_charter.py, _read_path_resolver.py, core/worktree.py,
    agent/workflow.py, and upgrade.py (all behavior-preserving); regenerated stale codex/vibe command-skill
    snapshots to match the advanced templates (PR #1897 finding).

  • Upgrade no longer re-records not-applicable migrations (issue #1872): a migration whose detect()
    is False was re-appended as a skipped / "Not applicable" MigrationRecord on every spec-kitty upgrade
    run over the same version range, growing applied_migrations without bound and — for worktrees, after
    #1857 — bumping last_upgraded_at on no-op runs. ProjectMetadata.record_migration() is now idempotent
    (an identical (id, result) record is not re-appended) and the worktree upgrade path only marks metadata
    dirty when a new record was actually written, restoring stable last_upgraded_at for no-op re-runs. A
    genuine failed → success transition still records the new result.

  • Coordination & Merge stabilization (mission 131; closes #1826, #1861 Part 1, residuals of #1833/#1814/#1736/#1735):
    merge-pipeline ref advances now resync any worktree checked out on the advanced branch (shared
    git/ref_advance.py helper with a no-raw-update-ref architectural ratchet), refusing loudly — never
    resetting — when the worktree holds uncommitted state; the safe-commit backstop message names the diverged
    worktree/ref/state; finalize-tasks --validate-only no longer switches the git checkout; task finalization
    cleans its own primary-checkout residue (operator files untouched); workspace resolution treats non-worktree
    "husk" directories under .worktrees/ as structured failures instead of silently running git against the
    primary repo, with a new spec-kitty doctor workspaces [--fix] check for self-serve recovery — note:
    pre-existing husks that previously failed silently now produce explicit errors; run
    spec-kitty doctor workspaces --fix once to clean them; retrospective gating reads route through the
    canonical status surface (AC10 ratchet); upgrade --dry-run no longer prints a success line implying
    changes were applied; merge-driver hardening (single _make_merge_env() authority, narrowed exception
    mask, deterministic mixed-timestamp event-log sort).

  • Protected-branch guard capability honesty (PR #1850 review): the bool→capability conversion had
    re-opened protected-ref commits from production flows — three sites asserted GuardCapability.TEST_MODE
    (legacy workflow commit, baseline-artifact commit, finalize-tasks bootstrap) and six non-merge flows
    borrowed MERGE_BOOKKEEPING (move-task, mark-status, map-requirements, decision-log, op-record). All
    now assert STANDARD; protected destinations refuse, and refusals degrade gracefully (decision events
    and Op records are preserved on disk, nothing lands on the protected ref). SPEC_KITTY_TEST_MODE no
    longer waives the command-level protected-branch prechecks — only the documented operator hatch
    SPEC_KITTY_ALLOW_PROTECTED_BRANCH_COMMITS does — and the coordination gate now computes the same
    hatch-aware ProtectionState as safe_commit, so the two can no longer disagree. Ratcheted by
    tests/architectural/test_guard_capability_call_sites.py (capability→flow allowlist; TEST_MODE has
    zero src/ callers) and tests/git/test_guard_capability_regression.py.

  • Mission handle canonicalization completes at every CLI write boundary (PR #1850 review): bare mid8,
    numeric-prefix, and full-ULID handles now resolve to the identical canonical mission_slug,
    mission_id, status surfaces, and placement (ref and kind) as the full slug — across
    resolve_status_surface_with_anchor, resolve_placement_only, MissionStatus.load,
    _find_mission_slug (agent tasks/status/workflow), agent decision open, merge --mission,
    spec-kitty next --mission, plan --mission, mission run/close --mission,
    research --mission, and context resolve (persisted authoritative_ref). No more
    wrong-but-plausible kitty-specs/<mid8>/ paths, legacy-<mid8> identities, split-brain runtime
    runs or SaaS sync namespaces keyed by the raw handle, or close --discard silently leaving lane
    branches/worktrees behind. Pinned by
    tests/specify_cli/missions/test_handle_equivalence_matrix.py (78 parity tests).

  • Sync daemon reaper is scoped to its daemon root, not just the interpreter (PR #1850 review): the
    spawner embeds the resolved daemon state root and spawn-time interpreter identity as inert argv markers;
    the reaper kills only on marker + spawn-signature + interpreter-identity match and conservatively skips
    unmarked or unidentifiable processes. Fixes both the cross-$HOME over-kill and the macOS
    framework-Python inertness (where the re-exec rewrites exe() and argv[0] to the Python.app stub).

  • CI next filter covers the canonical runtime: src/runtime/next/** and src/mission_runtime/**
    now trigger the next suites and count toward diff-coverage critical paths (previously only the
    deprecated src/specify_cli/next/ shim was mapped, so integration-tests-next skipped on
    canonical-runtime changes).

  • StatusReadPathNotFound no longer escapes mission_runtime's single-error contract: the fail-closed
    refusal is translated to ActionContextError (error code and message preserved) at all three resolution
    boundaries and handled in the transactional status path; MissionStatus.load keeps its established
    CoordAuthorityUnavailable shape for every handle form in the fail-closed coordination window.

  • Repo hygiene: per-machine .kittify/legacy-warning-shown-* marker files untracked and gitignored.

Don't miss a new spec-kitty release

NewReleases is sending notifications on new releases.