@things-factory/headless-twin 10.0.19 → 10.1.1
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.
- package/dist-server/engine/canonical-ingest.d.ts +10 -1
- package/dist-server/engine/canonical-ingest.js +110 -33
- package/dist-server/engine/canonical-ingest.js.map +1 -1
- package/dist-server/engine/event-time.d.ts +25 -0
- package/dist-server/engine/event-time.js +98 -0
- package/dist-server/engine/event-time.js.map +1 -0
- package/dist-server/engine/index.d.ts +2 -0
- package/dist-server/engine/index.js +23 -0
- package/dist-server/engine/index.js.map +1 -1
- package/dist-server/engine/ingest-dedupe.d.ts +18 -6
- package/dist-server/engine/ingest-dedupe.js +201 -15
- package/dist-server/engine/ingest-dedupe.js.map +1 -1
- package/dist-server/engine/ingest-health.d.ts +60 -1
- package/dist-server/engine/ingest-health.js +43 -8
- package/dist-server/engine/ingest-health.js.map +1 -1
- package/dist-server/engine/kpi-fold.d.ts +19 -0
- package/dist-server/engine/kpi-fold.js +4 -1
- package/dist-server/engine/kpi-fold.js.map +1 -1
- package/dist-server/engine/kpi-query.js +23 -3
- package/dist-server/engine/kpi-query.js.map +1 -1
- package/dist-server/engine/oee-accumulator.d.ts +35 -2
- package/dist-server/engine/oee-accumulator.js +56 -4
- package/dist-server/engine/oee-accumulator.js.map +1 -1
- package/dist-server/engine/twin-engine.d.ts +72 -3
- package/dist-server/engine/twin-engine.js +118 -5
- package/dist-server/engine/twin-engine.js.map +1 -1
- package/dist-server/index.js +21 -0
- package/dist-server/index.js.map +1 -1
- package/dist-server/migrations/1786600000000-RenameOperatoMesAdapterType.d.ts +5 -0
- package/dist-server/migrations/1786600000000-RenameOperatoMesAdapterType.js +66 -0
- package/dist-server/migrations/1786600000000-RenameOperatoMesAdapterType.js.map +1 -0
- package/dist-server/migrations/1786700000000-AddDispatchRetryColumns.d.ts +5 -0
- package/dist-server/migrations/1786700000000-AddDispatchRetryColumns.js +79 -0
- package/dist-server/migrations/1786700000000-AddDispatchRetryColumns.js.map +1 -0
- package/dist-server/migrations/index.js +5 -1
- package/dist-server/migrations/index.js.map +1 -1
- package/dist-server/routes.js +12 -20
- package/dist-server/routes.js.map +1 -1
- package/dist-server/service/actuation/actuation-advisor.d.ts +60 -0
- package/dist-server/service/actuation/actuation-advisor.js +53 -0
- package/dist-server/service/actuation/actuation-advisor.js.map +1 -0
- package/dist-server/service/actuation/actuation-outcome.d.ts +52 -0
- package/dist-server/service/actuation/actuation-outcome.js +34 -0
- package/dist-server/service/actuation/actuation-outcome.js.map +1 -0
- package/dist-server/service/actuation/actuation-rule-resolver.d.ts +19 -0
- package/dist-server/service/actuation/actuation-rule-resolver.js +161 -0
- package/dist-server/service/actuation/actuation-rule-resolver.js.map +1 -0
- package/dist-server/service/actuation/actuation-rule.d.ts +55 -0
- package/dist-server/service/actuation/actuation-rule.js +130 -0
- package/dist-server/service/actuation/actuation-rule.js.map +1 -0
- package/dist-server/service/actuation/approval-gateway.d.ts +20 -0
- package/dist-server/service/actuation/approval-gateway.js +14 -0
- package/dist-server/service/actuation/approval-gateway.js.map +1 -0
- package/dist-server/service/actuation/catch-up-effects.d.ts +16 -0
- package/dist-server/service/actuation/catch-up-effects.js +120 -0
- package/dist-server/service/actuation/catch-up-effects.js.map +1 -0
- package/dist-server/service/actuation/command-dispatcher.d.ts +206 -8
- package/dist-server/service/actuation/command-dispatcher.js +191 -14
- package/dist-server/service/actuation/command-dispatcher.js.map +1 -1
- package/dist-server/service/actuation/command-store.d.ts +10 -2
- package/dist-server/service/actuation/command-store.js +168 -5
- package/dist-server/service/actuation/command-store.js.map +1 -1
- package/dist-server/service/actuation/dispatch-after-approval.d.ts +11 -0
- package/dist-server/service/actuation/dispatch-after-approval.js +73 -0
- package/dist-server/service/actuation/dispatch-after-approval.js.map +1 -0
- package/dist-server/service/actuation/effect-match.d.ts +53 -0
- package/dist-server/service/actuation/effect-match.js +65 -0
- package/dist-server/service/actuation/effect-match.js.map +1 -0
- package/dist-server/service/actuation/index.d.ts +21 -2
- package/dist-server/service/actuation/index.js +21 -2
- package/dist-server/service/actuation/index.js.map +1 -1
- package/dist-server/service/actuation/retry-plan.d.ts +63 -0
- package/dist-server/service/actuation/retry-plan.js +99 -0
- package/dist-server/service/actuation/retry-plan.js.map +1 -0
- package/dist-server/service/actuation/rule-evaluate.d.ts +127 -0
- package/dist-server/service/actuation/rule-evaluate.js +205 -0
- package/dist-server/service/actuation/rule-evaluate.js.map +1 -0
- package/dist-server/service/actuation/rule-loop.d.ts +5 -0
- package/dist-server/service/actuation/rule-loop.js +156 -0
- package/dist-server/service/actuation/rule-loop.js.map +1 -0
- package/dist-server/service/actuation/rule-runner.d.ts +52 -0
- package/dist-server/service/actuation/rule-runner.js +135 -0
- package/dist-server/service/actuation/rule-runner.js.map +1 -0
- package/dist-server/service/actuation/rule-wiring.d.ts +24 -0
- package/dist-server/service/actuation/rule-wiring.js +80 -0
- package/dist-server/service/actuation/rule-wiring.js.map +1 -0
- package/dist-server/service/actuation/settle-effects.d.ts +21 -0
- package/dist-server/service/actuation/settle-effects.js +101 -0
- package/dist-server/service/actuation/settle-effects.js.map +1 -0
- package/dist-server/service/actuation/sweep-dispatch.d.ts +37 -0
- package/dist-server/service/actuation/sweep-dispatch.js +125 -0
- package/dist-server/service/actuation/sweep-dispatch.js.map +1 -0
- package/dist-server/service/actuation/twin-command-resolver.d.ts +120 -0
- package/dist-server/service/actuation/twin-command-resolver.js +406 -0
- package/dist-server/service/actuation/twin-command-resolver.js.map +1 -0
- package/dist-server/service/actuation/twin-command.d.ts +81 -0
- package/dist-server/service/actuation/twin-command.js +60 -0
- package/dist-server/service/actuation/twin-command.js.map +1 -1
- package/dist-server/service/actuation/twin-now.d.ts +41 -0
- package/dist-server/service/actuation/twin-now.js +65 -0
- package/dist-server/service/actuation/twin-now.js.map +1 -0
- package/dist-server/service/index.d.ts +5 -2
- package/dist-server/service/index.js +8 -0
- package/dist-server/service/index.js.map +1 -1
- package/dist-server/service/reference/actuation-routing.d.ts +60 -0
- package/dist-server/service/reference/actuation-routing.js +126 -0
- package/dist-server/service/reference/actuation-routing.js.map +1 -0
- package/dist-server/service/reference/actuation-target.d.ts +65 -0
- package/dist-server/service/reference/actuation-target.js +94 -0
- package/dist-server/service/reference/actuation-target.js.map +1 -0
- package/dist-server/service/reference/connection-portability-resolver.d.ts +29 -0
- package/dist-server/service/reference/connection-portability-resolver.js +181 -0
- package/dist-server/service/reference/connection-portability-resolver.js.map +1 -0
- package/dist-server/service/reference/connection-portability.d.ts +138 -0
- package/dist-server/service/reference/connection-portability.js +230 -0
- package/dist-server/service/reference/connection-portability.js.map +1 -0
- package/dist-server/service/reference/fill-cadence.d.ts +17 -0
- package/dist-server/service/reference/fill-cadence.js +31 -0
- package/dist-server/service/reference/fill-cadence.js.map +1 -0
- package/dist-server/service/reference/fill-dedupe.d.ts +16 -0
- package/dist-server/service/reference/fill-dedupe.js +63 -0
- package/dist-server/service/reference/fill-dedupe.js.map +1 -0
- package/dist-server/service/reference/fill-loop.d.ts +35 -0
- package/dist-server/service/reference/fill-loop.js +187 -0
- package/dist-server/service/reference/fill-loop.js.map +1 -0
- package/dist-server/service/reference/fill-span.d.ts +10 -0
- package/dist-server/service/reference/fill-span.js +37 -0
- package/dist-server/service/reference/fill-span.js.map +1 -0
- package/dist-server/service/reference/hook-contract.d.ts +88 -4
- package/dist-server/service/reference/hook-contract.js +105 -4
- package/dist-server/service/reference/hook-contract.js.map +1 -1
- package/dist-server/service/reference/hook-rejected.d.ts +25 -0
- package/dist-server/service/reference/hook-rejected.js +48 -0
- package/dist-server/service/reference/hook-rejected.js.map +1 -0
- package/dist-server/service/reference/index.d.ts +4 -1
- package/dist-server/service/reference/index.js +5 -1
- package/dist-server/service/reference/index.js.map +1 -1
- package/dist-server/service/reference/live-cadence.d.ts +68 -0
- package/dist-server/service/reference/live-cadence.js +44 -0
- package/dist-server/service/reference/live-cadence.js.map +1 -0
- package/dist-server/service/reference/live-feed-lease.d.ts +15 -0
- package/dist-server/service/reference/live-feed-lease.js +56 -0
- package/dist-server/service/reference/live-feed-lease.js.map +1 -0
- package/dist-server/service/reference/live-ingest.d.ts +21 -0
- package/dist-server/service/reference/live-ingest.js +66 -0
- package/dist-server/service/reference/live-ingest.js.map +1 -0
- package/dist-server/service/reference/reference-adapter.d.ts +291 -2
- package/dist-server/service/reference/reference-adapter.js +19 -1
- package/dist-server/service/reference/reference-adapter.js.map +1 -1
- package/dist-server/service/reference/reference-fill-run.d.ts +50 -0
- package/dist-server/service/reference/reference-fill-run.js +142 -0
- package/dist-server/service/reference/reference-fill-run.js.map +1 -0
- package/dist-server/service/reference/reference-fill.d.ts +90 -0
- package/dist-server/service/reference/reference-fill.js +141 -0
- package/dist-server/service/reference/reference-fill.js.map +1 -0
- package/dist-server/service/reference/reference-hook.d.ts +22 -0
- package/dist-server/service/reference/reference-hook.js +135 -55
- package/dist-server/service/reference/reference-hook.js.map +1 -1
- package/dist-server/service/reference/reference-link-groups.d.ts +10 -0
- package/dist-server/service/reference/reference-link-groups.js +15 -0
- package/dist-server/service/reference/reference-link-groups.js.map +1 -0
- package/dist-server/service/reference/reference-links.d.ts +14 -0
- package/dist-server/service/reference/reference-links.js +73 -0
- package/dist-server/service/reference/reference-links.js.map +1 -0
- package/dist-server/service/reference/reference-live.d.ts +1 -0
- package/dist-server/service/reference/reference-live.js +32 -6
- package/dist-server/service/reference/reference-live.js.map +1 -1
- package/dist-server/service/reference/reference-master.d.ts +56 -2
- package/dist-server/service/reference/reference-master.js +33 -3
- package/dist-server/service/reference/reference-master.js.map +1 -1
- package/dist-server/service/reference/reference-resolver.d.ts +27 -0
- package/dist-server/service/reference/reference-resolver.js +79 -1
- package/dist-server/service/reference/reference-resolver.js.map +1 -1
- package/dist-server/service/twin-event/twin-event-keys.d.ts +31 -3
- package/dist-server/service/twin-event/twin-event-keys.js +36 -4
- package/dist-server/service/twin-event/twin-event-keys.js.map +1 -1
- package/dist-server/service/twin-event/twin-event.d.ts +1 -0
- package/dist-server/service/twin-event/twin-event.js +11 -2
- package/dist-server/service/twin-event/twin-event.js.map +1 -1
- package/dist-server/service/twin-model/choose-recipe.d.ts +15 -0
- package/dist-server/service/twin-model/choose-recipe.js +33 -0
- package/dist-server/service/twin-model/choose-recipe.js.map +1 -0
- package/dist-server/service/twin-model/external-resolver.d.ts +76 -0
- package/dist-server/service/twin-model/external-resolver.js +109 -0
- package/dist-server/service/twin-model/external-resolver.js.map +1 -0
- package/dist-server/service/twin-model/project-structure.js +16 -3
- package/dist-server/service/twin-model/project-structure.js.map +1 -1
- package/dist-server/service/twin-model/twin-equipment.d.ts +17 -0
- package/dist-server/service/twin-model/twin-equipment.js +10 -0
- package/dist-server/service/twin-model/twin-equipment.js.map +1 -1
- package/dist-server/service/twin-model/twin-lineage-query.js +75 -1
- package/dist-server/service/twin-model/twin-lineage-query.js.map +1 -1
- package/dist-server/service/twin-model/twin-model-item-query.js +94 -5
- package/dist-server/service/twin-model/twin-model-item-query.js.map +1 -1
- package/dist-server/service/twin-model/twin-model-tree-query.js.map +1 -1
- package/dist-server/service/twin-space/twin-space.d.ts +29 -0
- package/dist-server/service/twin-space/twin-space.js +13 -0
- package/dist-server/service/twin-space/twin-space.js.map +1 -1
- package/dist-server/service/twin-subject/event-subjects.d.ts +3 -1
- package/dist-server/service/twin-subject/event-subjects.js +8 -1
- package/dist-server/service/twin-subject/event-subjects.js.map +1 -1
- package/dist-shared/entity-delta.js +1 -1
- package/dist-shared/entity-delta.js.map +1 -1
- package/package.json +8 -8
- package/server/engine/canonical-ingest.ts +119 -33
- package/server/engine/event-time.ts +96 -0
- package/server/engine/index.ts +20 -0
- package/server/engine/ingest-dedupe.ts +203 -27
- package/server/engine/ingest-health.ts +91 -6
- package/server/engine/kpi-fold.ts +24 -1
- package/server/engine/kpi-query.ts +23 -4
- package/server/engine/oee-accumulator.ts +80 -8
- package/server/engine/twin-engine.ts +119 -5
- package/server/index.ts +23 -0
- package/server/migrations/1786600000000-RenameOperatoMesAdapterType.ts +66 -0
- package/server/migrations/1786700000000-AddDispatchRetryColumns.ts +82 -0
- package/server/migrations/index.ts +5 -1
- package/server/routes.ts +12 -24
- package/server/service/actuation/actuation-advisor.ts +124 -0
- package/server/service/actuation/actuation-outcome.ts +97 -0
- package/server/service/actuation/actuation-rule-resolver.ts +147 -0
- package/server/service/actuation/actuation-rule.ts +139 -0
- package/server/service/actuation/approval-gateway.ts +44 -0
- package/server/service/actuation/catch-up-effects.ts +152 -0
- package/server/service/actuation/command-dispatcher.ts +401 -20
- package/server/service/actuation/command-store.ts +182 -8
- package/server/service/actuation/dispatch-after-approval.ts +71 -0
- package/server/service/actuation/effect-match.ts +124 -0
- package/server/service/actuation/index.ts +21 -2
- package/server/service/actuation/retry-plan.ts +145 -0
- package/server/service/actuation/rule-evaluate.ts +352 -0
- package/server/service/actuation/rule-loop.ts +160 -0
- package/server/service/actuation/rule-runner.ts +216 -0
- package/server/service/actuation/rule-wiring.ts +84 -0
- package/server/service/actuation/settle-effects.ts +115 -0
- package/server/service/actuation/sweep-dispatch.ts +179 -0
- package/server/service/actuation/twin-command-resolver.ts +387 -0
- package/server/service/actuation/twin-command.ts +128 -1
- package/server/service/actuation/twin-now.ts +97 -0
- package/server/service/index.ts +9 -1
- package/server/service/reference/actuation-routing.ts +165 -0
- package/server/service/reference/actuation-target.ts +163 -0
- package/server/service/reference/connection-portability-resolver.ts +171 -0
- package/server/service/reference/connection-portability.ts +285 -0
- package/server/service/reference/fill-cadence.ts +29 -0
- package/server/service/reference/fill-dedupe.ts +66 -0
- package/server/service/reference/fill-loop.ts +153 -0
- package/server/service/reference/fill-span.ts +31 -0
- package/server/service/reference/hook-contract.ts +185 -5
- package/server/service/reference/hook-rejected.ts +53 -0
- package/server/service/reference/index.ts +5 -1
- package/server/service/reference/live-cadence.ts +129 -0
- package/server/service/reference/live-feed-lease.ts +56 -0
- package/server/service/reference/live-ingest.ts +94 -0
- package/server/service/reference/reference-adapter.ts +327 -5
- package/server/service/reference/reference-fill-run.ts +165 -0
- package/server/service/reference/reference-fill.ts +223 -0
- package/server/service/reference/reference-hook.ts +162 -56
- package/server/service/reference/reference-link-groups.ts +21 -0
- package/server/service/reference/reference-links.ts +77 -0
- package/server/service/reference/reference-live.ts +30 -5
- package/server/service/reference/reference-master.ts +90 -5
- package/server/service/reference/reference-resolver.ts +77 -2
- package/server/service/twin-event/twin-event-keys.ts +37 -4
- package/server/service/twin-event/twin-event.ts +18 -1
- package/server/service/twin-model/choose-recipe.ts +31 -0
- package/server/service/twin-model/external-resolver.ts +161 -0
- package/server/service/twin-model/project-structure.ts +16 -3
- package/server/service/twin-model/twin-equipment.ts +22 -0
- package/server/service/twin-model/twin-lineage-query.ts +82 -1
- package/server/service/twin-model/twin-model-item-query.ts +95 -4
- package/server/service/twin-model/twin-model-tree-query.ts +1 -1
- package/server/service/twin-space/twin-space.ts +39 -0
- package/server/service/twin-subject/event-subjects.ts +8 -1
- package/shared/entity-delta.ts +1 -1
- package/test/ack-shape-alignment.test.ts +97 -0
- package/test/actuation-approval-door.test.ts +421 -0
- package/test/actuation-dispatch.test.ts +16 -3
- package/test/actuation-effect.test.ts +162 -0
- package/test/actuation-outcome.test.ts +152 -0
- package/test/actuation-rule-runner.test.ts +281 -0
- package/test/actuation-rule.test.ts +266 -0
- package/test/actuation-seam.test.ts +249 -0
- package/test/actuation-settle.test.ts +164 -0
- package/test/actuation-target.test.ts +145 -0
- package/test/canonical-ingest-vocabularies.test.ts +49 -2
- package/test/capability-mapping.test.ts +1 -1
- package/test/choose-recipe.test.ts +117 -0
- package/test/command-store-writes-columns.test.ts +126 -0
- package/test/connection-portability-doors.test.ts +87 -0
- package/test/connector-capability-declaration.test.ts +54 -4
- package/test/declaration-reaches-model.test.ts +43 -0
- package/test/dedupe-transformation.test.ts +112 -0
- package/test/entity-delta.test.ts +1 -1
- package/test/event-subjects.test.ts +2 -1
- package/test/external-resolver.test.ts +171 -0
- package/test/fill-dedupe.test.ts +59 -0
- package/test/fill-loop.test.ts +35 -0
- package/test/first-envelope.test.ts +153 -0
- package/test/fold-shift-dst.test.ts +110 -0
- package/test/home-in-area.test.ts +90 -0
- package/test/hook-rejected-shape.test.ts +86 -0
- package/test/hook-response-sum.test.ts +193 -0
- package/test/hook-sequence.test.ts +1 -1
- package/test/ingest-dedupe.test.ts +56 -0
- package/test/ingest-expected-quiet.test.ts +111 -0
- package/test/ingest-idempotent.test.ts +79 -0
- package/test/ingest-reconcile-four-ways.test.ts +97 -0
- package/test/ingest-rules-header.test.ts +100 -0
- package/test/ingest-window-rolls-unobserved.test.ts +72 -0
- package/test/intake-mapping-parity.test.ts +175 -0
- package/test/live-cadence.test.ts +170 -0
- package/test/live-feed-lease.test.ts +63 -0
- package/test/live-mirror-parity.test.ts +1 -1
- package/test/oee-accumulator.test.ts +3 -3
- package/test/oee-site-calendar.test.ts +146 -0
- package/test/order-and-transaction-split.test.ts +107 -0
- package/test/reference-fill.test.ts +235 -0
- package/test/reference-hook.test.ts +1 -1
- package/test/reference-links.test.ts +56 -0
- package/test/retry-plan.test.ts +139 -0
- package/test/sweep-dispatch.test.ts +191 -0
- package/test/twin-event-keys.test.ts +20 -6
- package/test/twin-model-item-db.test.ts +6 -6
- package/test/twin-model-tree-db.test.ts +6 -6
- package/tsconfig.shared.tsbuildinfo +1 -1
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TwinCommandResolver = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const type_graphql_1 = require("type-graphql");
|
|
6
|
+
const ops_contract_1 = require("@operato/ops-contract");
|
|
7
|
+
const node_crypto_1 = require("node:crypto");
|
|
8
|
+
const shell_1 = require("@things-factory/shell");
|
|
9
|
+
const actuation_advisor_js_1 = require("./actuation-advisor.js");
|
|
10
|
+
const approval_gateway_js_1 = require("./approval-gateway.js");
|
|
11
|
+
const command_dispatcher_js_1 = require("./command-dispatcher.js");
|
|
12
|
+
const actuation_routing_js_1 = require("../reference/actuation-routing.js");
|
|
13
|
+
const actuation_outcome_js_1 = require("./actuation-outcome.js");
|
|
14
|
+
const command_store_js_1 = require("./command-store.js");
|
|
15
|
+
const twin_command_js_1 = require("./twin-command.js");
|
|
16
|
+
const twin_now_js_1 = require("./twin-now.js");
|
|
17
|
+
/*
|
|
18
|
+
* 승인 대기 줄과 그 결정 — **사람이 쓰는 자리**.
|
|
19
|
+
*
|
|
20
|
+
* ── 왜 필요한가 (2026-08-31) ─────────────────────────────────────────────
|
|
21
|
+
* 게이트를 세우고 승인할 화면을 만들지 않았다. 그래서 되돌릴 수 없는 조치는 전부 대기 상태로 쌓이고
|
|
22
|
+
* **사람이 승인할 방법이 없었다.** 서버만 있고 사람이 쓸 자리가 없는 상태다.
|
|
23
|
+
*
|
|
24
|
+
* ── 왜 조회와 결정을 한 파일에 두나 ──────────────────────────────────────
|
|
25
|
+
* 대기 줄을 여는 것과 그 줄에서 결정하는 것은 한 화면의 일이다. 나누면 화면이 두 곳을 부르게 되고,
|
|
26
|
+
* 그중 하나만 권한이 바뀌는 날 목록은 보이는데 결정이 안 되거나 그 반대가 된다.
|
|
27
|
+
*/
|
|
28
|
+
let TwinCommandResolver = class TwinCommandResolver {
|
|
29
|
+
/**
|
|
30
|
+
* 커맨드 목록 — 기본은 **결정을 기다리는 것부터**.
|
|
31
|
+
*
|
|
32
|
+
* 정렬을 최근순으로 두지 않는다. 승인 대기 줄에서 사람이 찾는 것은 「새로 온 것」이 아니라
|
|
33
|
+
* **「오래 기다린 것」**이다 — 오래 기다린 조치가 뒤로 밀리면 그것이 가장 늦게 처리된다.
|
|
34
|
+
*/
|
|
35
|
+
async twinCommands(params, context) {
|
|
36
|
+
const domainId = context.state.domain?.id;
|
|
37
|
+
if (!domainId)
|
|
38
|
+
return { items: [], total: 0 };
|
|
39
|
+
const effective = {
|
|
40
|
+
...(params ?? {}),
|
|
41
|
+
sortings: params?.sortings?.length ? params.sortings : [{ name: 'createdAt', desc: false }]
|
|
42
|
+
};
|
|
43
|
+
const qb = (0, shell_1.getQueryBuilderFromListParams)({
|
|
44
|
+
repository: (0, shell_1.getRepository)(twin_command_js_1.TwinCommandRecord),
|
|
45
|
+
params: effective,
|
|
46
|
+
domain: context.state.domain,
|
|
47
|
+
alias: 'c',
|
|
48
|
+
/* 전부 실컬럼이다 — 질의 빌더는 없는 컬럼의 LIKE 를 경고 후 무시한다(인덱스 없는 전체 스캔 방지). */
|
|
49
|
+
searchables: ['instanceId', 'type', 'origin', 'state', 'approvalRef', 'decidedBy', 'error'],
|
|
50
|
+
sortables: ['createdAt', 'updatedAt', 'state', 'type', 'instanceId'],
|
|
51
|
+
/* 사람이 읽는 속도로 본다. */
|
|
52
|
+
defaultLimit: 50,
|
|
53
|
+
maxLimit: 200
|
|
54
|
+
});
|
|
55
|
+
const [items, total] = await qb.getManyAndCount();
|
|
56
|
+
return { items, total };
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* **이 조치에 대해 트윈이 지금 보는 것과 AI 의견** — 승인 화면이 부른다.
|
|
60
|
+
*
|
|
61
|
+
* ── 왜 조회인가 (2026-09-01) ───────────────────────────────────────────
|
|
62
|
+
* 결재선에 올릴 때 묻지 않는다. 그 자리는 트랜잭션 안이고 거기서 LLM 을 기다리면 DB 연결 하나를 몇 초
|
|
63
|
+
* 붙잡는다. 그리고 **승인하는 사람은 지금 판단한다** — 올린 시각의 의견은 낡았다.
|
|
64
|
+
*
|
|
65
|
+
* AI 는 판정하지 않는다. 이 값을 읽어 승인·거절을 막는 코드가 없다. 반대해도 승인되고 동의해도
|
|
66
|
+
* 거절된다 — 판정에 쓰면 AI 가 사실상 승인자가 되고, 그러면 사고 뒤에 책임을 물을 자리가 사라진다.
|
|
67
|
+
*/
|
|
68
|
+
async twinActuationOpinion(id, askAi, locale, context) {
|
|
69
|
+
const domainId = context.state.domain?.id;
|
|
70
|
+
if (!domainId)
|
|
71
|
+
throw new Error('테넌트를 알 수 없습니다');
|
|
72
|
+
const command = await (0, command_store_js_1.databaseCommandStore)().load(domainId, id);
|
|
73
|
+
if (!command)
|
|
74
|
+
throw new Error(`모르는 조치입니다 (${id})`);
|
|
75
|
+
/* 트윈의 지금 상태는 늘 새로 읽는다 — 계산값이라 싸고, 승인자는 지금을 봐야 한다. */
|
|
76
|
+
const now = (0, twin_now_js_1.twinNow)(domainId, command.instanceId, command.causeRef);
|
|
77
|
+
if (!askAi)
|
|
78
|
+
return { command, twinNow: now };
|
|
79
|
+
/*
|
|
80
|
+
* **의견을 저장하지 않는다.**
|
|
81
|
+
*
|
|
82
|
+
* 의견은 「지금」에 대한 것이고 승인자마다 여는 시각이 다르다. 저장해서 같은 문장을 돌려주면 그것이
|
|
83
|
+
* 오히려 낡은 값이다. 그리고 이 값을 읽어 승인·거절을 막는 코드가 없다 — 판정에 쓰면 AI 가 사실상
|
|
84
|
+
* 승인자가 되고, 사고 뒤에 책임을 물을 자리가 사라진다.
|
|
85
|
+
*/
|
|
86
|
+
const advice = await (0, actuation_advisor_js_1.askAdvisor)({ command, twinNow: now, ...(locale ? { locale } : {}) });
|
|
87
|
+
return { command, twinNow: now, advice };
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* 조치를 낸다 — **대기 줄에 무언가가 들어오는 유일한 자리.**
|
|
91
|
+
*
|
|
92
|
+
* 결재선이 등록된 배포에서는 여기서 바로 결재선에 올라간다(§`ApprovalGateway`). 등록되지 않았으면
|
|
93
|
+
* 제안 상태로 남고, 이 리졸버의 직접 승인이 유일한 문이 된다. 어느 쪽인지는 답에 적어 준다 — 화면이
|
|
94
|
+
* 「어디서 승인하는가」를 사람에게 말해야 한다.
|
|
95
|
+
*
|
|
96
|
+
* 되돌릴 수 있는 조치는 결재선에 올리지 않는다. 계약이 그 판단을 든다(§`requiresApproval`).
|
|
97
|
+
*/
|
|
98
|
+
async proposeTwinCommand(instanceId, type, payload, context) {
|
|
99
|
+
const { domain, user } = context.state;
|
|
100
|
+
const by = String(user?.email ?? user?.name ?? '').trim();
|
|
101
|
+
if (!by)
|
|
102
|
+
throw new Error('누가 내는지 알 수 없습니다 — 로그인한 사용자가 없습니다');
|
|
103
|
+
const store = (0, command_store_js_1.databaseCommandStore)(context.state.tx);
|
|
104
|
+
const command = await (0, command_dispatcher_js_1.propose)(store, domain.id, ops_contract_1.MES_COMMANDS, {
|
|
105
|
+
id: (0, node_crypto_1.randomUUID)(),
|
|
106
|
+
instanceId,
|
|
107
|
+
type,
|
|
108
|
+
/*
|
|
109
|
+
* 사람이 낸 것이다. 규칙·AI 가 내는 길은 아직 없다 — 그 길은 그것을 내는 쪽이 붙인다.
|
|
110
|
+
* 여기서 인자로 받으면 사람이 「규칙이 냈다」로 적어 승인자를 오판하게 만들 수 있다.
|
|
111
|
+
*/
|
|
112
|
+
origin: 'operator',
|
|
113
|
+
/* 낸 사람을 적는다 — 이 값이 있어야 자기 것을 자기가 승인하는 것을 막을 수 있다. */
|
|
114
|
+
proposedBy: by,
|
|
115
|
+
proposedAt: new Date().toISOString(),
|
|
116
|
+
...(payload ? { payload } : {})
|
|
117
|
+
});
|
|
118
|
+
if (command.reversible === true) {
|
|
119
|
+
return { command, gateway: null, note: '되돌릴 수 있는 조치입니다 — 승인 없이 넘길 수 있습니다' };
|
|
120
|
+
}
|
|
121
|
+
const gateway = (0, approval_gateway_js_1.approvalGateway)();
|
|
122
|
+
if (!gateway) {
|
|
123
|
+
return {
|
|
124
|
+
command,
|
|
125
|
+
gateway: null,
|
|
126
|
+
note: '결재선이 설치되지 않은 배포입니다 — 이 목록에서 직접 승인합니다'
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
/*
|
|
130
|
+
* 올리기와 적기가 한 트랜잭션에 있다(`@transaction`). 올렸는데 적지 못하면 결재선에는 올라가 있고
|
|
131
|
+
* 커맨드는 직접 결정도 되는 상태가 남는다 — 그때 승인이 두 곳에 갈린다.
|
|
132
|
+
*/
|
|
133
|
+
const approvalRef = await gateway.request(command, context);
|
|
134
|
+
const linked = await (0, command_dispatcher_js_1.linkApproval)(store, domain.id, command.id, approvalRef);
|
|
135
|
+
return { command: linked, gateway: gateway.label, note: `${gateway.label} 에 올렸습니다 — 승인은 그곳에서 합니다` };
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* **사람이 결재선에 올린다** — 규칙이 낸 조치가 승인 앞에 서는 유일한 길.
|
|
139
|
+
*
|
|
140
|
+
* ── 왜 규칙이 직접 올리지 않나 ─────────────────────────────────────────
|
|
141
|
+
* 업무 목록의 결재선은 **올린 사람 기준**으로 풀린다 — `Myself` · `MyDepartment` · `MySupervisor` 가
|
|
142
|
+
* 전부 로그인한 사람을 본다. 배경 루프에는 「나」가 없으므로, 시스템 사용자를 지어내 올리면 그 셋이
|
|
143
|
+
* 시스템 사용자를 가리키고 결재선이 뜻을 잃는다.
|
|
144
|
+
*
|
|
145
|
+
* 그래서 규칙은 내는 것까지 하고, 여기서 사람이 올린다. **올린 사람이 「이것을 승인자들 앞에 놓았다」의
|
|
146
|
+
* 주체**가 되고, 그 사람 기준으로 결재선이 풀린다.
|
|
147
|
+
*
|
|
148
|
+
* 올린 사람은 자기가 올린 것을 승인할 수 있다 — 규칙이 낸 조치에는 낸 사람이 없으므로 승인자가 곧
|
|
149
|
+
* 두 번째 사람이다. 올린 것과 낸 것은 다르다.
|
|
150
|
+
*/
|
|
151
|
+
async raiseTwinCommand(id, context) {
|
|
152
|
+
const { domain, user } = context.state;
|
|
153
|
+
if (!user?.id)
|
|
154
|
+
throw new Error('누가 올리는지 알 수 없습니다 — 로그인한 사용자가 없습니다');
|
|
155
|
+
const store = (0, command_store_js_1.databaseCommandStore)(context.state.tx);
|
|
156
|
+
const command = await store.load(domain.id, id);
|
|
157
|
+
if (!command)
|
|
158
|
+
throw new Error(`모르는 조치입니다 (${id})`);
|
|
159
|
+
if (command.approvalRef) {
|
|
160
|
+
throw new Error(`이미 결재선에 올라가 있습니다 (${command.approvalRef}) — 승인은 업무 목록에서 합니다`);
|
|
161
|
+
}
|
|
162
|
+
if (command.state !== 'proposed') {
|
|
163
|
+
throw new Error(`${command.state} 상태의 조치는 올릴 수 없습니다 — 이미 결정되었거나 나갔습니다`);
|
|
164
|
+
}
|
|
165
|
+
const gateway = (0, approval_gateway_js_1.approvalGateway)();
|
|
166
|
+
if (!gateway) {
|
|
167
|
+
throw new Error('결재선이 설치되지 않은 배포입니다 — 이 목록에서 직접 승인합니다');
|
|
168
|
+
}
|
|
169
|
+
const approvalRef = await gateway.request(command, context);
|
|
170
|
+
const linked = await (0, command_dispatcher_js_1.linkApproval)(store, domain.id, command.id, approvalRef);
|
|
171
|
+
return { command: linked, gateway: gateway.label, note: `${gateway.label} 에 올렸습니다 — 승인은 그곳에서 합니다` };
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* 승인한다 — **누가 승인했는지는 로그인한 사람에서 온다.**
|
|
175
|
+
*
|
|
176
|
+
* 인자로 받지 않는다. 받으면 다른 사람 이름으로 승인할 수 있고, 그러면 그 기록이 사고 뒤에 쓸 수
|
|
177
|
+
* 없어진다. 승인 기록의 값어치가 거기서 나온다.
|
|
178
|
+
*/
|
|
179
|
+
async approveTwinCommand(id, note, context) {
|
|
180
|
+
const { domain, user } = context.state;
|
|
181
|
+
const by = String(user?.email ?? user?.name ?? '').trim();
|
|
182
|
+
if (!by)
|
|
183
|
+
throw new Error('누가 승인하는지 알 수 없습니다 — 로그인한 사용자가 없습니다');
|
|
184
|
+
return (0, command_dispatcher_js_1.approve)((0, command_store_js_1.databaseCommandStore)(context.state.tx), domain.id, id, {
|
|
185
|
+
by,
|
|
186
|
+
at: new Date().toISOString(),
|
|
187
|
+
...(note?.trim() ? { note: note.trim() } : {})
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* 거절한다 — 여기서 끝난다.
|
|
192
|
+
*
|
|
193
|
+
* 사유를 요구한다. 거절은 현장이 기다리던 조치를 취소하는 것이고, 이유 없이 거절되면 낸 쪽이 다시
|
|
194
|
+
* 낸다. 그러면 같은 것이 대기 줄에 계속 돌아온다.
|
|
195
|
+
*/
|
|
196
|
+
async rejectTwinCommand(id, reason, context) {
|
|
197
|
+
const { domain, user } = context.state;
|
|
198
|
+
const by = String(user?.email ?? user?.name ?? '').trim();
|
|
199
|
+
if (!by)
|
|
200
|
+
throw new Error('누가 거절하는지 알 수 없습니다 — 로그인한 사용자가 없습니다');
|
|
201
|
+
if (!reason?.trim())
|
|
202
|
+
throw new Error('거절 사유가 필요합니다 — 이유 없이 거절되면 같은 조치가 다시 올라옵니다');
|
|
203
|
+
return (0, command_dispatcher_js_1.reject)((0, command_store_js_1.databaseCommandStore)(context.state.tx), domain.id, id, { by, at: new Date().toISOString(), note: reason.trim() });
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* 어댑터에 넘긴다 — **승인을 지나지 않은 것은 여기서 막힌다.**
|
|
207
|
+
*
|
|
208
|
+
* ── 이름이 왜 `dispatchTwinCommand` 가 아닌가 (2026-09-01) ─────────────
|
|
209
|
+
* 그 이름은 이미 **커널 자극**이 쓴다(`TwinControlMutation.dispatchTwinCommand` —
|
|
210
|
+
* `order.hold`·`resource.repair` 를 커널에 넣는다). 같은 이름을 두 번 선언하면 type-graphql 이
|
|
211
|
+
* 오류 없이 하나만 남기고, 실제로 이 뮤테이션이 통째로 가려져 있었다 — 걸어 보고 알았다.
|
|
212
|
+
*
|
|
213
|
+
* 자극과 조치가 다른 어휘라는 것을 계약에서 갈라 놓고(§`propose` 의 거절), 정작 API 이름에서 겹쳐
|
|
214
|
+
* 두었다. 여기서는 조치임을 이름에 적는다.
|
|
215
|
+
*
|
|
216
|
+
* 화면이 이것을 따로 부르는 이유는, 승인과 넘김이 다른 순간이기 때문이다. 승인한 사람과 넘긴 시각이
|
|
217
|
+
* 같아야 할 이유가 없고, 어댑터가 죽어 있으면 승인은 남아 있어야 한다.
|
|
218
|
+
*
|
|
219
|
+
* ── 여기가 끊겨 있었다 (2026-09-02) ──────────────────────────────────
|
|
220
|
+
* 이 자리가 **어댑터를 찾지도 않고** 「구현이 없습니다」를 답했다. MES 커넥터는 그때 이미 `actuate`
|
|
221
|
+
* 를 다 만들어 두었다. 그 답을 사실로 읽어서 설계 문서에도, 다른 레인에도 그렇게 알렸다 — 둘 다
|
|
222
|
+
* 틀렸다.
|
|
223
|
+
*
|
|
224
|
+
* 이제 원본을 찾아 그 원본이 선언한 능력으로 판단한다(§`routeActuation`). 보내지 못하면 **무엇이
|
|
225
|
+
* 없어서인지** 말한다. 조용히 성공을 답하면 화면은 나간 줄로 읽고, 현장은 오지 않는 지시를 기다린다.
|
|
226
|
+
*
|
|
227
|
+
* ── 여기에는 트랜잭션을 걸지 않는다 ──────────────────────────────────
|
|
228
|
+
* 넘기기 전에 「넘기는 중」을 먼저 적는 것이 이 함수의 요점이다. 한 트랜잭션에 묶으면 그 기록이
|
|
229
|
+
* 커밋 전까지 아무에게도 보이지 않고, 넘기는 사이에 프로세스가 죽으면 그대로 사라진다. 그러면 저쪽은
|
|
230
|
+
* 받았는데 우리는 안 보낸 줄 알고 다시 보낸다 — 현장이 두 번 움직인다.
|
|
231
|
+
*/
|
|
232
|
+
/**
|
|
233
|
+
* **이 조치를 넘길 수 있나** — 누르기 전에 답한다.
|
|
234
|
+
*
|
|
235
|
+
* ── 왜 이 자리가 필요한가 (2026-09-03) ────────────────────────────────────
|
|
236
|
+
* 판정 함수 둘을 만들어 두고 **부르는 자리를 안 만들었다**(`actuationTargetOf`·
|
|
237
|
+
* `actuationReadinessOf`). 그래서 화면이 물을 방법이 없었고, 못 넘기는 조치도 눌러 보고 알게 됐다.
|
|
238
|
+
* 인티그레이션 레인이 그 사실을 두 번 짚어 줬다 — 자리는 있고 길이 없는 그 부류다.
|
|
239
|
+
*
|
|
240
|
+
* 그동안 값이 실제로 없어졌다. 저쪽에 비밀값이 없던 날, 사람이 승인 화면까지 가서 누르고 실패를
|
|
241
|
+
* 보고 다시 로그인했다. **승인은 살아 있지만 사람의 시간은 돌아오지 않는다.**
|
|
242
|
+
*
|
|
243
|
+
* ── 둘을 함께 답한다 ──────────────────────────────────────────────────────
|
|
244
|
+
* 화면이 묻는 것은 하나다 — 「지금 넘겨도 되나」. 그 답이 두 겹이라 둘을 함께 싣는다.
|
|
245
|
+
*
|
|
246
|
+
* target 보낼 대상이 정해지나 — 망을 타지 않는다(원본·능력·사이트)
|
|
247
|
+
* readiness 저쪽이 받을 준비가 됐나 — 커넥터가 망을 탈 수 있다
|
|
248
|
+
*
|
|
249
|
+
* **문이 아니다.** 이 답으로 넘김을 막지 않는다(§`actuationReadinessOf`) — 화면이 미리 말하는
|
|
250
|
+
* 데까지다. 그래서 조회이고 뮤테이션이 아니다.
|
|
251
|
+
*
|
|
252
|
+
* 화면이 **목록을 그릴 때 부르지 말 것.** 커넥터가 저쪽에 물을 수 있어서 목록 한 줄마다 망을 탄다.
|
|
253
|
+
* 사람이 「넘기기」를 열 때 한 번이다.
|
|
254
|
+
*/
|
|
255
|
+
/*
|
|
256
|
+
* 권한 지시자를 달지 않는다 — 이 파일의 다른 조회 둘과 같다. **쓰기만 게이트를 지난다**(ADR-0027),
|
|
257
|
+
* 그리고 조회는 테넌트로 좁혀진다. 처음에 `privilege: "query"` 를 달았더니 권한 문장 검사가
|
|
258
|
+
* 「정본과 다르다」로 잡았다.
|
|
259
|
+
*/
|
|
260
|
+
async twinActuationReadiness(id, context) {
|
|
261
|
+
const domainId = context.state.domain?.id;
|
|
262
|
+
if (!domainId)
|
|
263
|
+
throw new Error('테넌트를 알 수 없습니다');
|
|
264
|
+
const command = await (0, command_store_js_1.databaseCommandStore)().load(domainId, id);
|
|
265
|
+
if (!command)
|
|
266
|
+
throw new Error(`모르는 조치입니다 (${id})`);
|
|
267
|
+
/*
|
|
268
|
+
* 상태를 함께 낸다 — **이 조치가 넘길 수 있는 상태인가**는 저쪽 사정과 다른 물음이다. 이미
|
|
269
|
+
* `acked` 인 것은 저쪽이 아무리 준비돼 있어도 다시 넘기지 않는다(종착).
|
|
270
|
+
*/
|
|
271
|
+
const dispatchable = (0, ops_contract_1.nextCommandState)(command.state, 'dispatch') !== undefined;
|
|
272
|
+
const [target, readiness] = await Promise.all([
|
|
273
|
+
(0, actuation_routing_js_1.actuationTargetOf)(domainId, command.instanceId),
|
|
274
|
+
(0, actuation_routing_js_1.actuationReadinessOf)(domainId, command.instanceId)
|
|
275
|
+
]);
|
|
276
|
+
return { id, state: command.state, dispatchable, target, readiness };
|
|
277
|
+
}
|
|
278
|
+
/*
|
|
279
|
+
* 권한 지시자를 달지 않는다 — 이 파일의 다른 조회들과 같다(ADR-0027: 쓰기만 게이트를 지난다).
|
|
280
|
+
*/
|
|
281
|
+
async twinActuationOutcome(id, context) {
|
|
282
|
+
const domainId = context.state.domain?.id;
|
|
283
|
+
if (!domainId)
|
|
284
|
+
throw new Error('테넌트를 알 수 없습니다');
|
|
285
|
+
const command = await (0, command_store_js_1.databaseCommandStore)().load(domainId, id);
|
|
286
|
+
if (!command)
|
|
287
|
+
throw new Error(`모르는 조치입니다 (${id})`);
|
|
288
|
+
/*
|
|
289
|
+
* **승인 직후에 부르는 자리다.** 발신은 승인 응답이 나간 다음 틱에 일어나므로(§
|
|
290
|
+
* `dispatchAfterApproval`), 그 순간에는 아직 `approved` 일 수 있다. 그것을 감추지 않는다 —
|
|
291
|
+
* 화면이 「보내는 중」을 그리고 짧게 다시 묻는다(UX 레인 규칙: 대략 0.5초·2초 두 번, 그래도
|
|
292
|
+
* 안 끝나면 조치 목록으로 안내).
|
|
293
|
+
*
|
|
294
|
+
* 여기서 기다리지 않는 이유: 기다리면 이 조회가 저쪽 왕복만큼 멈추고, 사람이 화면을 떠난
|
|
295
|
+
* 뒤에도 붙잡는다.
|
|
296
|
+
*/
|
|
297
|
+
return (0, actuation_outcome_js_1.actuationOutcomeOf)(command, (0, ops_contract_1.nextCommandState)(command.state, 'dispatch') !== undefined);
|
|
298
|
+
}
|
|
299
|
+
async dispatchTwinActuation(id, context) {
|
|
300
|
+
const { domain } = context.state;
|
|
301
|
+
/* 트랜잭션을 넘기지 않는다 — 위의 이유다. 지시자가 뒤에 붙어도 이 자리는 바뀌지 않아야 한다. */
|
|
302
|
+
return (0, command_dispatcher_js_1.dispatch)((0, command_store_js_1.databaseCommandStore)(), domain.id, id, command => (0, actuation_routing_js_1.routeActuation)(domain.id, command.instanceId, command));
|
|
303
|
+
}
|
|
304
|
+
};
|
|
305
|
+
exports.TwinCommandResolver = TwinCommandResolver;
|
|
306
|
+
tslib_1.__decorate([
|
|
307
|
+
(0, type_graphql_1.Query)(returns => shell_1.ScalarObject, {
|
|
308
|
+
nullable: true,
|
|
309
|
+
description: 'List actuation commands with the standard list contract. Defaults to the oldest waiting first.'
|
|
310
|
+
}),
|
|
311
|
+
tslib_1.__param(0, (0, type_graphql_1.Args)(type => shell_1.ListParam)),
|
|
312
|
+
tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
|
|
313
|
+
tslib_1.__metadata("design:type", Function),
|
|
314
|
+
tslib_1.__metadata("design:paramtypes", [shell_1.ListParam, Object]),
|
|
315
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
316
|
+
], TwinCommandResolver.prototype, "twinCommands", null);
|
|
317
|
+
tslib_1.__decorate([
|
|
318
|
+
(0, type_graphql_1.Query)(returns => shell_1.ScalarObject, {
|
|
319
|
+
nullable: true,
|
|
320
|
+
description: 'What the twin sees now for one command, plus an AI opinion when asked. Advisory only — never gates the decision.'
|
|
321
|
+
}),
|
|
322
|
+
tslib_1.__param(0, (0, type_graphql_1.Arg)('id')),
|
|
323
|
+
tslib_1.__param(1, (0, type_graphql_1.Arg)('askAi', { nullable: true })),
|
|
324
|
+
tslib_1.__param(2, (0, type_graphql_1.Arg)('locale', { nullable: true })),
|
|
325
|
+
tslib_1.__param(3, (0, type_graphql_1.Ctx)()),
|
|
326
|
+
tslib_1.__metadata("design:type", Function),
|
|
327
|
+
tslib_1.__metadata("design:paramtypes", [String, Boolean, String, Object]),
|
|
328
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
329
|
+
], TwinCommandResolver.prototype, "twinActuationOpinion", null);
|
|
330
|
+
tslib_1.__decorate([
|
|
331
|
+
(0, type_graphql_1.Directive)('@transaction'),
|
|
332
|
+
(0, type_graphql_1.Directive)('@privilege(category: "twin", privilege: "mutation", domainOwnerGranted: true, superUserGranted: true)'),
|
|
333
|
+
(0, type_graphql_1.Mutation)(returns => shell_1.ScalarObject, { description: 'Propose one actuation command against a twin. Raises it for approval when an approval gateway is installed.' }),
|
|
334
|
+
tslib_1.__param(0, (0, type_graphql_1.Arg)('instanceId')),
|
|
335
|
+
tslib_1.__param(1, (0, type_graphql_1.Arg)('type')),
|
|
336
|
+
tslib_1.__param(2, (0, type_graphql_1.Arg)('payload', type => shell_1.ScalarObject, { nullable: true })),
|
|
337
|
+
tslib_1.__param(3, (0, type_graphql_1.Ctx)()),
|
|
338
|
+
tslib_1.__metadata("design:type", Function),
|
|
339
|
+
tslib_1.__metadata("design:paramtypes", [String, String, Object, Object]),
|
|
340
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
341
|
+
], TwinCommandResolver.prototype, "proposeTwinCommand", null);
|
|
342
|
+
tslib_1.__decorate([
|
|
343
|
+
(0, type_graphql_1.Directive)('@transaction'),
|
|
344
|
+
(0, type_graphql_1.Directive)('@privilege(category: "twin", privilege: "mutation", domainOwnerGranted: true, superUserGranted: true)'),
|
|
345
|
+
(0, type_graphql_1.Mutation)(returns => shell_1.ScalarObject, { description: 'Raise one proposed command to the approval line. The signed-in user is the submitter.' }),
|
|
346
|
+
tslib_1.__param(0, (0, type_graphql_1.Arg)('id')),
|
|
347
|
+
tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
|
|
348
|
+
tslib_1.__metadata("design:type", Function),
|
|
349
|
+
tslib_1.__metadata("design:paramtypes", [String, Object]),
|
|
350
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
351
|
+
], TwinCommandResolver.prototype, "raiseTwinCommand", null);
|
|
352
|
+
tslib_1.__decorate([
|
|
353
|
+
(0, type_graphql_1.Directive)('@privilege(category: "twin", privilege: "mutation", domainOwnerGranted: true, superUserGranted: true)'),
|
|
354
|
+
(0, type_graphql_1.Mutation)(returns => shell_1.ScalarObject, { description: 'Approve one actuation command. The approver is the signed-in user.' }),
|
|
355
|
+
tslib_1.__param(0, (0, type_graphql_1.Arg)('id')),
|
|
356
|
+
tslib_1.__param(1, (0, type_graphql_1.Arg)('note', { nullable: true })),
|
|
357
|
+
tslib_1.__param(2, (0, type_graphql_1.Ctx)()),
|
|
358
|
+
tslib_1.__metadata("design:type", Function),
|
|
359
|
+
tslib_1.__metadata("design:paramtypes", [String, String, Object]),
|
|
360
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
361
|
+
], TwinCommandResolver.prototype, "approveTwinCommand", null);
|
|
362
|
+
tslib_1.__decorate([
|
|
363
|
+
(0, type_graphql_1.Directive)('@privilege(category: "twin", privilege: "mutation", domainOwnerGranted: true, superUserGranted: true)'),
|
|
364
|
+
(0, type_graphql_1.Mutation)(returns => shell_1.ScalarObject, { description: 'Reject one actuation command. A reason is required.' }),
|
|
365
|
+
tslib_1.__param(0, (0, type_graphql_1.Arg)('id')),
|
|
366
|
+
tslib_1.__param(1, (0, type_graphql_1.Arg)('reason')),
|
|
367
|
+
tslib_1.__param(2, (0, type_graphql_1.Ctx)()),
|
|
368
|
+
tslib_1.__metadata("design:type", Function),
|
|
369
|
+
tslib_1.__metadata("design:paramtypes", [String, String, Object]),
|
|
370
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
371
|
+
], TwinCommandResolver.prototype, "rejectTwinCommand", null);
|
|
372
|
+
tslib_1.__decorate([
|
|
373
|
+
(0, type_graphql_1.Query)(returns => shell_1.ScalarObject, {
|
|
374
|
+
nullable: true,
|
|
375
|
+
description: 'Whether one approved actuation can be dispatched now — target and far-side readiness. Advisory, not a gate.'
|
|
376
|
+
}),
|
|
377
|
+
tslib_1.__param(0, (0, type_graphql_1.Arg)('id')),
|
|
378
|
+
tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
|
|
379
|
+
tslib_1.__metadata("design:type", Function),
|
|
380
|
+
tslib_1.__metadata("design:paramtypes", [String, Object]),
|
|
381
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
382
|
+
], TwinCommandResolver.prototype, "twinActuationReadiness", null);
|
|
383
|
+
tslib_1.__decorate([
|
|
384
|
+
(0, type_graphql_1.Query)(returns => shell_1.ScalarObject, {
|
|
385
|
+
nullable: true,
|
|
386
|
+
description: 'What happened to one actuation — for the person who just approved it. Includes whether work remains at the source.'
|
|
387
|
+
}),
|
|
388
|
+
tslib_1.__param(0, (0, type_graphql_1.Arg)('id')),
|
|
389
|
+
tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
|
|
390
|
+
tslib_1.__metadata("design:type", Function),
|
|
391
|
+
tslib_1.__metadata("design:paramtypes", [String, Object]),
|
|
392
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
393
|
+
], TwinCommandResolver.prototype, "twinActuationOutcome", null);
|
|
394
|
+
tslib_1.__decorate([
|
|
395
|
+
(0, type_graphql_1.Directive)('@privilege(category: "twin", privilege: "mutation", domainOwnerGranted: true, superUserGranted: true)'),
|
|
396
|
+
(0, type_graphql_1.Mutation)(returns => shell_1.ScalarObject, { description: 'Send one approved actuation command to its connector. Not a kernel stimulus.' }),
|
|
397
|
+
tslib_1.__param(0, (0, type_graphql_1.Arg)('id')),
|
|
398
|
+
tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
|
|
399
|
+
tslib_1.__metadata("design:type", Function),
|
|
400
|
+
tslib_1.__metadata("design:paramtypes", [String, Object]),
|
|
401
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
402
|
+
], TwinCommandResolver.prototype, "dispatchTwinActuation", null);
|
|
403
|
+
exports.TwinCommandResolver = TwinCommandResolver = tslib_1.__decorate([
|
|
404
|
+
(0, type_graphql_1.Resolver)()
|
|
405
|
+
], TwinCommandResolver);
|
|
406
|
+
//# sourceMappingURL=twin-command-resolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"twin-command-resolver.js","sourceRoot":"","sources":["../../../server/service/actuation/twin-command-resolver.ts"],"names":[],"mappings":"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","sourcesContent":["import { Arg, Args, Ctx, Directive, Mutation, Query, Resolver } from 'type-graphql'\n\nimport { MES_COMMANDS, nextCommandState } from '@operato/ops-contract'\n\nimport { randomUUID } from 'node:crypto'\n\nimport { ListParam, ScalarObject, getQueryBuilderFromListParams, getRepository } from '@things-factory/shell'\n\nimport { askAdvisor } from './actuation-advisor.js'\nimport { approvalGateway } from './approval-gateway.js'\nimport { approve, dispatch, linkApproval, propose, reject } from './command-dispatcher.js'\nimport { actuationReadinessOf, actuationTargetOf, routeActuation } from '../reference/actuation-routing.js'\n\nimport { actuationOutcomeOf } from './actuation-outcome.js'\nimport { databaseCommandStore } from './command-store.js'\nimport { TwinCommandRecord } from './twin-command.js'\nimport { twinNow } from './twin-now.js'\n\n/*\n * 승인 대기 줄과 그 결정 — **사람이 쓰는 자리**.\n *\n * ── 왜 필요한가 (2026-08-31) ─────────────────────────────────────────────\n * 게이트를 세우고 승인할 화면을 만들지 않았다. 그래서 되돌릴 수 없는 조치는 전부 대기 상태로 쌓이고\n * **사람이 승인할 방법이 없었다.** 서버만 있고 사람이 쓸 자리가 없는 상태다.\n *\n * ── 왜 조회와 결정을 한 파일에 두나 ──────────────────────────────────────\n * 대기 줄을 여는 것과 그 줄에서 결정하는 것은 한 화면의 일이다. 나누면 화면이 두 곳을 부르게 되고,\n * 그중 하나만 권한이 바뀌는 날 목록은 보이는데 결정이 안 되거나 그 반대가 된다.\n */\n\n@Resolver()\nexport class TwinCommandResolver {\n /**\n * 커맨드 목록 — 기본은 **결정을 기다리는 것부터**.\n *\n * 정렬을 최근순으로 두지 않는다. 승인 대기 줄에서 사람이 찾는 것은 「새로 온 것」이 아니라\n * **「오래 기다린 것」**이다 — 오래 기다린 조치가 뒤로 밀리면 그것이 가장 늦게 처리된다.\n */\n @Query(returns => ScalarObject, {\n nullable: true,\n description: 'List actuation commands with the standard list contract. Defaults to the oldest waiting first.'\n })\n async twinCommands(\n /* 표준 목록 계약은 `@Args` 로 펼쳐 받는다 — `@Arg` 로 받으면 스키마 조립이 실패한다. */\n @Args(type => ListParam) params: ListParam,\n @Ctx() context: ResolverContext\n ): Promise<any> {\n const domainId = context.state.domain?.id\n if (!domainId) return { items: [], total: 0 }\n\n const effective: ListParam = {\n ...(params ?? ({} as ListParam)),\n sortings: params?.sortings?.length ? params.sortings : [{ name: 'createdAt', desc: false }]\n }\n\n const qb = getQueryBuilderFromListParams({\n repository: getRepository(TwinCommandRecord),\n params: effective,\n domain: context.state.domain,\n alias: 'c',\n /* 전부 실컬럼이다 — 질의 빌더는 없는 컬럼의 LIKE 를 경고 후 무시한다(인덱스 없는 전체 스캔 방지). */\n searchables: ['instanceId', 'type', 'origin', 'state', 'approvalRef', 'decidedBy', 'error'],\n sortables: ['createdAt', 'updatedAt', 'state', 'type', 'instanceId'],\n /* 사람이 읽는 속도로 본다. */\n defaultLimit: 50,\n maxLimit: 200\n })\n\n const [items, total] = await qb.getManyAndCount()\n return { items, total }\n }\n\n /**\n * **이 조치에 대해 트윈이 지금 보는 것과 AI 의견** — 승인 화면이 부른다.\n *\n * ── 왜 조회인가 (2026-09-01) ───────────────────────────────────────────\n * 결재선에 올릴 때 묻지 않는다. 그 자리는 트랜잭션 안이고 거기서 LLM 을 기다리면 DB 연결 하나를 몇 초\n * 붙잡는다. 그리고 **승인하는 사람은 지금 판단한다** — 올린 시각의 의견은 낡았다.\n *\n * AI 는 판정하지 않는다. 이 값을 읽어 승인·거절을 막는 코드가 없다. 반대해도 승인되고 동의해도\n * 거절된다 — 판정에 쓰면 AI 가 사실상 승인자가 되고, 그러면 사고 뒤에 책임을 물을 자리가 사라진다.\n */\n @Query(returns => ScalarObject, {\n nullable: true,\n description: 'What the twin sees now for one command, plus an AI opinion when asked. Advisory only — never gates the decision.'\n })\n async twinActuationOpinion(\n @Arg('id') id: string,\n /**\n * AI 에게도 물을 것인가 — **누르면 묻는다.**\n *\n * 기본은 안 묻는다. 화면을 열 때마다 부르면 승인자 다섯 명이 두 번씩 열 때 한 건에 열 번이고,\n * 대부분의 지시는 평범해서 그중 아홉 번은 같은 말을 다시 받는 것이다.\n */\n @Arg('askAi', { nullable: true }) askAi: boolean,\n @Arg('locale', { nullable: true }) locale: string,\n @Ctx() context: ResolverContext\n ): Promise<any> {\n const domainId = context.state.domain?.id\n if (!domainId) throw new Error('테넌트를 알 수 없습니다')\n\n const command = await databaseCommandStore().load(domainId, id)\n if (!command) throw new Error(`모르는 조치입니다 (${id})`)\n\n /* 트윈의 지금 상태는 늘 새로 읽는다 — 계산값이라 싸고, 승인자는 지금을 봐야 한다. */\n const now = twinNow(domainId, command.instanceId, command.causeRef)\n\n if (!askAi) return { command, twinNow: now }\n\n /*\n * **의견을 저장하지 않는다.**\n *\n * 의견은 「지금」에 대한 것이고 승인자마다 여는 시각이 다르다. 저장해서 같은 문장을 돌려주면 그것이\n * 오히려 낡은 값이다. 그리고 이 값을 읽어 승인·거절을 막는 코드가 없다 — 판정에 쓰면 AI 가 사실상\n * 승인자가 되고, 사고 뒤에 책임을 물을 자리가 사라진다.\n */\n const advice = await askAdvisor({ command, twinNow: now, ...(locale ? { locale } : {}) })\n\n return { command, twinNow: now, advice }\n }\n\n /**\n * 조치를 낸다 — **대기 줄에 무언가가 들어오는 유일한 자리.**\n *\n * 결재선이 등록된 배포에서는 여기서 바로 결재선에 올라간다(§`ApprovalGateway`). 등록되지 않았으면\n * 제안 상태로 남고, 이 리졸버의 직접 승인이 유일한 문이 된다. 어느 쪽인지는 답에 적어 준다 — 화면이\n * 「어디서 승인하는가」를 사람에게 말해야 한다.\n *\n * 되돌릴 수 있는 조치는 결재선에 올리지 않는다. 계약이 그 판단을 든다(§`requiresApproval`).\n */\n @Directive('@transaction')\n @Directive('@privilege(category: \"twin\", privilege: \"mutation\", domainOwnerGranted: true, superUserGranted: true)')\n @Mutation(returns => ScalarObject, { description: 'Propose one actuation command against a twin. Raises it for approval when an approval gateway is installed.' })\n async proposeTwinCommand(\n @Arg('instanceId') instanceId: string,\n @Arg('type') type: string,\n @Arg('payload', type => ScalarObject, { nullable: true }) payload: any,\n @Ctx() context: ResolverContext\n ): Promise<any> {\n const { domain, user } = context.state\n const by = String(user?.email ?? user?.name ?? '').trim()\n if (!by) throw new Error('누가 내는지 알 수 없습니다 — 로그인한 사용자가 없습니다')\n\n const store = databaseCommandStore(context.state.tx)\n const command = await propose(store, domain.id, MES_COMMANDS, {\n id: randomUUID(),\n instanceId,\n type,\n /*\n * 사람이 낸 것이다. 규칙·AI 가 내는 길은 아직 없다 — 그 길은 그것을 내는 쪽이 붙인다.\n * 여기서 인자로 받으면 사람이 「규칙이 냈다」로 적어 승인자를 오판하게 만들 수 있다.\n */\n origin: 'operator',\n /* 낸 사람을 적는다 — 이 값이 있어야 자기 것을 자기가 승인하는 것을 막을 수 있다. */\n proposedBy: by,\n proposedAt: new Date().toISOString(),\n ...(payload ? { payload } : {})\n })\n\n if (command.reversible === true) {\n return { command, gateway: null, note: '되돌릴 수 있는 조치입니다 — 승인 없이 넘길 수 있습니다' }\n }\n\n const gateway = approvalGateway()\n if (!gateway) {\n return {\n command,\n gateway: null,\n note: '결재선이 설치되지 않은 배포입니다 — 이 목록에서 직접 승인합니다'\n }\n }\n\n /*\n * 올리기와 적기가 한 트랜잭션에 있다(`@transaction`). 올렸는데 적지 못하면 결재선에는 올라가 있고\n * 커맨드는 직접 결정도 되는 상태가 남는다 — 그때 승인이 두 곳에 갈린다.\n */\n const approvalRef = await gateway.request(command, context)\n const linked = await linkApproval(store, domain.id, command.id, approvalRef)\n\n return { command: linked, gateway: gateway.label, note: `${gateway.label} 에 올렸습니다 — 승인은 그곳에서 합니다` }\n }\n\n /**\n * **사람이 결재선에 올린다** — 규칙이 낸 조치가 승인 앞에 서는 유일한 길.\n *\n * ── 왜 규칙이 직접 올리지 않나 ─────────────────────────────────────────\n * 업무 목록의 결재선은 **올린 사람 기준**으로 풀린다 — `Myself` · `MyDepartment` · `MySupervisor` 가\n * 전부 로그인한 사람을 본다. 배경 루프에는 「나」가 없으므로, 시스템 사용자를 지어내 올리면 그 셋이\n * 시스템 사용자를 가리키고 결재선이 뜻을 잃는다.\n *\n * 그래서 규칙은 내는 것까지 하고, 여기서 사람이 올린다. **올린 사람이 「이것을 승인자들 앞에 놓았다」의\n * 주체**가 되고, 그 사람 기준으로 결재선이 풀린다.\n *\n * 올린 사람은 자기가 올린 것을 승인할 수 있다 — 규칙이 낸 조치에는 낸 사람이 없으므로 승인자가 곧\n * 두 번째 사람이다. 올린 것과 낸 것은 다르다.\n */\n @Directive('@transaction')\n @Directive('@privilege(category: \"twin\", privilege: \"mutation\", domainOwnerGranted: true, superUserGranted: true)')\n @Mutation(returns => ScalarObject, { description: 'Raise one proposed command to the approval line. The signed-in user is the submitter.' })\n async raiseTwinCommand(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<any> {\n const { domain, user } = context.state\n if (!user?.id) throw new Error('누가 올리는지 알 수 없습니다 — 로그인한 사용자가 없습니다')\n\n const store = databaseCommandStore(context.state.tx)\n const command = await store.load(domain.id, id)\n if (!command) throw new Error(`모르는 조치입니다 (${id})`)\n\n if (command.approvalRef) {\n throw new Error(`이미 결재선에 올라가 있습니다 (${command.approvalRef}) — 승인은 업무 목록에서 합니다`)\n }\n if (command.state !== 'proposed') {\n throw new Error(`${command.state} 상태의 조치는 올릴 수 없습니다 — 이미 결정되었거나 나갔습니다`)\n }\n\n const gateway = approvalGateway()\n if (!gateway) {\n throw new Error('결재선이 설치되지 않은 배포입니다 — 이 목록에서 직접 승인합니다')\n }\n\n const approvalRef = await gateway.request(command, context)\n const linked = await linkApproval(store, domain.id, command.id, approvalRef)\n\n return { command: linked, gateway: gateway.label, note: `${gateway.label} 에 올렸습니다 — 승인은 그곳에서 합니다` }\n }\n\n /**\n * 승인한다 — **누가 승인했는지는 로그인한 사람에서 온다.**\n *\n * 인자로 받지 않는다. 받으면 다른 사람 이름으로 승인할 수 있고, 그러면 그 기록이 사고 뒤에 쓸 수\n * 없어진다. 승인 기록의 값어치가 거기서 나온다.\n */\n @Directive('@privilege(category: \"twin\", privilege: \"mutation\", domainOwnerGranted: true, superUserGranted: true)')\n @Mutation(returns => ScalarObject, { description: 'Approve one actuation command. The approver is the signed-in user.' })\n async approveTwinCommand(\n @Arg('id') id: string,\n @Arg('note', { nullable: true }) note: string,\n @Ctx() context: ResolverContext\n ): Promise<any> {\n const { domain, user } = context.state\n const by = String(user?.email ?? user?.name ?? '').trim()\n if (!by) throw new Error('누가 승인하는지 알 수 없습니다 — 로그인한 사용자가 없습니다')\n\n return approve(databaseCommandStore(context.state.tx), domain.id, id, {\n by,\n at: new Date().toISOString(),\n ...(note?.trim() ? { note: note.trim() } : {})\n })\n }\n\n /**\n * 거절한다 — 여기서 끝난다.\n *\n * 사유를 요구한다. 거절은 현장이 기다리던 조치를 취소하는 것이고, 이유 없이 거절되면 낸 쪽이 다시\n * 낸다. 그러면 같은 것이 대기 줄에 계속 돌아온다.\n */\n @Directive('@privilege(category: \"twin\", privilege: \"mutation\", domainOwnerGranted: true, superUserGranted: true)')\n @Mutation(returns => ScalarObject, { description: 'Reject one actuation command. A reason is required.' })\n async rejectTwinCommand(\n @Arg('id') id: string,\n @Arg('reason') reason: string,\n @Ctx() context: ResolverContext\n ): Promise<any> {\n const { domain, user } = context.state\n const by = String(user?.email ?? user?.name ?? '').trim()\n if (!by) throw new Error('누가 거절하는지 알 수 없습니다 — 로그인한 사용자가 없습니다')\n if (!reason?.trim()) throw new Error('거절 사유가 필요합니다 — 이유 없이 거절되면 같은 조치가 다시 올라옵니다')\n\n return reject(databaseCommandStore(context.state.tx), domain.id, id, { by, at: new Date().toISOString(), note: reason.trim() })\n }\n\n /**\n * 어댑터에 넘긴다 — **승인을 지나지 않은 것은 여기서 막힌다.**\n *\n * ── 이름이 왜 `dispatchTwinCommand` 가 아닌가 (2026-09-01) ─────────────\n * 그 이름은 이미 **커널 자극**이 쓴다(`TwinControlMutation.dispatchTwinCommand` —\n * `order.hold`·`resource.repair` 를 커널에 넣는다). 같은 이름을 두 번 선언하면 type-graphql 이\n * 오류 없이 하나만 남기고, 실제로 이 뮤테이션이 통째로 가려져 있었다 — 걸어 보고 알았다.\n *\n * 자극과 조치가 다른 어휘라는 것을 계약에서 갈라 놓고(§`propose` 의 거절), 정작 API 이름에서 겹쳐\n * 두었다. 여기서는 조치임을 이름에 적는다.\n *\n * 화면이 이것을 따로 부르는 이유는, 승인과 넘김이 다른 순간이기 때문이다. 승인한 사람과 넘긴 시각이\n * 같아야 할 이유가 없고, 어댑터가 죽어 있으면 승인은 남아 있어야 한다.\n *\n * ── 여기가 끊겨 있었다 (2026-09-02) ──────────────────────────────────\n * 이 자리가 **어댑터를 찾지도 않고** 「구현이 없습니다」를 답했다. MES 커넥터는 그때 이미 `actuate`\n * 를 다 만들어 두었다. 그 답을 사실로 읽어서 설계 문서에도, 다른 레인에도 그렇게 알렸다 — 둘 다\n * 틀렸다.\n *\n * 이제 원본을 찾아 그 원본이 선언한 능력으로 판단한다(§`routeActuation`). 보내지 못하면 **무엇이\n * 없어서인지** 말한다. 조용히 성공을 답하면 화면은 나간 줄로 읽고, 현장은 오지 않는 지시를 기다린다.\n *\n * ── 여기에는 트랜잭션을 걸지 않는다 ──────────────────────────────────\n * 넘기기 전에 「넘기는 중」을 먼저 적는 것이 이 함수의 요점이다. 한 트랜잭션에 묶으면 그 기록이\n * 커밋 전까지 아무에게도 보이지 않고, 넘기는 사이에 프로세스가 죽으면 그대로 사라진다. 그러면 저쪽은\n * 받았는데 우리는 안 보낸 줄 알고 다시 보낸다 — 현장이 두 번 움직인다.\n */\n /**\n * **이 조치를 넘길 수 있나** — 누르기 전에 답한다.\n *\n * ── 왜 이 자리가 필요한가 (2026-09-03) ────────────────────────────────────\n * 판정 함수 둘을 만들어 두고 **부르는 자리를 안 만들었다**(`actuationTargetOf`·\n * `actuationReadinessOf`). 그래서 화면이 물을 방법이 없었고, 못 넘기는 조치도 눌러 보고 알게 됐다.\n * 인티그레이션 레인이 그 사실을 두 번 짚어 줬다 — 자리는 있고 길이 없는 그 부류다.\n *\n * 그동안 값이 실제로 없어졌다. 저쪽에 비밀값이 없던 날, 사람이 승인 화면까지 가서 누르고 실패를\n * 보고 다시 로그인했다. **승인은 살아 있지만 사람의 시간은 돌아오지 않는다.**\n *\n * ── 둘을 함께 답한다 ──────────────────────────────────────────────────────\n * 화면이 묻는 것은 하나다 — 「지금 넘겨도 되나」. 그 답이 두 겹이라 둘을 함께 싣는다.\n *\n * target 보낼 대상이 정해지나 — 망을 타지 않는다(원본·능력·사이트)\n * readiness 저쪽이 받을 준비가 됐나 — 커넥터가 망을 탈 수 있다\n *\n * **문이 아니다.** 이 답으로 넘김을 막지 않는다(§`actuationReadinessOf`) — 화면이 미리 말하는\n * 데까지다. 그래서 조회이고 뮤테이션이 아니다.\n *\n * 화면이 **목록을 그릴 때 부르지 말 것.** 커넥터가 저쪽에 물을 수 있어서 목록 한 줄마다 망을 탄다.\n * 사람이 「넘기기」를 열 때 한 번이다.\n */\n /*\n * 권한 지시자를 달지 않는다 — 이 파일의 다른 조회 둘과 같다. **쓰기만 게이트를 지난다**(ADR-0027),\n * 그리고 조회는 테넌트로 좁혀진다. 처음에 `privilege: \"query\"` 를 달았더니 권한 문장 검사가\n * 「정본과 다르다」로 잡았다.\n */\n @Query(returns => ScalarObject, {\n nullable: true,\n description: 'Whether one approved actuation can be dispatched now — target and far-side readiness. Advisory, not a gate.'\n })\n async twinActuationReadiness(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<any> {\n const domainId = context.state.domain?.id\n if (!domainId) throw new Error('테넌트를 알 수 없습니다')\n\n const command = await databaseCommandStore().load(domainId, id)\n if (!command) throw new Error(`모르는 조치입니다 (${id})`)\n\n /*\n * 상태를 함께 낸다 — **이 조치가 넘길 수 있는 상태인가**는 저쪽 사정과 다른 물음이다. 이미\n * `acked` 인 것은 저쪽이 아무리 준비돼 있어도 다시 넘기지 않는다(종착).\n */\n const dispatchable = nextCommandState(command.state, 'dispatch') !== undefined\n\n const [target, readiness] = await Promise.all([\n actuationTargetOf(domainId, command.instanceId),\n actuationReadinessOf(domainId, command.instanceId)\n ])\n\n return { id, state: command.state, dispatchable, target, readiness }\n }\n\n /*\n * 권한 지시자를 달지 않는다 — 이 파일의 다른 조회들과 같다(ADR-0027: 쓰기만 게이트를 지난다).\n */\n @Query(returns => ScalarObject, {\n nullable: true,\n description: 'What happened to one actuation — for the person who just approved it. Includes whether work remains at the source.'\n })\n async twinActuationOutcome(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<any> {\n const domainId = context.state.domain?.id\n if (!domainId) throw new Error('테넌트를 알 수 없습니다')\n\n const command = await databaseCommandStore().load(domainId, id)\n if (!command) throw new Error(`모르는 조치입니다 (${id})`)\n\n /*\n * **승인 직후에 부르는 자리다.** 발신은 승인 응답이 나간 다음 틱에 일어나므로(§\n * `dispatchAfterApproval`), 그 순간에는 아직 `approved` 일 수 있다. 그것을 감추지 않는다 —\n * 화면이 「보내는 중」을 그리고 짧게 다시 묻는다(UX 레인 규칙: 대략 0.5초·2초 두 번, 그래도\n * 안 끝나면 조치 목록으로 안내).\n *\n * 여기서 기다리지 않는 이유: 기다리면 이 조회가 저쪽 왕복만큼 멈추고, 사람이 화면을 떠난\n * 뒤에도 붙잡는다.\n */\n return actuationOutcomeOf(command, nextCommandState(command.state, 'dispatch') !== undefined)\n }\n\n @Directive('@privilege(category: \"twin\", privilege: \"mutation\", domainOwnerGranted: true, superUserGranted: true)')\n @Mutation(returns => ScalarObject, { description: 'Send one approved actuation command to its connector. Not a kernel stimulus.' })\n async dispatchTwinActuation(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<any> {\n const { domain } = context.state\n\n /* 트랜잭션을 넘기지 않는다 — 위의 이유다. 지시자가 뒤에 붙어도 이 자리는 바뀌지 않아야 한다. */\n return dispatch(databaseCommandStore(), domain.id, id, command =>\n routeActuation(domain.id, command.instanceId, command)\n )\n }\n}\n"]}
|
|
@@ -7,6 +7,16 @@ export declare class TwinCommandRecord {
|
|
|
7
7
|
type: string;
|
|
8
8
|
payload?: any;
|
|
9
9
|
origin: string;
|
|
10
|
+
/**
|
|
11
|
+
* **낸 사람** — 종류가 아니라 사람이다.
|
|
12
|
+
*
|
|
13
|
+
* `origin` 은 「사람이 냈나 · 규칙이 냈나」만 말한다. 그것만으로는 **낸 사람이 자기 것을 승인하는 것**을
|
|
14
|
+
* 막을 수 없고, 그러면 게이트가 시늉이 된다. 되돌릴 수 없는 조치에 두 사람이 필요하다는 것이 이 표의
|
|
15
|
+
* 존재 이유다.
|
|
16
|
+
*
|
|
17
|
+
* 규칙·AI 가 낸 것은 비어 있다 — 사람이 아니다.
|
|
18
|
+
*/
|
|
19
|
+
proposedBy?: string;
|
|
10
20
|
/**
|
|
11
21
|
* **되돌릴 수 있는가** — 게이트가 걸리는 기준이다.
|
|
12
22
|
*
|
|
@@ -15,6 +25,31 @@ export declare class TwinCommandRecord {
|
|
|
15
25
|
*/
|
|
16
26
|
reversible?: boolean;
|
|
17
27
|
state: string;
|
|
28
|
+
/**
|
|
29
|
+
* **무엇 때문에 냈나** — 규칙이 낸 조치가 가리키는 관측의 식별자(`Attention.id`).
|
|
30
|
+
*
|
|
31
|
+
* 두 가지를 한다.
|
|
32
|
+
*
|
|
33
|
+
* 같은 조건을 두 번 올리지 않는다 결정을 기다리는 커맨드의 이 값을 모아 판정에 넘긴다
|
|
34
|
+
* 승인하는 사람이 근거를 본다 「무슨 일이 있어서 이것이 올라왔나」
|
|
35
|
+
*
|
|
36
|
+
* 앞엣것이 이 칸의 존재 이유다. 프로세스 기억으로 중복을 막으면 **재기동이 곧 중복**이 된다 — 다시 선
|
|
37
|
+
* 트윈이 같은 조건을 처음 보는 것으로 읽고 대기 줄에 같은 지시를 또 올린다.
|
|
38
|
+
*
|
|
39
|
+
* 사람이 낸 것은 비어 있다. 사람은 자기가 왜 내는지 알고 있고, 그 이유를 값으로 요구하면 아무 글자나 적힌다.
|
|
40
|
+
*/
|
|
41
|
+
causeRef?: string;
|
|
42
|
+
/** 어느 규칙이 냈나 — 규칙을 끄거나 고칠 때 그 규칙이 무엇을 냈는지 되짚을 자리. */
|
|
43
|
+
ruleRef?: string;
|
|
44
|
+
/**
|
|
45
|
+
* **결재선에 올라간 자리** — 업무 목록(`@things-factory/worklist`)의 액티비티 인스턴스 식별자.
|
|
46
|
+
*
|
|
47
|
+
* 이 값이 있으면 승인·거절은 **그 목록에서만** 한다. 여기 있는 직접 결정 뮤테이션은 막힌다 — 문이 두
|
|
48
|
+
* 벌이면 결재선에는 대기로 남아 있는데 조치는 이미 나간 상태가 만들어진다.
|
|
49
|
+
*
|
|
50
|
+
* 비어 있으면 결재선을 쓰지 않는 배포다. 그때는 직접 결정이 유일한 문이다.
|
|
51
|
+
*/
|
|
52
|
+
approvalRef?: string;
|
|
18
53
|
decidedBy?: string;
|
|
19
54
|
decidedAt?: string;
|
|
20
55
|
decisionNote?: string;
|
|
@@ -24,6 +59,52 @@ export declare class TwinCommandRecord {
|
|
|
24
59
|
* 이것이 없으면 되돌릴 때 **무엇을 되돌릴지 말할 수 없다.**
|
|
25
60
|
*/
|
|
26
61
|
dispatchRef?: string;
|
|
62
|
+
/**
|
|
63
|
+
* 받아들였으나 저쪽이 덧붙인 말 — **실패가 아니고 「끝났다」도 아니다.**
|
|
64
|
+
*
|
|
65
|
+
* MES 가 지시를 접수해 놓고 지시서를 못 붙이면 그 사실이 여기 온다. `error` 와 다른 칸이어야 한다 —
|
|
66
|
+
* `error` 에 적으면 실패로 읽혀 커맨드가 `failed` 로 앉는다.
|
|
67
|
+
*/
|
|
68
|
+
dispatchNote?: string;
|
|
69
|
+
/** 저쪽이 보고한 상태 — **해석하지 않고 그대로.** 어느 값이 「나갔다」인지는 현장이 안다. */
|
|
70
|
+
effectStatus?: string;
|
|
71
|
+
/** 그 보고를 관측한 시각. 컬럼 타입을 적지 않는다 — 드라이버 방언이라 개발에서 안 잡힌다. */
|
|
72
|
+
effectAt?: string;
|
|
73
|
+
/** 몇 번 보고됐나 — 한 번도 안 바뀐 것과 다섯 번 바뀐 것은 다른 일이다. */
|
|
74
|
+
effectSeen?: number;
|
|
75
|
+
/**
|
|
76
|
+
* 저쪽이 받으면서 덧붙인 말 중 **다음에 할 일** 한 줄 — 원인은 `dispatchNote` 다.
|
|
77
|
+
*
|
|
78
|
+
* 왜 둘로 나누나: 읽는 사람은 「그래서 내가 뭘 해야 하나」를 먼저 찾는다(UX 레인). 한 문장으로
|
|
79
|
+
* 주면 화면이 자르게 되고, 자르는 규칙이 화면마다 생긴다. 어댑터가 이미 둘로 알고 있으니
|
|
80
|
+
* 붙이지 않고 그대로 받는다.
|
|
81
|
+
*/
|
|
82
|
+
dispatchNoteNext?: string;
|
|
83
|
+
/**
|
|
84
|
+
* **다시 해서 될 일인가** — 어댑터가 실패마다 답한다(§`CommandAck.retry`).
|
|
85
|
+
*
|
|
86
|
+
* again 그대로 다시 해 볼 만하다 — 못 닿았거나 저쪽이 잠깐 흔들렸다
|
|
87
|
+
* after-fix 사람이 고친 뒤 그대로 나간다 — 설정 문제
|
|
88
|
+
* never 이 조치로는 영원히 안 된다 — 지시 내용이 틀렸다
|
|
89
|
+
*
|
|
90
|
+
* 가르는 자리는 「조치를 다시 낼 필요가 있나」다. 설정이 틀린 것은 조치가 멀쩡하므로 `after-fix`,
|
|
91
|
+
* 지시 내용이 틀린 것은 그 조치가 영원히 틀렸으므로 `never` 다(인티그레이션 레인 판단).
|
|
92
|
+
*
|
|
93
|
+
* **비어 있으면 `never` 로 읽지 않는다.** 모르는 것과 영원히 안 되는 것은 다르다 — 선언하지 않은
|
|
94
|
+
* 커넥터의 실패를 `never` 로 접으면 고칠 수 있는 것을 사람이 포기한다.
|
|
95
|
+
*/
|
|
96
|
+
retry?: string;
|
|
97
|
+
/** 몇 번 넘겨 봤나 — 목록의 「몇 번 해 봤나」가 이 값이다. 첫 시도가 1이다. */
|
|
98
|
+
attempts?: number;
|
|
99
|
+
/**
|
|
100
|
+
* **다음에 넘겨 볼 시각**(ISO) — 물러섬을 표로 든다.
|
|
101
|
+
*
|
|
102
|
+
* 메모리에 두지 않는 이유: 재기동하면 사라지고, 그러면 물러서던 것이 전부 즉시 재시도가 된다.
|
|
103
|
+
* 표에 두면 일꾼이 여러 대여도 같은 답을 본다.
|
|
104
|
+
*
|
|
105
|
+
* 비어 있으면 **다음 주기에 바로** 본다(한 번도 실패하지 않은 것).
|
|
106
|
+
*/
|
|
107
|
+
nextAttemptAt?: string;
|
|
27
108
|
error?: string;
|
|
28
109
|
createdAt?: Date;
|
|
29
110
|
updatedAt?: Date;
|