@rizom/ops 0.2.0-alpha.346 → 0.2.0-alpha.348

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,29 @@
1
+ import { type JobInfo } from "@brains/job-queue";
2
+ import { z } from "@brains/utils/zod";
3
+ export declare const LEGACY_PROJECTION_JOB_TYPES: readonly ["conversation-memory:project", "skill:project", "swot:derive", "topic:project"];
4
+ export declare const legacyProjectionJobTypeSchema: z.ZodEnum<{
5
+ "conversation-memory:project": "conversation-memory:project";
6
+ "skill:project": "skill:project";
7
+ "swot:derive": "swot:derive";
8
+ "topic:project": "topic:project";
9
+ }>;
10
+ export type LegacyProjectionJobType = z.output<typeof legacyProjectionJobTypeSchema>;
11
+ export declare const LEGACY_PROJECTION_RETIREMENT_REASON = "Retired legacy projection job superseded by scheduler-owned projections";
12
+ export interface RetireLegacyProjectionJobOptions {
13
+ databasePath: string;
14
+ jobId: string;
15
+ jobType: LegacyProjectionJobType;
16
+ confirmation?: string | undefined;
17
+ dryRun?: boolean | undefined;
18
+ now?: (() => number) | undefined;
19
+ }
20
+ export interface RetireLegacyProjectionJobResult {
21
+ databasePath: string;
22
+ job: Pick<JobInfo, "id" | "type" | "status" | "retryCount" | "maxRetries" | "createdAt" | "startedAt" | "completedAt">;
23
+ retired: boolean;
24
+ }
25
+ /**
26
+ * Retire one exact pre-scheduler projection job after proving that no attempt
27
+ * owns it. This is deliberately not a general job cancellation API.
28
+ */
29
+ export declare function retireLegacyProjectionJob(options: RetireLegacyProjectionJobOptions): Promise<RetireLegacyProjectionJobResult>;
@@ -7,6 +7,7 @@ import { type SshKeygen } from "./ssh-key-bootstrap";
7
7
  import type { UserRunner } from "./user-runner";
8
8
  import type { cleanupDirectorySyncStress, runDeployedDirectorySyncStress, verifyDirectorySyncStressAccess } from "./directory-sync-stress-system";
9
9
  import type { cleanupHealthWatchdogSmoke, runHealthWatchdogSmoke } from "./health-watchdog-smoke";
10
+ import type { retireLegacyProjectionJob } from "./legacy-projection-job-recovery";
10
11
  export interface CommandResult {
11
12
  success: boolean;
12
13
  message?: string;
@@ -27,6 +28,7 @@ export interface CommandDependencies extends LoadPilotRegistryOptions {
27
28
  directorySyncStressCleanupRunner?: typeof cleanupDirectorySyncStress | undefined;
28
29
  healthWatchdogSmokeRunner?: typeof runHealthWatchdogSmoke | undefined;
29
30
  healthWatchdogSmokeCleanupRunner?: typeof cleanupHealthWatchdogSmoke | undefined;
31
+ legacyProjectionJobRecoveryRunner?: typeof retireLegacyProjectionJob | undefined;
30
32
  }
31
33
  export declare const globalFlags: FlagDefinitions;
32
34
  export declare const commands: readonly CommandDefinition<CommandDependencies, CommandResult>[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rizom/ops",
3
- "version": "0.2.0-alpha.346",
3
+ "version": "0.2.0-alpha.348",
4
4
  "description": "Operator CLI for managing private brain fleet registry repos",
5
5
  "keywords": [
6
6
  "brains",
@@ -17,12 +17,14 @@
17
17
  },
18
18
  "bugs": "https://github.com/rizom-ai/brains/issues",
19
19
  "dependencies": {
20
+ "@libsql/client": "^0.17.4",
20
21
  "age-encryption": "^0.3.0",
21
22
  "yaml": "^2.9.0"
22
23
  },
23
24
  "devDependencies": {
24
25
  "@brains/deploy-support": "workspace:*",
25
26
  "@brains/eslint-config": "workspace:*",
27
+ "@brains/job-queue": "workspace:*",
26
28
  "@brains/profile": "workspace:*",
27
29
  "@brains/site-composition": "workspace:*",
28
30
  "@brains/test-utils": "workspace:*",
@@ -56,6 +56,27 @@ Files use mode `0600` and the directory uses `0700`. A `.incomplete` directory i
56
56
 
57
57
  These are same-server rollback snapshots, not off-host disaster recovery. There is no normal skip and no automatic restore. Restoration requires separate approval: stop replacement/application processes, recheck the selected snapshot's checksums, preserve the current state, restore databases and exact Git state, then validate health, queues, Git checkpoints, durable export intents, preview, and production output before reopening the target.
58
58
 
59
+ ## Retired projection job recovery
60
+
61
+ A pre-scheduler projection job can remain active after its handler type is retired. Current runtime health reports active job types missing from the finalized execution inventory as degraded. Do not restart repeatedly or relax the snapshot idle gate.
62
+
63
+ Use the recovery command only after read-only evidence proves all of the following for one exact row:
64
+
65
+ - its type is one of the command's fixed legacy projection types;
66
+ - the installed runtime no longer contains that handler;
67
+ - attempt, worker-session, lease, and heartbeat ownership are all absent;
68
+ - no durable progress snapshot or result exists.
69
+
70
+ Preview the exact row first:
71
+
72
+ ```sh
73
+ bunx --package @rizom/ops@<exact-version> brains-ops \
74
+ recover:retire-legacy-projection-job \
75
+ /data/brain-jobs.db <job-id> --type <legacy-type> --dry-run
76
+ ```
77
+
78
+ After separate operator review, replace `--dry-run` with the exact confirmation `--confirm retire:<job-id>`. The command atomically fences against ownership or progress appearing between inspection and retirement, and fails closed if the row changed. It is not a general job cancellation API and cannot retire arbitrary job types. Require operational health and a fully idle queue afterward, then run the unchanged canonical predeploy snapshot and Deploy workflow.
79
+
59
80
  ## Canonical contract crossover maintenance window
60
81
 
61
82
  Do not run this procedure without explicit operator approval. The canonical desired state, canonical `@rizom/ops`, and unified runtime image form one contract and must move or roll back together. Complete `docs/canonical-crossover-record.md` as the approval evidence without adding secret values.