fluncle 0.225.0 → 0.227.0

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.
Files changed (2) hide show
  1. package/bin/fluncle.mjs +49 -7
  2. package/package.json +1 -1
package/bin/fluncle.mjs CHANGED
@@ -612,7 +612,7 @@ function parseVersion(version) {
612
612
  var currentVersion;
613
613
  var init_version = __esm(() => {
614
614
  init_output();
615
- currentVersion = "0.225.0".trim() ? "0.225.0".trim() : "0.1.0";
615
+ currentVersion = "0.227.0".trim() ? "0.227.0".trim() : "0.1.0";
616
616
  });
617
617
 
618
618
  // src/update-notifier.ts
@@ -2454,7 +2454,7 @@ function parseVersion2(version) {
2454
2454
  var currentVersion2, latestReleaseUrl = "https://api.github.com/repos/mauricekleine/fluncle/releases/latest";
2455
2455
  var init_version2 = __esm(() => {
2456
2456
  init_output();
2457
- currentVersion2 = "0.225.0".trim() ? "0.225.0".trim() : "0.1.0";
2457
+ currentVersion2 = "0.227.0".trim() ? "0.227.0".trim() : "0.1.0";
2458
2458
  });
2459
2459
 
2460
2460
  // ../../packages/registry/src/index.ts
@@ -3978,6 +3978,23 @@ var init_src = __esm(() => {
3978
3978
  title: "Count check",
3979
3979
  weights: { status: "hidden" }
3980
3980
  },
3981
+ {
3982
+ command: "fluncle admin projections advance --target <public_aggregates|artist_qualification> --action repair --limit 500 --max-steps 4",
3983
+ exposedContent: [
3984
+ "keep the two public projection families converged after cutover with status-gated, bounded repair (--no-agent)"
3985
+ ],
3986
+ kind: "cron",
3987
+ name: "cron.projection-maintenance",
3988
+ operatorNotes: "every 5m with per-firing jitter, run by a rave-02 host systemd timer (docs/agents/hermes/projection-maintenance-timer/). Reads bounded projection status first. A dark shared cutover issues zero repair calls; an open idle cutover also writes nothing. Each affected public family gets at most four sequential repair pages of 500 subjects, with independent failure handling. Public aggregate repair also advances the bounded anchor cursor after marker debt drains. Rebuild, audit, track/crawl repair, and every cutover mutation remain operator-only. Zero LLM tokens; no new secret.",
3989
+ probeConfig: {
3990
+ cadenceMs: 5 * MINUTE_MS,
3991
+ cronName: "fluncle-projection-maintenance",
3992
+ kind: "cron"
3993
+ },
3994
+ statusDescription: "keeps the public catalogue projections caught up",
3995
+ title: "Projection upkeep",
3996
+ weights: { status: "hidden" }
3997
+ },
3981
3998
  {
3982
3999
  command: "fluncle admin reach collect",
3983
4000
  exposedContent: [
@@ -12493,6 +12510,7 @@ var init_admin_projections = __esm(() => {
12493
12510
  tags: ["Admin"]
12494
12511
  }).input(object({
12495
12512
  action: ProjectionStepActionSchema,
12513
+ includeStatus: boolean2().default(true),
12496
12514
  limit: number2().int().min(1).max(PROJECTION_STEP_LIMIT_MAX),
12497
12515
  target: ProjectionTargetSchema
12498
12516
  })).output(object({
@@ -12501,7 +12519,7 @@ var init_admin_projections = __esm(() => {
12501
12519
  ok: literal(true),
12502
12520
  processed: CountSchema,
12503
12521
  scheduled: CountSchema,
12504
- status: ProjectionStatusSchema,
12522
+ status: ProjectionStatusSchema.optional(),
12505
12523
  target: ProjectionTargetSchema
12506
12524
  }));
12507
12525
  setProjectionCutover = oc.route({
@@ -16560,6 +16578,7 @@ var init_admin_operation_receipts2 = __esm(() => {
16560
16578
  // src/commands/admin-projections.ts
16561
16579
  var exports_admin_projections = {};
16562
16580
  __export(exports_admin_projections, {
16581
+ PROJECTION_MAX_STEPS: () => PROJECTION_MAX_STEPS,
16563
16582
  PROJECTION_STEP_LIMIT_MAX: () => PROJECTION_STEP_LIMIT_MAX,
16564
16583
  advanceProjectionCommand: () => advanceProjectionCommand,
16565
16584
  getProjectionStatusCommand: () => getProjectionStatusCommand,
@@ -16567,6 +16586,7 @@ __export(exports_admin_projections, {
16567
16586
  parseProjectionCutover: () => parseProjectionCutover,
16568
16587
  parseProjectionEnabled: () => parseProjectionEnabled,
16569
16588
  parseProjectionLimit: () => parseProjectionLimit,
16589
+ parseProjectionMaxSteps: () => parseProjectionMaxSteps,
16570
16590
  parseProjectionTarget: () => parseProjectionTarget,
16571
16591
  projectionStatusLines: () => projectionStatusLines,
16572
16592
  setProjectionCutoverCommand: () => setProjectionCutoverCommand
@@ -16575,8 +16595,20 @@ async function getProjectionStatusCommand() {
16575
16595
  return adminApiGet("/api/v1/admin/projections/status");
16576
16596
  }
16577
16597
  async function advanceProjectionCommand(input) {
16578
- const { target, ...body } = input;
16579
- return adminApiPost(`/api/v1/admin/projections/${target}/advance`, body);
16598
+ const { maxSteps = 1, target, ...body } = input;
16599
+ const stepBody = maxSteps > 1 ? { ...body, includeStatus: false } : body;
16600
+ let response = await adminApiPost(`/api/v1/admin/projections/${target}/advance`, stepBody);
16601
+ let steps = 1;
16602
+ let processed = response.processed;
16603
+ let scheduled = response.scheduled;
16604
+ while (!response.complete && steps < maxSteps) {
16605
+ response = await adminApiPost(`/api/v1/admin/projections/${target}/advance`, stepBody);
16606
+ steps += 1;
16607
+ processed += response.processed;
16608
+ scheduled += response.scheduled;
16609
+ }
16610
+ const status = response.status ?? (await getProjectionStatusCommand()).status;
16611
+ return { ...response, processed, scheduled, status, steps };
16580
16612
  }
16581
16613
  async function setProjectionCutoverCommand(input) {
16582
16614
  const { enabled, target } = input;
@@ -16595,6 +16627,13 @@ function parseProjectionLimit(value) {
16595
16627
  }
16596
16628
  return limit;
16597
16629
  }
16630
+ function parseProjectionMaxSteps(value) {
16631
+ const maxSteps = Number(value);
16632
+ if (!Number.isSafeInteger(maxSteps) || maxSteps < 1 || maxSteps > PROJECTION_MAX_STEPS) {
16633
+ throw new Error(`--max-steps must be a whole number from 1 through ${PROJECTION_MAX_STEPS}`);
16634
+ }
16635
+ return maxSteps;
16636
+ }
16598
16637
  function parseProjectionTarget(value) {
16599
16638
  if (value !== "artist_qualification" && value !== "crawl_due_work" && value !== "public_aggregates" && value !== "track_due_work") {
16600
16639
  throw new Error("--target must be artist_qualification, crawl_due_work, public_aggregates, or track_due_work");
@@ -16622,6 +16661,7 @@ function projectionStatusLines(status) {
16622
16661
  row("Artist qualification", status.projections.artistQualification, status.cutovers.publicProjections)
16623
16662
  ];
16624
16663
  }
16664
+ var PROJECTION_MAX_STEPS = 100;
16625
16665
  var init_admin_projections2 = __esm(() => {
16626
16666
  init_orpc();
16627
16667
  init_api();
@@ -22156,18 +22196,19 @@ JSON field reference:
22156
22196
  console.log(projections.projectionStatusLines(result.status).join(`
22157
22197
  `));
22158
22198
  });
22159
- adminProjections.command("advance").description("Run one bounded, resumable rebuild, repair, or audit step").requiredOption("--target <target>", "track_due_work, crawl_due_work, public_aggregates, or artist_qualification").requiredOption("--action <action>", "rebuild, repair, or audit").option("--limit <limit>", "Maximum rows or repairs in this request (1-500)", "100").option("--json", "Print the step result and current readiness as JSON", false).action(async (options) => {
22199
+ adminProjections.command("advance").description("Run bounded, resumable rebuild, repair, or audit steps").requiredOption("--target <target>", "track_due_work, crawl_due_work, public_aggregates, or artist_qualification").requiredOption("--action <action>", "rebuild, repair, or audit").option("--limit <limit>", "Maximum rows or repairs in this request (1-500)", "100").option("--max-steps <steps>", "Maximum sequential advance calls (1-100)").option("--json", "Print the aggregate result and current readiness as JSON", false).action(async (options) => {
22160
22200
  const projections = await Promise.resolve().then(() => (init_admin_projections2(), exports_admin_projections));
22161
22201
  const result = await projections.advanceProjectionCommand({
22162
22202
  action: projections.parseProjectionAction(options.action),
22163
22203
  limit: projections.parseProjectionLimit(options.limit),
22204
+ maxSteps: options.maxSteps === undefined ? undefined : projections.parseProjectionMaxSteps(options.maxSteps),
22164
22205
  target: projections.parseProjectionTarget(options.target)
22165
22206
  });
22166
22207
  if (options.json) {
22167
22208
  printJson(result);
22168
22209
  return;
22169
22210
  }
22170
- console.log(`${result.target} ${result.action}: processed ${result.processed}, scheduled ${result.scheduled}, ${result.complete ? "complete" : "more work remains"}.`);
22211
+ console.log(`${result.target} ${result.action}: steps ${result.steps}, processed ${result.processed}, scheduled ${result.scheduled}, ${result.complete ? "complete" : "more work remains"}.`);
22171
22212
  });
22172
22213
  adminProjections.command("set").description("Open or close one readiness-gated projection cutover").requiredOption("--target <target>", "track_due_work, crawl_due_work, or public_projections").requiredOption("--enabled <boolean>", "true opens; false closes unconditionally").option("--json", "Print the stored flag and current readiness as JSON", false).action(async (options) => {
22173
22214
  const projections = await Promise.resolve().then(() => (init_admin_projections2(), exports_admin_projections));
@@ -26061,6 +26102,7 @@ var stringOptions = new Set([
26061
26102
  "--lens",
26062
26103
  "--limit",
26063
26104
  "--max-hop",
26105
+ "--max-steps",
26064
26106
  "--max-overlap",
26065
26107
  "--metrics",
26066
26108
  "--missing-field",
package/package.json CHANGED
@@ -31,5 +31,5 @@
31
31
  "url": "git+https://github.com/mauricekleine/fluncle.git"
32
32
  },
33
33
  "type": "module",
34
- "version": "0.225.0"
34
+ "version": "0.227.0"
35
35
  }