Conversation
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
WalkthroughThe PR strengthens fleet persistence invariants, adds bounded probe policies, introduces model-aware supervisor status and probe flows, preserves chat request bytes, and coalesces snapshot loads while protecting cache freshness during concurrent revisions. ChangesProtocol and persistence integrity
Model-aware supervisor control flow
Chat proxy and snapshot cache
Documentation and runtime support
Estimated code review effort: 5 (Critical) | ~120 minutes Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
✨ Simplify code
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. Comment |
Code Review BotNo comment/code divergences detected. |
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
services/haru-server/src/reconciler/steps.ts (1)
447-453: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winReuse
configuredInferenceModelNamesinstead of re-deriving the expected model set.This inline
flatMapis identical to the newconfiguredInferenceModelNames(domain)helper (also reused byisEveryConfiguredInferenceModel). Two copies of the layout-bound-model derivation can silently diverge, and this one gates routing safety, so consolidate.♻️ Proposed consolidation
- const expectedModels = new Set( - domain.slots.flatMap((slot) => - slot.spec.kind === "inference" - ? slot.spec.models.map((m) => m.name) - : [], - ), - ); + const expectedModels = new Set(configuredInferenceModelNames(domain));🤖 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 `@services/haru-server/src/reconciler/steps.ts` around lines 447 - 453, Replace the inline expectedModels Set construction in the reconciler step with the existing configuredInferenceModelNames(domain) helper. Keep the resulting set semantics and routing-safety behavior unchanged, and do not duplicate the slot/model derivation logic.
🤖 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 `@packages/db/drizzle/0003_dazzling_may_parker.sql`:
- Around line 81-83: The composite foreign keys
fleets_active_domain_membership_fk, operations_target_domain_membership_fk, and
operations_source_domain_membership_fk should be added with NOT VALID, followed
by separate VALIDATE CONSTRAINT statements to reduce the exclusive-lock window
while preserving enforcement for new writes. Apply the same NOT
VALID-then-VALIDATE approach to the CHECK constraints immediately below.
In `@README.md`:
- Around line 306-307: Update the migration repair guidance in README.md lines
306-307 to refer to the offending persisted prompt or maxTokens value,
instructing operators to edit that value or remove its field rather than
referring to a persisted key. Apply the equivalent wording in README.ja.md lines
317-318, such as directing operators to fix the violating persisted value or
delete the relevant field.
---
Outside diff comments:
In `@services/haru-server/src/reconciler/steps.ts`:
- Around line 447-453: Replace the inline expectedModels Set construction in the
reconciler step with the existing configuredInferenceModelNames(domain) helper.
Keep the resulting set semantics and routing-safety behavior unchanged, and do
not duplicate the slot/model derivation logic.
🪄 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: ASSERTIVE
Plan: Pro Plus
Run ID: a6adc4c7-2ff1-43b1-b098-32344535f0a2
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (43)
AGENTS.mdREADME.ja.mdREADME.mdpackage.jsonpackages/db/drizzle/0003_dazzling_may_parker.sqlpackages/db/drizzle/meta/0003_snapshot.jsonpackages/db/drizzle/meta/_journal.jsonpackages/db/src/cas.test.tspackages/db/src/migration-preflight.test.tspackages/db/src/operations.test.tspackages/db/src/persistence-invariants.test.tspackages/db/src/repo/fleets.tspackages/db/src/repo/operations.tspackages/db/src/repo/snapshots.tspackages/db/src/schema/domains.tspackages/db/src/schema/fleet-topology.tspackages/db/src/schema/fleets.tspackages/db/src/schema/operations.tspackages/db/src/schema/slots.tspackages/db/vitest.config.tspackages/protocol/schemas/fleet-layout.schema.jsonpackages/protocol/src/fleet-snapshot-invariants.test.tspackages/protocol/src/fleet.tspackages/protocol/src/json-schema.test.tspackages/protocol/src/json-schema.tspackages/protocol/src/policy.tspackages/protocol/src/protocol.test.tspackages/protocol/src/supervisor.tspnpm-workspace.yamlservices/haru-server/src/app.tsservices/haru-server/src/chat-proxy.tsservices/haru-server/src/chat.test.tsservices/haru-server/src/fake-supervisor.test-helper.tsservices/haru-server/src/promotion-flow.test.tsservices/haru-server/src/reconciler/reconciler.tsservices/haru-server/src/reconciler/steps.tsservices/haru-server/src/supervisor-client.test.tsservices/haru-server/src/supervisor-client.tsservices/haru-server/vitest.config.tsservices/haru-supervisor/src/app.test.tsservices/haru-supervisor/src/app.tsservices/haru-supervisor/src/probe.tsservices/haru-supervisor/src/vllm-client.ts
📜 Review details
⏰ Context from checks skipped due to timeout. (1)
- GitHub Check: check
🧰 Additional context used
📓 Path-based instructions (17)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Keep new I/O behind injectable boundaries so it can be tested without GPUs, cloud accounts, or a running database.
新しい I/O は注入可能な境界の背後に配置し、外部実行、fetch、子プロセス、タイマーなどをテストダブルに置き換えられるようにする。
**/*.{ts,tsx}: Respect the dependency graph:@haru/protocolhas no workspace dependencies beyond permitted built-ins,@haru/coreis pure and performs no I/O,@haru/dbdepends on core,services/haru-supervisordepends only on protocol, and shared server/supervisor functionality belongs in protocol.
Build outbound URLs withjoinUrlfrom@haru/protocol; do not usenew URL('/path', base)when the base may contain a path prefix.
Use English comments and avoid the em dash character (U+2014) in code and prose.
Files:
packages/db/src/migration-preflight.test.tspackages/db/src/schema/domains.tspackages/db/src/operations.test.tspackages/protocol/src/json-schema.test.tspackages/db/src/schema/fleets.tspackages/db/src/schema/fleet-topology.tspackages/db/src/schema/slots.tsservices/haru-supervisor/src/probe.tspackages/protocol/src/json-schema.tspackages/db/src/repo/operations.tspackages/protocol/src/fleet-snapshot-invariants.test.tsservices/haru-server/src/chat-proxy.tsservices/haru-server/vitest.config.tsservices/haru-server/src/supervisor-client.test.tspackages/db/src/cas.test.tspackages/protocol/src/policy.tspackages/db/src/repo/fleets.tspackages/db/src/persistence-invariants.test.tspackages/db/vitest.config.tspackages/db/src/schema/operations.tspackages/db/src/repo/snapshots.tspackages/protocol/src/fleet.tsservices/haru-server/src/promotion-flow.test.tspackages/protocol/src/protocol.test.tsservices/haru-server/src/reconciler/reconciler.tsservices/haru-server/src/app.tsservices/haru-supervisor/src/vllm-client.tsservices/haru-server/src/fake-supervisor.test-helper.tsservices/haru-server/src/reconciler/steps.tsservices/haru-supervisor/src/app.test.tspackages/protocol/src/supervisor.tsservices/haru-server/src/supervisor-client.tsservices/haru-supervisor/src/app.tsservices/haru-server/src/chat.test.ts
**/*.{test,spec}.{ts,tsx}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Add a Vitest case next to changed code when introducing or modifying behavior.
変更したコードの近くに Vitest のテストを追加し、外部 I/O は注入可能な境界に対してテストする。
Files:
packages/db/src/migration-preflight.test.tspackages/db/src/operations.test.tspackages/protocol/src/json-schema.test.tspackages/protocol/src/fleet-snapshot-invariants.test.tsservices/haru-server/src/supervisor-client.test.tspackages/db/src/cas.test.tspackages/db/src/persistence-invariants.test.tsservices/haru-server/src/promotion-flow.test.tspackages/protocol/src/protocol.test.tsservices/haru-supervisor/src/app.test.tsservices/haru-server/src/chat.test.ts
**/*.{ts,tsx,js,jsx,json,md,yml,yaml}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Use oxfmt as the owner of formatting, including whitespace, wrapping, quotes, and trailing commas; do not hand-tune formatting for ESLint.
Files:
packages/db/src/migration-preflight.test.tspackage.jsonpackages/db/src/schema/domains.tsREADME.mdpackages/db/src/operations.test.tspackages/protocol/src/json-schema.test.tspackages/protocol/schemas/fleet-layout.schema.jsonAGENTS.mdpackages/db/src/schema/fleets.tsREADME.ja.mdpackages/db/drizzle/meta/_journal.jsonpackages/db/src/schema/fleet-topology.tspnpm-workspace.yamlpackages/db/src/schema/slots.tsservices/haru-supervisor/src/probe.tspackages/protocol/src/json-schema.tspackages/db/src/repo/operations.tspackages/protocol/src/fleet-snapshot-invariants.test.tsservices/haru-server/src/chat-proxy.tsservices/haru-server/vitest.config.tsservices/haru-server/src/supervisor-client.test.tspackages/db/src/cas.test.tspackages/protocol/src/policy.tspackages/db/src/repo/fleets.tspackages/db/src/persistence-invariants.test.tspackages/db/vitest.config.tspackages/db/src/schema/operations.tspackages/db/src/repo/snapshots.tspackages/protocol/src/fleet.tsservices/haru-server/src/promotion-flow.test.tspackages/protocol/src/protocol.test.tsservices/haru-server/src/reconciler/reconciler.tsservices/haru-server/src/app.tsservices/haru-supervisor/src/vllm-client.tsservices/haru-server/src/fake-supervisor.test-helper.tspackages/db/drizzle/meta/0003_snapshot.jsonservices/haru-server/src/reconciler/steps.tsservices/haru-supervisor/src/app.test.tspackages/protocol/src/supervisor.tsservices/haru-server/src/supervisor-client.tsservices/haru-supervisor/src/app.tsservices/haru-server/src/chat.test.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Run both root-configured linters,
oxlint --type-awarefollowed by strict type-aware ESLint 10; add overrides at the repository root rather than per-package configs.
**/*.{ts,tsx,js,jsx}: oxlint の型認識 lint を実行した後、型情報ベースの strict ESLint 10 を実行する。設定はパッケージごとではなくリポジトリルートに置き、例外には理由をコメントしたスコープ付きオーバーライドを優先する。
コード内のコメントは英語で記述する。
Files:
packages/db/src/migration-preflight.test.tspackages/db/src/schema/domains.tspackages/db/src/operations.test.tspackages/protocol/src/json-schema.test.tspackages/db/src/schema/fleets.tspackages/db/src/schema/fleet-topology.tspackages/db/src/schema/slots.tsservices/haru-supervisor/src/probe.tspackages/protocol/src/json-schema.tspackages/db/src/repo/operations.tspackages/protocol/src/fleet-snapshot-invariants.test.tsservices/haru-server/src/chat-proxy.tsservices/haru-server/vitest.config.tsservices/haru-server/src/supervisor-client.test.tspackages/db/src/cas.test.tspackages/protocol/src/policy.tspackages/db/src/repo/fleets.tspackages/db/src/persistence-invariants.test.tspackages/db/vitest.config.tspackages/db/src/schema/operations.tspackages/db/src/repo/snapshots.tspackages/protocol/src/fleet.tsservices/haru-server/src/promotion-flow.test.tspackages/protocol/src/protocol.test.tsservices/haru-server/src/reconciler/reconciler.tsservices/haru-server/src/app.tsservices/haru-supervisor/src/vllm-client.tsservices/haru-server/src/fake-supervisor.test-helper.tsservices/haru-server/src/reconciler/steps.tsservices/haru-supervisor/src/app.test.tspackages/protocol/src/supervisor.tsservices/haru-server/src/supervisor-client.tsservices/haru-supervisor/src/app.tsservices/haru-server/src/chat.test.ts
**/*
📄 CodeRabbit inference engine (CONTRIBUTING.md)
**/*: Use kebab-case for file names.
Write comments in English.
Do not use the em dash character (U+2014) in code or prose; use a colon, comma, parentheses, or spaced hyphen instead.ファイル名は kebab-case にする。
Keep the repository publishable: do not reference consumer-private repositories or infrastructure, and do not include specific model or GPU names in code, seeds, or example layouts.
Files:
packages/db/src/migration-preflight.test.tspackage.jsonpackages/db/src/schema/domains.tsREADME.mdpackages/db/src/operations.test.tspackages/protocol/src/json-schema.test.tspackages/protocol/schemas/fleet-layout.schema.jsonAGENTS.mdpackages/db/src/schema/fleets.tsREADME.ja.mdpackages/db/drizzle/meta/_journal.jsonpackages/db/src/schema/fleet-topology.tspnpm-workspace.yamlpackages/db/src/schema/slots.tsservices/haru-supervisor/src/probe.tspackages/protocol/src/json-schema.tspackages/db/src/repo/operations.tspackages/db/drizzle/0003_dazzling_may_parker.sqlpackages/protocol/src/fleet-snapshot-invariants.test.tsservices/haru-server/src/chat-proxy.tsservices/haru-server/vitest.config.tsservices/haru-server/src/supervisor-client.test.tspackages/db/src/cas.test.tspackages/protocol/src/policy.tspackages/db/src/repo/fleets.tspackages/db/src/persistence-invariants.test.tspackages/db/vitest.config.tspackages/db/src/schema/operations.tspackages/db/src/repo/snapshots.tspackages/protocol/src/fleet.tsservices/haru-server/src/promotion-flow.test.tspackages/protocol/src/protocol.test.tsservices/haru-server/src/reconciler/reconciler.tsservices/haru-server/src/app.tsservices/haru-supervisor/src/vllm-client.tsservices/haru-server/src/fake-supervisor.test-helper.tspackages/db/drizzle/meta/0003_snapshot.jsonservices/haru-server/src/reconciler/steps.tsservices/haru-supervisor/src/app.test.tspackages/protocol/src/supervisor.tsservices/haru-server/src/supervisor-client.tsservices/haru-supervisor/src/app.tsservices/haru-server/src/chat.test.ts
packages/db/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Test
@haru/dbagainst in-memory PGlite using the committed Drizzle migrations, including compare-and-swap SQL and concurrent-winner races.状態ストアの状態遷移では、compare-and-swap SQL によって並行実行時の勝者決定レースを保護する。
Files:
packages/db/src/migration-preflight.test.tspackages/db/src/schema/domains.tspackages/db/src/operations.test.tspackages/db/src/schema/fleets.tspackages/db/src/schema/fleet-topology.tspackages/db/src/schema/slots.tspackages/db/src/repo/operations.tspackages/db/src/cas.test.tspackages/db/src/repo/fleets.tspackages/db/src/persistence-invariants.test.tspackages/db/vitest.config.tspackages/db/src/schema/operations.tspackages/db/src/repo/snapshots.ts
**/*.{ts,tsx,js,jsx,json,md,yaml,yml}
📄 CodeRabbit inference engine (CONTRIBUTING.ja.md)
oxfmt を使用して、空白、折り返し、クォート、末尾カンマを整形する。整形確認には
pnpm format:checkを使用する。
Files:
packages/db/src/migration-preflight.test.tspackage.jsonpackages/db/src/schema/domains.tsREADME.mdpackages/db/src/operations.test.tspackages/protocol/src/json-schema.test.tspackages/protocol/schemas/fleet-layout.schema.jsonAGENTS.mdpackages/db/src/schema/fleets.tsREADME.ja.mdpackages/db/drizzle/meta/_journal.jsonpackages/db/src/schema/fleet-topology.tspnpm-workspace.yamlpackages/db/src/schema/slots.tsservices/haru-supervisor/src/probe.tspackages/protocol/src/json-schema.tspackages/db/src/repo/operations.tspackages/protocol/src/fleet-snapshot-invariants.test.tsservices/haru-server/src/chat-proxy.tsservices/haru-server/vitest.config.tsservices/haru-server/src/supervisor-client.test.tspackages/db/src/cas.test.tspackages/protocol/src/policy.tspackages/db/src/repo/fleets.tspackages/db/src/persistence-invariants.test.tspackages/db/vitest.config.tspackages/db/src/schema/operations.tspackages/db/src/repo/snapshots.tspackages/protocol/src/fleet.tsservices/haru-server/src/promotion-flow.test.tspackages/protocol/src/protocol.test.tsservices/haru-server/src/reconciler/reconciler.tsservices/haru-server/src/app.tsservices/haru-supervisor/src/vllm-client.tsservices/haru-server/src/fake-supervisor.test-helper.tspackages/db/drizzle/meta/0003_snapshot.jsonservices/haru-server/src/reconciler/steps.tsservices/haru-supervisor/src/app.test.tspackages/protocol/src/supervisor.tsservices/haru-server/src/supervisor-client.tsservices/haru-supervisor/src/app.tsservices/haru-server/src/chat.test.ts
**/*.{ts,tsx,js,jsx,md}
📄 CodeRabbit inference engine (CONTRIBUTING.ja.md)
コードと文章ではエムダッシュ (U+2014) を使用せず、コロン、コンマ、括弧、またはスペース付きハイフンを使用する。
Files:
packages/db/src/migration-preflight.test.tspackages/db/src/schema/domains.tsREADME.mdpackages/db/src/operations.test.tspackages/protocol/src/json-schema.test.tsAGENTS.mdpackages/db/src/schema/fleets.tsREADME.ja.mdpackages/db/src/schema/fleet-topology.tspackages/db/src/schema/slots.tsservices/haru-supervisor/src/probe.tspackages/protocol/src/json-schema.tspackages/db/src/repo/operations.tspackages/protocol/src/fleet-snapshot-invariants.test.tsservices/haru-server/src/chat-proxy.tsservices/haru-server/vitest.config.tsservices/haru-server/src/supervisor-client.test.tspackages/db/src/cas.test.tspackages/protocol/src/policy.tspackages/db/src/repo/fleets.tspackages/db/src/persistence-invariants.test.tspackages/db/vitest.config.tspackages/db/src/schema/operations.tspackages/db/src/repo/snapshots.tspackages/protocol/src/fleet.tsservices/haru-server/src/promotion-flow.test.tspackages/protocol/src/protocol.test.tsservices/haru-server/src/reconciler/reconciler.tsservices/haru-server/src/app.tsservices/haru-supervisor/src/vllm-client.tsservices/haru-server/src/fake-supervisor.test-helper.tsservices/haru-server/src/reconciler/steps.tsservices/haru-supervisor/src/app.test.tspackages/protocol/src/supervisor.tsservices/haru-server/src/supervisor-client.tsservices/haru-supervisor/src/app.tsservices/haru-server/src/chat.test.ts
packages/db/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
packages/db/src/**/*.{ts,tsx}: Implement every database state transition as a single-statement compare-and-swap with guarded predicates and row-count checking. Never usedb.transaction()or perform external work between a read and its dependent write.
Keep core state tables as the single source of truth and have repositories reject invalid(from, to)transitions withInvalidTransitionError.
UsecreateTestDatabasewith committed migrations and do not add per-test migration calls.
Files:
packages/db/src/migration-preflight.test.tspackages/db/src/schema/domains.tspackages/db/src/operations.test.tspackages/db/src/schema/fleets.tspackages/db/src/schema/fleet-topology.tspackages/db/src/schema/slots.tspackages/db/src/repo/operations.tspackages/db/src/cas.test.tspackages/db/src/repo/fleets.tspackages/db/src/persistence-invariants.test.tspackages/db/src/schema/operations.tspackages/db/src/repo/snapshots.ts
**/*.test.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Inject all I/O including fetch, exec, spawn, and clocks. Server tests should use
app.request()with scripted fake supervisors; supervisor signal escalation tests should use fake timers.
Files:
packages/db/src/migration-preflight.test.tspackages/db/src/operations.test.tspackages/protocol/src/json-schema.test.tspackages/protocol/src/fleet-snapshot-invariants.test.tsservices/haru-server/src/supervisor-client.test.tspackages/db/src/cas.test.tspackages/db/src/persistence-invariants.test.tsservices/haru-server/src/promotion-flow.test.tspackages/protocol/src/protocol.test.tsservices/haru-supervisor/src/app.test.tsservices/haru-server/src/chat.test.ts
**/package.json
📄 CodeRabbit inference engine (AGENTS.md)
Resolve direct third-party dependencies through the
catalog:inpnpm-workspace.yaml; keep workspace links asworkspace:*.
Files:
package.json
{README.md,README.ja.md,CONTRIBUTING.md,CONTRIBUTING.ja.md,KNOWN_ISSUES.md,KNOWN_ISSUES.ja.md}
📄 CodeRabbit inference engine (AGENTS.md)
Maintain English/Japanese documentation pairs together; update the corresponding translation when editing one side, and record new reviewed deferrals in both
KNOWN_ISSUESfiles.
Files:
README.mdREADME.ja.md
pnpm-workspace.yaml
📄 CodeRabbit inference engine (AGENTS.md)
Do not weaken supply-chain protections such as
minimumReleaseAge,trustPolicy,blockExoticSubdeps, orallowBuilds, and do not addtrustPolicyExcludeentries autonomously.
Files:
pnpm-workspace.yaml
services/haru-supervisor/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Test supervisor behavior with fake fetch, fake child-process handles, and fake timers, including SIGTERM-to-grace-period-to-SIGKILL escalation.
スーパーバイザーのプロセス終了処理では、SIGTERM を送信し、猶予期間後に SIGKILL へエスカレーションする挙動をテストする。
Files:
services/haru-supervisor/src/probe.tsservices/haru-supervisor/src/vllm-client.tsservices/haru-supervisor/src/app.test.tsservices/haru-supervisor/src/app.ts
services/haru-supervisor/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Training child processes must register both
exitanderrorhandlers onChildHandle; spawn failures emiterrorwithoutexit.
Files:
services/haru-supervisor/src/probe.tsservices/haru-supervisor/src/vllm-client.tsservices/haru-supervisor/src/app.test.tsservices/haru-supervisor/src/app.ts
services/haru-server/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Run server suites against in-memory PGlite with committed Drizzle migrations so compare-and-swap SQL guarding state transitions is exercised, including concurrent-winner races.
Files:
services/haru-server/src/chat-proxy.tsservices/haru-server/vitest.config.tsservices/haru-server/src/supervisor-client.test.tsservices/haru-server/src/promotion-flow.test.tsservices/haru-server/src/reconciler/reconciler.tsservices/haru-server/src/app.tsservices/haru-server/src/fake-supervisor.test-helper.tsservices/haru-server/src/reconciler/steps.tsservices/haru-server/src/supervisor-client.tsservices/haru-server/src/chat.test.ts
services/haru-server/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
services/haru-server/src/**/*.{ts,tsx}: Usefleets.activeDomainIdas the sole routing pointer;switchActiveis the only writer and must atomically commit routing and the driving operation’sroutingCommittedstate.
The reconciler must be re-entrant and check-and-nudge based: issue at most one step nudge per tick, make executors safe to rerun, and apply executor outcomes and timeouts through the single CAS-and-audit pathapplyStepResolution.
Use the injected application clock forstepStartedAtanddomains.stateUpdatedAt; do not replace it withsqlnow()``.
Map supervisor failures throughwithSupervisor: target-domain 401/403 responses fail immediately, other failures remain pending until the policy budget expires, and best-effort source steps treat authentication failures as pending. Keep response parsing inside SupervisorError wrapping.
Degraded escalation must remain guarded by policy settings, a viable standby, no in-flight operation, and the active routing pointer; all guards belong inside the escalation UPDATE. Recovery of failed active domains must verify every LAYOUT-bound model is served.
Completion checks over supervisor-reported lists must require `length > 0 && every(...)`; never allow an empty list to vacuously succeed.
Keep the data path fail-open and the control path fail-closed. Serve only the last cached snapshot when the pointer read fails; after a successful pointer read, fail closed on revision movement or malformed state, and serve a cached snapshot only when its revision matches.
`/healthz` must never access the database.
Distinguish a pointer lookup returning `null` from throwing: `null` means the fleet is gone and may be forgotten; a thrown lookup means the store is unavailable and the cache entry must be retained.
Use case-insensitive lowercase identity only for UUID fleet IDs; keep slugs and aliases case-sensitive. Apply the database ID-first resolution rule so UUID-shaped slugs cannot shadow an ID owner.
Do not publish an ove...
Files:
services/haru-server/src/chat-proxy.tsservices/haru-server/src/supervisor-client.test.tsservices/haru-server/src/promotion-flow.test.tsservices/haru-server/src/reconciler/reconciler.tsservices/haru-server/src/app.tsservices/haru-server/src/fake-supervisor.test-helper.tsservices/haru-server/src/reconciler/steps.tsservices/haru-server/src/supervisor-client.tsservices/haru-server/src/chat.test.ts
🪛 ast-grep (0.44.1)
packages/db/src/migration-preflight.test.ts
[error] 32-47: Avoid SQL injection
Context: client.query(
INSERT INTO fleets (slug, policy) VALUES ($1, $2::jsonb), ($3, $4::jsonb),
[
"oversized-prompt",
JSON.stringify({
probe: {
prompt: "x".repeat(MAX_PROBE_PROMPT_CODE_POINTS + 1),
},
}),
"oversized-tokens",
JSON.stringify({
probe: { maxTokens: MAX_PROBE_TOKENS + 1 },
}),
],
)
Note: [CWE-89] Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection').
(sql-injection-typescript)
🪛 OpenGrep (1.25.0)
packages/db/src/migration-preflight.test.ts
[ERROR] 17-17: Dynamic command passed to child_process.exec/execSync. Use child_process.execFile or spawn with an argument array instead.
(coderabbit.command-injection.exec-js)
[ERROR] 52-52: Dynamic command passed to child_process.exec/execSync. Use child_process.execFile or spawn with an argument array instead.
(coderabbit.command-injection.exec-js)
[ERROR] 70-70: Dynamic command passed to child_process.exec/execSync. Use child_process.execFile or spawn with an argument array instead.
(coderabbit.command-injection.exec-js)
🪛 SQLFluff (4.2.2)
packages/db/drizzle/0003_dazzling_may_parker.sql
[error] 81-81: ADD CONSTRAINT ... FOREIGN KEY should use NOT VALID to avoid locking the table while validating existing rows.
(PG01)
[error] 82-82: ADD CONSTRAINT ... FOREIGN KEY should use NOT VALID to avoid locking the table while validating existing rows.
(PG01)
[error] 83-83: ADD CONSTRAINT ... FOREIGN KEY should use NOT VALID to avoid locking the table while validating existing rows.
(PG01)
🔇 Additional comments (44)
package.json (1)
45-45: LGTM!pnpm-workspace.yaml (1)
16-16: LGTM!packages/db/vitest.config.ts (1)
10-13: LGTM!services/haru-server/vitest.config.ts (1)
10-12: LGTM!packages/protocol/schemas/fleet-layout.schema.json (1)
85-91: LGTM!packages/protocol/src/policy.ts (1)
12-44: LGTM!packages/protocol/src/json-schema.ts (1)
4-48: LGTM!packages/protocol/src/json-schema.test.ts (1)
66-89: LGTM!packages/protocol/src/fleet.ts (1)
128-218: LGTM!packages/protocol/src/protocol.test.ts (1)
126-166: LGTM!Also applies to: 243-330, 584-643
packages/db/drizzle/0003_dazzling_may_parker.sql (1)
1-74: LGTM!packages/db/src/migration-preflight.test.ts (1)
1-97: LGTM!packages/db/src/repo/snapshots.ts (1)
1-1: LGTM!Also applies to: 146-192
packages/db/src/operations.test.ts (1)
100-119: LGTM!packages/db/src/persistence-invariants.test.ts (1)
1-188: LGTM!packages/protocol/src/fleet-snapshot-invariants.test.ts (1)
1-115: LGTM!packages/db/src/schema/fleet-topology.ts (1)
1-136: LGTM!packages/db/src/schema/domains.ts (1)
1-2: LGTM!packages/db/src/schema/fleets.ts (1)
1-2: LGTM!packages/db/src/schema/operations.ts (1)
4-4: LGTM!Also applies to: 29-36, 63-82
packages/db/src/schema/slots.ts (1)
1-1: LGTM!Also applies to: 19-28, 56-59
packages/db/drizzle/meta/0003_snapshot.json (1)
1-653: LGTM!packages/db/drizzle/meta/_journal.json (1)
25-31: LGTM!packages/db/src/repo/fleets.ts (1)
3-3: LGTM!Also applies to: 41-53, 76-84
packages/db/src/repo/operations.ts (1)
56-87: LGTM!packages/db/src/cas.test.ts (1)
2-10: LGTM!Also applies to: 61-78, 124-177, 612-631
services/haru-server/src/app.ts (2)
169-175: LGTM!Also applies to: 195-221, 358-362, 387-395
625-625: LGTM!Also applies to: 820-832, 875-875
services/haru-server/src/chat.test.ts (3)
9-9: LGTM!Also applies to: 39-52, 76-94
124-179: LGTM!Also applies to: 593-682
877-877: LGTM!Also applies to: 909-909, 993-993, 1025-1025, 1057-1057, 1092-1092, 1134-1134, 1157-1157, 1275-1319, 1388-1388, 1422-1422
AGENTS.md (1)
143-145: LGTM!services/haru-server/src/chat-proxy.ts (1)
35-42: LGTM!Also applies to: 61-61
services/haru-server/src/fake-supervisor.test-helper.ts (1)
201-221: LGTM!Also applies to: 250-254
services/haru-server/src/promotion-flow.test.ts (1)
266-268: LGTM!Also applies to: 279-279
packages/protocol/src/supervisor.ts (1)
4-35: LGTM!Also applies to: 46-63, 188-209, 227-238
services/haru-server/src/supervisor-client.ts (1)
6-8: LGTM!Also applies to: 47-54, 97-158, 181-204, 227-249
services/haru-server/src/supervisor-client.test.ts (1)
71-99: LGTM!Also applies to: 101-129, 131-167
services/haru-supervisor/src/app.ts (1)
3-16: LGTM!Also applies to: 24-52, 66-97, 158-210, 212-256, 434-508
services/haru-supervisor/src/probe.ts (1)
25-25: LGTM!Also applies to: 43-43
services/haru-supervisor/src/vllm-client.ts (1)
11-15: LGTM!Also applies to: 30-52, 101-113
services/haru-server/src/reconciler/reconciler.ts (1)
26-34: LGTM!Also applies to: 220-228
services/haru-server/src/reconciler/steps.ts (1)
212-224: LGTM!Also applies to: 247-252, 324-327, 404-407, 554-557, 585-588, 621-624, 656-659
services/haru-supervisor/src/app.test.ts (1)
1-6: LGTM!Also applies to: 114-162, 248-303, 305-335, 541-579, 612-693
| ALTER TABLE "fleets" ADD CONSTRAINT "fleets_active_domain_membership_fk" FOREIGN KEY ("id","active_domain_id") REFERENCES "public"."domains"("fleet_id","id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint | ||
| ALTER TABLE "operations" ADD CONSTRAINT "operations_target_domain_membership_fk" FOREIGN KEY ("fleet_id","target_domain_id") REFERENCES "public"."domains"("fleet_id","id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint | ||
| ALTER TABLE "operations" ADD CONSTRAINT "operations_source_domain_membership_fk" FOREIGN KEY ("fleet_id","source_domain_id") REFERENCES "public"."domains"("fleet_id","id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint |
There was a problem hiding this comment.
🩺 Stability & Availability | 🔵 Trivial
Consider NOT VALID + a follow-up VALIDATE CONSTRAINT for the composite FKs.
The plain ADD CONSTRAINT ... FOREIGN KEY takes an ACCESS EXCLUSIVE lock on the referencing table and performs a full validating scan. The preflight DO $$ block above has already proven every referencing row satisfies these relationships, so the validating scan here is redundant lock time. Adding the FK NOT VALID (constraint still enforces all new writes immediately) and running VALIDATE CONSTRAINT separately (which takes only SHARE UPDATE EXCLUSIVE) shortens the exclusive-lock window during rollout. The same applies to the CHECK constraints on lines 84-85. Given these are small control-plane tables the impact is modest, so treat this as a rollout hygiene improvement rather than a blocker.
🧰 Tools
🪛 SQLFluff (4.2.2)
[error] 81-81: ADD CONSTRAINT ... FOREIGN KEY should use NOT VALID to avoid locking the table while validating existing rows.
(PG01)
[error] 82-82: ADD CONSTRAINT ... FOREIGN KEY should use NOT VALID to avoid locking the table while validating existing rows.
(PG01)
[error] 83-83: ADD CONSTRAINT ... FOREIGN KEY should use NOT VALID to avoid locking the table while validating existing rows.
(PG01)
🤖 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 `@packages/db/drizzle/0003_dazzling_may_parker.sql` around lines 81 - 83, The
composite foreign keys fleets_active_domain_membership_fk,
operations_target_domain_membership_fk, and
operations_source_domain_membership_fk should be added with NOT VALID, followed
by separate VALIDATE CONSTRAINT statements to reduce the exclusive-lock window
while preserving enforcement for new writes. Apply the same NOT
VALID-then-VALIDATE approach to the CHECK constraints immediately below.
Source: Linters/SAST tools
| existing value above either limit. Shorten, lower, or remove the | ||
| offending persisted key before upgrading; re-applying a layout does |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Describe the migration repair target as a persisted value or field, not a key.
README.md#L306-L307: Tell operators to edit the offendingpromptormaxTokensvalue, or remove that field.README.ja.md#L317-L318: Use wording such as違反している保存済みの値を修正するか、該当フィールドを削除してください。
📍 Affects 2 files
README.md#L306-L307(this comment)README.ja.md#L317-L318
🤖 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 `@README.md` around lines 306 - 307, Update the migration repair guidance in
README.md lines 306-307 to refer to the offending persisted prompt or maxTokens
value, instructing operators to edit that value or remove its field rather than
referring to a persisted key. Apply the equivalent wording in README.ja.md lines
317-318, such as directing operators to fix the violating persisted value or
delete the relevant field.
Greptile SummaryThis PR hardens fleet control, routing, and supervisor boundaries. The main changes are:
Confidence Score: 5/5This looks safe to merge after a small memory-bounding cleanup.
services/haru-server/src/app.ts
|
| Filename | Overview |
|---|---|
| services/haru-server/src/app.ts | Adds raw-body handling and race-safe snapshot caching, but the new reference-generation map has no eviction policy. |
| services/haru-server/src/chat-proxy.ts | Forwards the original chat request bytes without reserializing the payload. |
| packages/db/drizzle/0003_dazzling_may_parker.sql | Adds preflight checks and database constraints for ownership, slot states, and probe limits. |
| packages/db/src/repo/fleets.ts | Restricts active-domain changes to same-fleet targets and the exact authorized promotion step. |
| packages/db/src/repo/operations.ts | Creates operations through an ownership-scoped insert that captures the source pointer atomically. |
| packages/db/src/repo/snapshots.ts | Rejects malformed slot kind and state combinations at the persistence read boundary. |
| services/haru-server/src/supervisor-client.ts | Adds model selectors and separates inner work timeouts from outer response budgets. |
| services/haru-supervisor/src/app.ts | Adds request limits, model filtering, timeout compatibility, and cancellation propagation. |
| packages/protocol/src/policy.ts | Centralizes probe prompt and token limits using Unicode code-point semantics. |
| packages/protocol/src/fleet.ts | Validates snapshot ownership, uniqueness, and active-domain relationships. |
Sequence Diagram
%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant Client
participant Server as haru-server
participant Cache as Routing cache
participant DB
participant Supervisor
participant VLLM
Client->>Server: Authenticated chat request
Server->>DB: Read route pointer
Server->>Cache: Check revisioned snapshot
alt Snapshot missing or stale
Server->>DB: Coalesced snapshot load
DB-->>Server: Validated snapshot
Server->>Cache: Publish if generation is current
end
Server->>Supervisor: Status or probe for selected models
Supervisor->>VLLM: Bounded cancellable request
Supervisor-->>Server: Model result
Server->>VLLM: Forward original chat bytes
VLLM-->>Client: Stream completion
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant Client
participant Server as haru-server
participant Cache as Routing cache
participant DB
participant Supervisor
participant VLLM
Client->>Server: Authenticated chat request
Server->>DB: Read route pointer
Server->>Cache: Check revisioned snapshot
alt Snapshot missing or stale
Server->>DB: Coalesced snapshot load
DB-->>Server: Validated snapshot
Server->>Cache: Publish if generation is current
end
Server->>Supervisor: Status or probe for selected models
Supervisor->>VLLM: Bounded cancellable request
Supervisor-->>Server: Model result
Server->>VLLM: Forward original chat bytes
VLLM-->>Client: Stream completion
Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.
---
### Issue 1 of 1
services/haru-server/src/app.ts:168-169
**Reference Generations Grow Without Bound**
Each distinct fleet reference is retained in `referenceVerdictGenerations`, including references that never resolve. An authenticated client can continuously submit unique references, causing this process-wide map to grow for the lifetime of the server and eventually increase memory use without limit.
Reviews (1): Last reviewed commit: "Harden fleet control and routing invaria..." | Re-trigger Greptile
| const forgottenGenerations = new Map<string, number>(); | ||
| // Coalesce ONLY the expensive full-snapshot read. Pointer reads stay |
There was a problem hiding this comment.
Reference Generations Grow Without Bound
Each distinct fleet reference is retained in referenceVerdictGenerations, including references that never resolve. An authenticated client can continuously submit unique references, causing this process-wide map to grow for the lifetime of the server and eventually increase memory use without limit.
Prompt To Fix With AI
This is a comment left during a code review.
Path: services/haru-server/src/app.ts
Line: 168-169
Comment:
**Reference Generations Grow Without Bound**
Each distinct fleet reference is retained in `referenceVerdictGenerations`, including references that never resolve. An authenticated client can continuously submit unique references, causing this process-wide map to grow for the lifetime of the server and eventually increase memory use without limit.
How can I resolve this? If you propose a fix, please make it concise.|
Codex Review: Didn't find any major issues. More of your lovely PRs please. Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
There was a problem hiding this comment.
2 issues found across 44 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="packages/db/src/schema/fleet-topology.ts">
<violation number="1" location="packages/db/src/schema/fleet-topology.ts:85">
P2: A direct DB write can persist non-positive or fractional `probe.maxTokens` (and an empty prompt), then every snapshot read for that fleet fails protocol validation. Extend this persistence check/preflight to enforce the runtime lower bounds and integer/min-length invariants, not only the upper caps.</violation>
</file>
<file name="services/haru-server/src/reconciler/steps.ts">
<violation number="1" location="services/haru-server/src/reconciler/steps.ts:220">
P3: The `probe()` step function builds `expectedModels` using inline flatMap/filter/map over `domain.slots`, which duplicates the exact same logic in the newly extracted `configuredInferenceModelNames()` helper a few lines above. Both traverse slots, filter for `kind === "inference"`, and map to model names. The probe function additionally wraps the result in a `Set` (for `.has()`/`.difference()` operations later), but could reuse the helper for the extraction part.
Consider using `configuredInferenceModelNames(domain)` and converting to a Set: `const modelNames = configuredInferenceModelNames(domain); const expectedModels = new Set(modelNames);` This keeps the inference-model-name extraction in one place.</violation>
</file>
Tip: cubic can generate docs of your entire codebase and keep them up to date. Try it here.
Re-trigger cubic
| // code points, matching JSON Schema maxLength and runtime parsing. | ||
| check( | ||
| "fleets_probe_policy_limits", | ||
| sql`(CASE WHEN jsonb_typeof(${table.policy} #> '{probe,prompt}') = 'string' THEN char_length(${table.policy} #>> '{probe,prompt}') <= ${MAX_PROBE_PROMPT_CODE_POINTS_SQL} ELSE TRUE END) AND (CASE WHEN jsonb_typeof(${table.policy} #> '{probe,maxTokens}') = 'number' THEN (${table.policy} #>> '{probe,maxTokens}')::numeric <= ${MAX_PROBE_TOKENS_SQL} ELSE TRUE END)`, |
There was a problem hiding this comment.
P2: A direct DB write can persist non-positive or fractional probe.maxTokens (and an empty prompt), then every snapshot read for that fleet fails protocol validation. Extend this persistence check/preflight to enforce the runtime lower bounds and integer/min-length invariants, not only the upper caps.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/db/src/schema/fleet-topology.ts, line 85:
<comment>A direct DB write can persist non-positive or fractional `probe.maxTokens` (and an empty prompt), then every snapshot read for that fleet fails protocol validation. Extend this persistence check/preflight to enforce the runtime lower bounds and integer/min-length invariants, not only the upper caps.</comment>
<file context>
@@ -0,0 +1,135 @@
+ // code points, matching JSON Schema maxLength and runtime parsing.
+ check(
+ "fleets_probe_policy_limits",
+ sql`(CASE WHEN jsonb_typeof(${table.policy} #> '{probe,prompt}') = 'string' THEN char_length(${table.policy} #>> '{probe,prompt}') <= ${MAX_PROBE_PROMPT_CODE_POINTS_SQL} ELSE TRUE END) AND (CASE WHEN jsonb_typeof(${table.policy} #> '{probe,maxTokens}') = 'number' THEN (${table.policy} #>> '{probe,maxTokens}')::numeric <= ${MAX_PROBE_TOKENS_SQL} ELSE TRUE END)`,
+ ),
+ // The routing revision only ever increments from its default of 1.
</file context>
| domain: DomainSnapshot, | ||
| ): string[] { | ||
| return domain.slots.flatMap((slot) => | ||
| slot.spec.kind === "inference" |
There was a problem hiding this comment.
P3: The probe() step function builds expectedModels using inline flatMap/filter/map over domain.slots, which duplicates the exact same logic in the newly extracted configuredInferenceModelNames() helper a few lines above. Both traverse slots, filter for kind === "inference", and map to model names. The probe function additionally wraps the result in a Set (for .has()/.difference() operations later), but could reuse the helper for the extraction part.
Consider using configuredInferenceModelNames(domain) and converting to a Set: const modelNames = configuredInferenceModelNames(domain); const expectedModels = new Set(modelNames); This keeps the inference-model-name extraction in one place.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At services/haru-server/src/reconciler/steps.ts, line 220:
<comment>The `probe()` step function builds `expectedModels` using inline flatMap/filter/map over `domain.slots`, which duplicates the exact same logic in the newly extracted `configuredInferenceModelNames()` helper a few lines above. Both traverse slots, filter for `kind === "inference"`, and map to model names. The probe function additionally wraps the result in a `Set` (for `.has()`/`.difference()` operations later), but could reuse the helper for the extraction part.
Consider using `configuredInferenceModelNames(domain)` and converting to a Set: `const modelNames = configuredInferenceModelNames(domain); const expectedModels = new Set(modelNames);` This keeps the inference-model-name extraction in one place.</comment>
<file context>
@@ -209,6 +209,20 @@ const hasNoTrainingSlots = (domain: DomainSnapshot): boolean =>
+ domain: DomainSnapshot,
+): string[] {
+ return domain.slots.flatMap((slot) =>
+ slot.spec.kind === "inference"
+ ? slot.spec.models.map((model) => model.name)
+ : [],
</file context>
Summary
devEnginesWhy
Adversarial review found several boundary cases where cross-fleet identifiers or malformed persisted state could bypass assumptions, concurrent cache loads could publish obsolete knowledge, raw chat payloads could be rewritten during JSON decoding, and mixed-version server/supervisor deployments could shorten timeout budgets or request excessive status data.
Impact
Invalid topology and operation references are now rejected before they can affect routing. Promotion commits require the exact running operation and step. Chat payload bytes and vendor extensions are preserved while malformed UTF-8 fails early. Supervisor calls remain bounded and compatible in either rolling-upgrade direction.
Migration
0003_dazzling_may_parkerintentionally stops when existing topology, slot state, or probe-policy rows violate the new constraints. Operators must repair those rows explicitly before applying the migration.Validation
pnpm format:checkpnpm exec turbo run build typecheck lint --force(21/21 tasks, no cache)pnpm exec turbo run test --force(12/12 tasks, 396 tests, no cache)pnpm schemas:generatewith no resulting diffpnpm db:generatereports no schema changesgit diff --checkSummary by cubic
Locks down fleet control and routing by enforcing ownership/state invariants at the DB and repo layers, preserves byte‑exact chat bodies, and makes supervisor timeouts/model selection safe across rolling upgrades. Adds strict probe-policy bounds and fixes routing-cache races. Addresses ENG-956.
Bug Fixes
@haru/corewith snapshot reads validating drifted rows.@haru/protocol.prompt≤ 8,192 Unicode code points;maxTokens≤ 256.Migration
0003_dazzling_may_parker: it stops if data violates new constraints (cross‑fleet pointers, invalid slot states, or out‑of‑range probe policy). Repair offending rows, then re-run.policy.probe.prompt≤ 8,192 code points andpolicy.probe.maxTokens≤ 256. Re-applying a layout does not update existing policy rows.24.17.0or24.18.0perdevEngines.Written for commit 0f21d86. Summary will update on new commits.
Summary by CodeRabbit
New Features
Bug Fixes
Documentation