@danypops/papyrus 0.44.6 → 0.44.7

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/package.json +1 -1
  2. package/src/service.ts +19 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@danypops/papyrus",
3
- "version": "0.44.6",
3
+ "version": "0.44.7",
4
4
  "description": "Daemon-backed graph artifacts, evidence-bearing tasks, rules, skills, and native TUI workflows for Pi",
5
5
  "type": "module",
6
6
  "keywords": ["pi-package"],
package/src/service.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { VehicleError } from "@danypops/vehicle-core";
1
2
  import type { VehicleRegistry } from "@danypops/vehicle-server";
2
3
  import { createVehicleHttpApp } from "@danypops/vehicle-server/http";
3
4
  import type { Logger } from "@danypops/vehicle-server/logging";
@@ -22,6 +23,7 @@ import type { CreateArtifactInput } from "./domain/artifact.ts";
22
23
  import type { TaskEventContext } from "./domain/task-event.ts";
23
24
  import type { TaskViewMode } from "./domain/task-scope.ts";
24
25
  import { listInjectableRules } from "./domain-services.ts";
26
+ import { logEvent } from "./log.ts";
25
27
  import { Logs } from "./log-service.ts";
26
28
  import { OperationRegistry } from "./module-registry.ts";
27
29
  import { DISCUSS_OPERATION_NAMES, discussOperations } from "./modules/discuss.ts";
@@ -588,7 +590,23 @@ export function createApp(deps: {
588
590
  return json({ error: "missing or invalid bearer token" }, { status: 401 });
589
591
  }
590
592
  const url = new URL(request.url);
591
- if (url.pathname.startsWith("/vehicle/")) return vehicleApp.fetch(request);
593
+ if (url.pathname.startsWith("/vehicle/")) {
594
+ // Every domain (tasks/docs/rules/discuss/notes/playbooks) is reachable here directly
595
+ // (registry.invoke()), bypassing execute()'s own migrationRequired guard below entirely --
596
+ // a stale schema surfaced as an opaque handler-failed (or worse, a silent wrong answer)
597
+ // the moment a request touched a column/table the old schema never had, instead of the
598
+ // same clear, actionable error execute() already gives. Real incident: restarting the
599
+ // live daemon onto new code without running `papyrus migrate schema` first.
600
+ if (deps.service.schemaState().migrationRequired) {
601
+ logEvent("warn", "vehicle_invoke_blocked_migration_required", { path: url.pathname, schema: deps.service.schemaState() });
602
+ const failure = new VehicleError("migration-required", "database migration required; run `papyrus migrate schema`", {
603
+ category: "unavailable",
604
+ retryable: false,
605
+ }).toFailure();
606
+ return json({ error: failure, operationId: crypto.randomUUID() }, { status: 503 });
607
+ }
608
+ return vehicleApp.fetch(request);
609
+ }
592
610
  if (request.method === "GET" && url.pathname === "/health") {
593
611
  return json({ ok: true, version: VERSION, schema: deps.service.schemaState() });
594
612
  }