Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1335,6 +1335,12 @@ async function runDaemon(): Promise<void> {
log: (line) => process.stderr.write(`${JSON.stringify({ ts: new Date().toISOString(), ...line })}\n`),
}),
controlOptions: liveControlOptions,
// PRD-018k / NEC-023: gate the WHOLE brood/watch activation on the brood prerequisites, not
// just the describe deps. Brooding is dormant out of the box: without Deep Lake creds AND
// Portkey enabled, resolve() reports zero active projects, so the supervisor auto-broods
// nothing (previously the structural brood — walk/mint/embed — still ran for any bound
// project even with no inference configured, pegging CPU to no purpose).
broodReady: () => broodPrereqs.ready,
Comment on lines +1338 to +1343

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Map the file structure first
ast-grep outline src/cli.ts --view expanded > /tmp/cli_outline.txt
sed -n '1,220p' /tmp/cli_outline.txt

echo '--- snippets around brood prereqs / readiness ---'
rg -n "broodPrereqs|broodReady|resolveCredentials|credentialsWatch\.probe|LiveActiveProjects|credentialsPath|loadDeepLakeCredentials" src/cli.ts

# Print the relevant section with line numbers if file is reasonably sized
nl -ba src/cli.ts | sed -n '1270,1425p'

Repository: legioncodeinc/nectar

Length of output: 6434


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- src/cli.ts around brood wiring ---'
awk 'NR>=1280 && NR<=1405 { printf "%d:%s\n", NR, $0 }' src/cli.ts

echo '--- src/brood-prereqs.ts ---'
awk 'NR>=1 && NR<=220 { printf "%d:%s\n", NR, $0 }' src/brood-prereqs.ts

echo '--- src/hive-graph/live-active-projects.ts ---'
awk 'NR>=1 && NR<=260 { printf "%d:%s\n", NR, $0 }' src/hive-graph/live-active-projects.ts

Repository: legioncodeinc/nectar

Length of output: 23729


Make broodReady live, not boot-time static. LiveActiveProjects.resolve() short-circuits to [] whenever this callback is false, so a daemon that starts before ~/.deeplake/credentials.json exists will never begin brooding after a later login. Recompute the prereqs inside the callback so the no-restart path can flip to ready.

🤖 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 `@src/cli.ts` around lines 1338 - 1343, The brood readiness check is currently
captured as a boot-time static value, so LiveActiveProjects.resolve() can stay
permanently disabled even after credentials appear later. Update the broodReady
callback in cli.ts to recompute the brood prerequisites each time it is invoked
rather than reading broodPrereqs.ready once, so a daemon that starts unready can
become ready without restart.

onError: (err) =>
process.stderr.write(
`nectar daemon: active-project resolve failed (non-fatal): ${err instanceof Error ? err.message : String(err)}\n`,
Expand Down
Binary file modified src/hive-graph/live-active-projects.ts
Binary file not shown.
37 changes: 37 additions & 0 deletions test/live-active-projects.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,43 @@ test("W1-N: a projects.json binding written AFTER boot is picked up on the next
}
});

test("NEC-023: brood prerequisites unmet (no Portkey) => dormant even with credentials + a binding", () => {
const cacheDir = tempDir("nectar-live-cache-");
const stateDir = tempDir("nectar-live-state-");
let broodReady = false;
const live = new LiveActiveProjects({
loadCredentials: () => CREDS,
createStore: () => fakeStore,
buildContext: ({ project }): RunningContext => ({
projectId: project.projectId,
path: project.path,
watcherState: () => "running",
start: async () => {},
stop: async () => {},
}),
controlOptions: { cacheDir, broodingState: { dir: stateDir } },
// The Portkey/creds prereq gate. False => the daemon must NOT auto-brood.
broodReady: () => broodReady,
});

try {
// Credentials resolve AND a project is bound, but Portkey is not enabled
// (broodReady=false) => brooding is dormant out of the box: zero active projects,
// so the supervisor stands up no brood/watch context (the auto-brood-without-Portkey fix).
writeProjectsCache(cacheDir, CREDS.orgId, CREDS.workspaceId, [{ path: "/work/repo-a", projectId: "proj-a" }]);
assert.equal(live.resolve().active.length, 0, "no Portkey => dormant even with a binding present");

// Once the prereqs are satisfied (Portkey configured), the SAME binding activates.
broodReady = true;
const after = live.resolve();
assert.equal(after.active.length, 1, "prereqs satisfied => the binding activates");
assert.equal(after.active[0].projectId, "proj-a");
} finally {
rmSync(cacheDir, { recursive: true, force: true });
rmSync(stateDir, { recursive: true, force: true });
}
});

test("W1-N: with credentials absent the resolver is dormant and fail-soft (empty resolution, factory is a no-op)", async () => {
const cacheDir = tempDir("nectar-live-cache-");
const stateDir = tempDir("nectar-live-state-");
Expand Down
Loading