Skip to content

fix(ci): set allow_zero_version and reset to 0.1.0#7

Merged
charlie83Gs merged 1 commit intomainfrom
fix/allow-zero-version
Mar 23, 2026
Merged

fix(ci): set allow_zero_version and reset to 0.1.0#7
charlie83Gs merged 1 commit intomainfrom
fix/allow-zero-version

Conversation

@charlie83Gs
Copy link
Copy Markdown
Contributor

Problem

python-semantic-release defaults allow_zero_version to false, which makes 1.0.0 the minimum possible version. This caused the initial release to be tagged as v1.0.0 instead of v0.1.0.

Fix

  • Set allow_zero_version = true in [tool.semantic_release]
  • Reset version in pyproject.toml back to 0.1.0
  • Created v0.1.0 baseline tag on current main so semantic-release has a starting point

After merge

The release workflow will detect the fix: commit and create v0.1.1, which will trigger the Docker build pipeline with the corrected Dockerfiles from PR #6.

🤖 Generated with Claude Code

semantic-release defaults allow_zero_version to false, which makes
the first possible version 1.0.0. Set it to true so versions can
start at 0.x.x as intended.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@charlie83Gs charlie83Gs force-pushed the fix/allow-zero-version branch from b43fef8 to 0704e4d Compare March 23, 2026 16:20
@charlie83Gs charlie83Gs merged commit 8c2dbb6 into main Mar 23, 2026
3 checks passed
@charlie83Gs charlie83Gs deleted the fix/allow-zero-version branch March 23, 2026 16:22
charlie83Gs added a commit that referenced this pull request Mar 27, 2026
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
charlie83Gs added a commit that referenced this pull request Apr 5, 2026
Critical:
- #1: Validate schema names with strict ^[a-z0-9_]+$ regex before DDL
- #2: Escape ILIKE special chars (%, _, \) in graph_nodes search
- #3: Replace cached Graph ORM instances with frozen GraphInfo dataclass
  to prevent DetachedInstanceError

High:
- #4: Reuse system session factories for default graph (no duplicate pools)
  via default_graph_session_factory/default_write_session_factory params
- #5: Add 23 unit tests — GraphInfo, GraphSessions, GraphSessionResolver,
  slug/schema validation, CreateGraphRequest, role validation
- #6: Scope sync watermarks by graph_slug — SyncEngine now passes
  graph_slug to _get_watermark/_set_watermark, composite PK on
  (table_name, graph_slug)

Medium:
- #7: Replace N+1 member count queries with batch GROUP BY
- #8: Replace catch { // ignore } with console.error in frontend
- #9: Engine pool disposal on GraphSessionResolver.invalidate()
- #10: Run Alembic migrations during graph provisioning
- #11: (node_count in list deferred — requires cross-schema queries)

Low:
- #13: Replace "Cycle Role" button with role dropdown
- #14: require_writer/require_graph_admin kept for future endpoints

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
charlie83Gs added a commit that referenced this pull request Apr 5, 2026
Critical:
- #1: Remove dead quote_ident call — regex is the sole injection guard
- #2: Add ^[a-z0-9_]+$ validation for ALEMBIC_SCHEMA in both env.py files

High:
- #3: Derive kt_db_root from kt_db package location instead of fragile parents[5]
- #4: Document MCP omits default_write_session_factory intentionally (read-only)
- #5: GraphContext now uses GraphInfo (frozen dataclass) instead of ORM Graph

Medium:
- #6: Replace user._token_graph_slugs monkey-patching with request.state
- #7: Fix remaining catch { // ignore } in graphs/page.tsx
- #9: Document MCP graph access check limitation, planned for follow-up

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
charlie83Gs added a commit that referenced this pull request Apr 5, 2026
Critical:
- #1: Invalidate resolver cache after provisioning (both success and error)
  so subsequent resolve() picks up fresh status
- #2: Combine status="active" + add_member in single commit to prevent
  orphaned graphs on crash

High:
- #3: Run Alembic migrations via asyncio.to_thread() to avoid blocking
  the event loop during HTTP requests
- #5: Store AsyncEngine references in GraphSessions for proper disposal
  instead of accessing sessionmaker.kw["bind"] internals

Medium:
- #7: Replace silent .catch(() => {}) with console.error in tokens page
- migrate.py path comment clarified for consistency

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
charlie83Gs added a commit that referenced this pull request Apr 5, 2026
Critical:
- #1: Control-plane migrations (zzai, zzaj) now skip when
  ALEMBIC_SCHEMA is non-public — prevents duplicating graphs/
  graph_members/api_tokens tables in per-graph schemas

High:
- #3: Replace global asyncio.Lock with per-graph locks via
  _locks dict + lightweight _meta_lock for dict insertion only
- #7: Default graph now enforces min_role for write operations
  (PUT /graphs/default requires admin)

Medium:
- #9: Validate storage_mode=database requires connection key at
  creation time (422 instead of confusing ValueError at resolve)
- #12: Fix SyncWatermark docstring (defaults to "default", not NULL)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
charlie83Gs added a commit that referenced this pull request Apr 5, 2026
…rors

- #1: Extract validate_schema_name() into kt_db.keys as single source
  of truth. Remove duplicate regex from graphs.py, repositories/graphs.py,
  graph_sessions.py, and both alembic env.py files. Remove redundant
  double-quotes in SET search_path.
- #3: Provisioning no longer caches via resolver — uses temporary write
  session factory for DDL, avoiding stale cached engines mid-migration.
- #5: Qdrant collection failures now propagate (not swallowed), causing
  graph to go "error" instead of "active" without collections.
- #7: GraphProvider gates listGraphs() on auth loading complete +
  user !== null, preventing race with AuthProvider.
- #11: Replace <a> with Next.js <Link> on graphs list page.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
charlie83Gs added a commit that referenced this pull request Apr 5, 2026
…ease

- #1: Lock admin members unconditionally before checking role — prevents
  race where two concurrent requests both see admin_count=2 before lock
- #5: Release control session before acquiring per-graph lock in
  resolve_by_slug to avoid holding pool slot during lock wait
- #7: require_writer now enforces superuser-only for default graph
  writes, matching the documented policy

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
charlie83Gs added a commit that referenced this pull request Apr 7, 2026
Picks up the actionable items from the round-3 review.

#1 Orphan-schema risk — defended in docstring + recovery path documented
   The Graph row is committed in "provisioning" status BEFORE _provision_graph
   runs (graphs.py:313). All provisioning steps are idempotent
   (CREATE SCHEMA IF NOT EXISTS, alembic upgrade head, ensure_collection),
   so a partial failure marks the row "error" and /retry-provision is the
   recovery path. Added a "Failure recovery" section to the _provision_graph
   docstring explaining why we deliberately don't drop schemas on failure.

#3 Fragile qdrant_url comparison — strip trailing slashes when comparing
   so http://h:6333 and http://h:6333/ are treated as the same target and
   we don't needlessly spawn+close a fresh Qdrant client.

#4 "default" magic string — extracted DEFAULT_DB_CONFIG_KEY constant in
   kt_config.settings and used everywhere (API handler, repo guard,
   list endpoint, startup check). Added a startup check in
   kt_api.main._assert_default_db_key_unreserved() that logs an error
   if a real database_connections row holds the reserved key — catches
   anything that may have slipped in via raw SQL or a previous version
   that lacked the repo guard.

#6 Test coverage gap — added two new test files:
   - services/api/tests/test_provision_graph_routing.py: 3 tests that mock
     create_async_engine, subprocess.run, and the Qdrant client factories
     to assert _provision_graph routes to the EXTERNAL DB URLs when
     database_connection_id is set, routes to the SYSTEM DB URLs when it's
     null, and raises a clear error when the config_key is missing from
     settings.graph_databases.
   - test_database_connections_endpoint.py: new
     test_create_graph_with_default_key_uses_system_db that POSTs a graph
     with database_connection_config_key="default" and asserts the
     resulting row has database_connection_id=None. Added a stub_users_in_db
     fixture that inserts the test users into the User table to satisfy
     the FK constraint on graphs.created_by.

#7 Frontend grep — confirmed nothing references storage_mode on
   CreateGraphRequest in frontend/. The only remaining reference is on
   GraphResponse, which is the read-side type (kept for backward compat).

Skipped per reviewer note: #2 (alembic env override — reviewer self-resolved),
#5 (cosmetic _admin rename).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
charlie83Gs added a commit that referenced this pull request Apr 21, 2026
Non-blocking review items on the sync wiring PR:

#4 Replace `assert worker_state.services is not None` with an
   explicit `if ... raise RuntimeError` so the invariant holds
   under `python -O` (which strips asserts) and we never dispatch
   against a silently-None services container.

#5 Dedup the 'no plugin contributes this id' WARN from
   `resolve_sync_provider` per `(graph_id, provider_id)` pair.
   Sync dispatch is a cron that runs once per graph every minute;
   without dedup a rolling deployment fills the log with N×60
   duplicate lines per hour per missing plugin. First occurrence
   still fires at WARNING; subsequent occurrences drop to DEBUG so
   operators can still see them under a verbose logger but don't
   get paged on spam. Set stays bounded by (graph_id, provider_id)
   cardinality (handful × handful) — no eviction needed; a worker
   restart re-warns once, which is the signal operators want.

#6 Surface `SyncResult.failures` in the task log line + emitted
   event. Legacy path doesn't have a failures counter (engine's
   dead-letter inserts are logged inside the engine), so the field
   is 0 on the legacy branch and populated from the provider result
   on the registry branch. No behaviour change on legacy; parity
   for the provider contract.

#7 Move the `from kt_worker_sync.sync_engine import SyncEngine`
   import inside the legacy-path branch — the provider-driven path
   never needs it, so we skip the import on workers whose plugin is
   registered. Micro-optimisation; clearer at the call site too.

Skipped:
- #1 PR body overstates scope: will amend body on GitHub instead.
- #2 ABC lifecycle mismatch (init once vs per-task): flagged for a
  Phase-5 follow-up. Cache-on-WorkerState design needs more thought
  than fits in a review pass.
- #3 options-dict workaround: real design tension — per-graph
  session factories don't fit the `initialize(services)` once-per-
  worker contract. Phase-5 follow-up.

Tests: 15 composition helper tests (2 new dedup tests — one
asserting repeated resolves produce a single WARN, one asserting
distinct keys warn independently), 18 worker-sync unit tests.
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