@things-factory/headless-twin 10.0.18 → 10.1.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.
- 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 +19 -16
- 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 +230 -0
- package/dist-server/service/actuation/command-dispatcher.js +269 -0
- package/dist-server/service/actuation/command-dispatcher.js.map +1 -0
- package/dist-server/service/actuation/command-store.d.ts +11 -0
- package/dist-server/service/actuation/command-store.js +219 -0
- package/dist-server/service/actuation/command-store.js.map +1 -0
- 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 +25 -0
- package/dist-server/service/actuation/index.js +30 -0
- package/dist-server/service/actuation/index.js.map +1 -0
- 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 +111 -0
- package/dist-server/service/actuation/twin-command.js +170 -0
- package/dist-server/service/actuation/twin-command.js.map +1 -0
- 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 +28 -17
- 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 +149 -22
- package/dist-server/service/reference/hook-contract.js +236 -23
- 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/hook-store.d.ts +3 -0
- package/dist-server/service/reference/hook-store.js +28 -0
- package/dist-server/service/reference/hook-store.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 +355 -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 +64 -6
- package/dist-server/service/reference/reference-hook.js +265 -27
- 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 +7 -7
- 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 +19 -20
- 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 +511 -0
- package/server/service/actuation/command-store.ts +236 -0
- 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 +27 -0
- 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 +232 -0
- package/server/service/actuation/twin-now.ts +97 -0
- package/server/service/index.ts +11 -0
- 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 +280 -22
- package/server/service/reference/hook-rejected.ts +53 -0
- package/server/service/reference/hook-store.ts +28 -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 +392 -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 +355 -32
- 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 +209 -0
- 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 +333 -0
- 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 +114 -23
- 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
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
import type { ApprovedCommand } from '@operato/ops-contract';
|
|
1
2
|
import type { ReferenceStep } from './reference-progress.js';
|
|
2
3
|
import type { ReferenceMaster } from './reference-master.js';
|
|
4
|
+
import type { ExternalIncoming as ReferenceLinkGroup } from '../twin-model/external-resolver.js';
|
|
5
|
+
export type { ReferenceLinkGroup };
|
|
3
6
|
/** 연결 설정(어댑터별 스키마) — 엔드포인트·자격·파라미터. */
|
|
4
7
|
export type ConnectionConfig = Record<string, any>;
|
|
5
8
|
/** discoverSites 가 반환하는 사이트/공장 서술자 — N 발견(§2.2). 1:1 은 길이 1 배열. */
|
|
@@ -58,7 +61,37 @@ export interface AdapterMeta {
|
|
|
58
61
|
* · `live` — 돌아가는 피드를 낸다(`openLiveFeed`).
|
|
59
62
|
* · `control` — 구동을 받는다(`control`) — 자극·속도·정지·초기화.
|
|
60
63
|
*/
|
|
61
|
-
|
|
64
|
+
/**
|
|
65
|
+
* 이 원본에 무엇을 요구할 수 있나.
|
|
66
|
+
*
|
|
67
|
+
* · `live` — 관측을 이어서 낸다
|
|
68
|
+
* · `control` — 시뮬레이터를 움직인다(자극·배속·정지). 실 시스템은 갖지 않는다
|
|
69
|
+
* · `actuate` — **승인된 조치를 받는다.** 현장에 작업지시가 나가는 유일한 축이다
|
|
70
|
+
*
|
|
71
|
+
* ── `actuate` 를 늦게 넣은 이유 (2026-09-02) ────────────────────────────────
|
|
72
|
+
* 어댑터에 `actuate` 구현은 있었는데 이 축에 그 이름이 없었다. 그래서 셋이 동시에 조용했다.
|
|
73
|
+
*
|
|
74
|
+
* 화면 「이 원본이 지시를 받나」를 물을 수 없다 — 능력 목록에 그 이름이 없다
|
|
75
|
+
* 등록 구현했는데 선언 안 한 것을 알려 주지 않는다 — 검사 목록에 그 이름이 없다
|
|
76
|
+
* 넘김 리졸버가 어댑터를 찾지도 않고 무조건 거절했다 — 커넥터는 이미 만들어져 있었다
|
|
77
|
+
*
|
|
78
|
+
* 실제로 MES 커넥터가 `actuate` 를 다 만들어 두었는데, 넘기면 「구현이 없습니다」라고 답했다.
|
|
79
|
+
* 자리는 있고 길이 없는 상태였고, 이 저장소에서 가장 자주 나는 결함 부류다.
|
|
80
|
+
*/
|
|
81
|
+
/**
|
|
82
|
+
* 커넥터가 선언하는 능력.
|
|
83
|
+
*
|
|
84
|
+
* `idempotent-actuation` 은 다른 셋과 성질이 다르다 — 무엇을 할 수 있나가 아니라 **두 번 해도
|
|
85
|
+
* 같은가**다. 일꾼이 실패한 조치를 다시 넘길지 정할 때 이것만 본다(§`retryDecisionOf`).
|
|
86
|
+
*
|
|
87
|
+
* 선언하지 않으면 **거짓으로 읽는다.** 이 한 자리에서만 「모르면 안전한 쪽」이 거짓이고, 그
|
|
88
|
+
* 안전한 쪽이 「재시도하지 않음」이다 — 참으로 가정하면 현장에 지시가 두 건 선다.
|
|
89
|
+
*
|
|
90
|
+
* 선언에는 근거가 있어야 한다. operato-plant 는 MES 가 `correlationId` 로 기존 행을 찾아 같은
|
|
91
|
+
* 이름을 돌려주기 때문에 참이다 — 우리가 조심해서가 아니라 저쪽 동작이 그래서다. 저쪽이 그것을
|
|
92
|
+
* 바꾸면 이 선언이 거짓이 된다.
|
|
93
|
+
*/
|
|
94
|
+
export type ReferenceCapability = 'live' | 'control' | 'actuate' | 'idempotent-actuation';
|
|
62
95
|
/** 원본에 보내는 구동 명령 — **시뮬레이터를 움직이는 말**이지 트윈을 고치는 말이 아니다. */
|
|
63
96
|
export interface ControlCommand {
|
|
64
97
|
/**
|
|
@@ -124,12 +157,143 @@ export interface ObservedItemFact {
|
|
|
124
157
|
expiry?: number;
|
|
125
158
|
lot?: string;
|
|
126
159
|
}
|
|
160
|
+
/**
|
|
161
|
+
* 밀어 받은 본문 하나를 옮긴 결과 (2026-08-31).
|
|
162
|
+
*
|
|
163
|
+
* 레코드만 돌려주던 것을 넓혔다. 번호를 함께 받아야 프레임워크가 빠진 것을 알아챈다.
|
|
164
|
+
*
|
|
165
|
+
* **`scope` 가 없으면 `seq` 도 없는 것으로 다룬다.** 번호만 있고 그 번호가 어느 줄의 것인지 모르면
|
|
166
|
+
* 커서를 무엇으로 잡을지 짐작해야 하고, 짐작한 열쇠는 보내는 쪽이 줄을 하나 더 늘리는 날 어긋난다.
|
|
167
|
+
* 실제로 operato-plant 가 `[domain, channel]` 마다 번호를 매기면서 봉투에 `channel` 을 싣지 않고 있었다.
|
|
168
|
+
*/
|
|
169
|
+
/** 번호 하나에 대해 원본이 아는 것. */
|
|
170
|
+
export interface SeqEntry {
|
|
171
|
+
seq: number;
|
|
172
|
+
/**
|
|
173
|
+
* `unknown` 은 결함이 아니다 — 채번을 따로 들지 않는 원본은 「행이 없다」에서 잃은 것과 아직 안
|
|
174
|
+
* 간 것을 가를 수 없다. 그것을 `lost` 로 단정하면 사람이 없는 사실을 찾으러 간다.
|
|
175
|
+
*/
|
|
176
|
+
state: 'present' | 'lost' | 'unissued' | 'unknown';
|
|
177
|
+
/** 그 봉투의 발생 시각 — `present` 일 때만. 무엇이었는지 사람이 알아보는 데 쓴다. */
|
|
178
|
+
at?: string;
|
|
179
|
+
/** 그 봉투 자체 — `present` 이고 원본이 낼 수 있을 때만. 없어도 `state` 는 참이다. */
|
|
180
|
+
record?: unknown;
|
|
181
|
+
}
|
|
182
|
+
/** 번호 구간에 대해 원본이 아는 것 — **원본이 아는 것만 낸다. 판정은 사람이 한다.** */
|
|
183
|
+
export interface SeqReport {
|
|
184
|
+
scope: string;
|
|
185
|
+
entries: SeqEntry[];
|
|
186
|
+
/** 상한에 닿아 구간을 다 못 냈다 — 알리지 않고 자르지 않는다. */
|
|
187
|
+
truncated?: boolean;
|
|
188
|
+
}
|
|
189
|
+
export interface InboundBatch {
|
|
190
|
+
/**
|
|
191
|
+
* 옮긴 것들. 우리와 무관한 본문이면 빈 배열이다.
|
|
192
|
+
*
|
|
193
|
+
* **한 요청에 봉투가 여럿 온다.** 밀어 주는 쪽은 한 건씩 보내지 않는다 — 번호도 봉투마다 붙는다.
|
|
194
|
+
* 배치를 대표하는 번호 하나로는 가운데가 빠진 것을 알아채지 못한다.
|
|
195
|
+
*/
|
|
196
|
+
items: InboundItem[];
|
|
197
|
+
/**
|
|
198
|
+
* 이 요청의 번호가 어느 줄의 것인가. 번호를 매기지 않는 원본은 주지 않는다.
|
|
199
|
+
*
|
|
200
|
+
* 요청 하나가 한 줄에만 속한다 — 한 요청에 두 줄을 섞으면 어느 줄의 어디까지 받았는지를 응답
|
|
201
|
+
* 하나로 말할 수 없다.
|
|
202
|
+
*/
|
|
203
|
+
scope?: string;
|
|
204
|
+
/**
|
|
205
|
+
* (선택) **원본이 지금 가진 번호의 범위** — 우리 커서와 견주려면 이것이 있어야 한다.
|
|
206
|
+
*
|
|
207
|
+
* ── 왜 어댑터가 주나 (인티그레이션 레인 제안, 2026-09-06) ──────────────────
|
|
208
|
+
* 「가장 낮은 번호」를 묻는 방법이 원본마다 다르다. operato-plant 는
|
|
209
|
+
* `mesOutboxEvents(since: 0, limit: 1)` 이고, ppms·chef 는 아웃박스가 없어 번호 범위 자체가
|
|
210
|
+
* 없다. 프레임워크가 이것을 알 방법이 없다.
|
|
211
|
+
*
|
|
212
|
+
* ── 모르면 주지 않는다 ────────────────────────────────────────────────────
|
|
213
|
+
* **0 이나 추측을 넣지 않는다.** 0 을 넣으면 「원본이 1번부터 다 갖고 있다」로 읽히고, 그것이
|
|
214
|
+
* 거짓이면 「우리가 다 받았다」는 잘못된 결론이 나온다.
|
|
215
|
+
*
|
|
216
|
+
* `last` 에는 조건이 하나 붙는다. 쪽 상한에서 멈췄으면 그때의 번호는 **원본의 끝이 아니라
|
|
217
|
+
* 「여기까지 읽었다」**이므로 주지 않는다 — 주면 「원본에 더 없다」로 읽히는데 실제로는 더 있다.
|
|
218
|
+
*/
|
|
219
|
+
sourceRange?: {
|
|
220
|
+
first?: number;
|
|
221
|
+
last?: number;
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
export interface InboundItem {
|
|
225
|
+
/** 우리 어휘로 옮긴 레코드 하나. */
|
|
226
|
+
record: unknown;
|
|
227
|
+
/**
|
|
228
|
+
* 원본이 이 봉투에 붙인 id — **떨어졌을 때 그쪽이 자기 행을 찾는 열쇠다.**
|
|
229
|
+
*
|
|
230
|
+
* ── 왜 필요한가 (2026-09-07 측정) ──────────────────────────────────────────
|
|
231
|
+
* 훅 응답의 떨어진 목록이 `{ record, errors }` 였고, plant 은 그것을 **봉투 id 문자열 목록**으로
|
|
232
|
+
* 읽고 있었다. `Array.isArray` 는 통과하니 그쪽 guard 도 안 걸렸다 — id 를 맞추는데 객체라 하나도
|
|
233
|
+
* 안 맞고 **묶음 전체가 「보냈음」으로 찍혔다.** 422 와 `ok: false` 를 보냈는데도 그쪽 행은 재시도
|
|
234
|
+
* 0 · 오류 없음이었다.
|
|
235
|
+
*
|
|
236
|
+
* 이 값을 주면 응답이 `{ eventId, errors }` 로 나가고 그쪽이 그 행만 표시할 수 있다. 안 주면
|
|
237
|
+
* 레코드가 그대로 실려 나간다 — 무엇이 떨어졌는지 알 길이 그것뿐이고, 빈 id 를 실으면 보내는 쪽이
|
|
238
|
+
* 아무 행도 못 찾으면서 「알았다」고 여긴다.
|
|
239
|
+
*/
|
|
240
|
+
eventId?: string;
|
|
241
|
+
/**
|
|
242
|
+
* 이 봉투의 번호.
|
|
243
|
+
*
|
|
244
|
+
* **한 배치 안에서 있거나 없거나 하나로 통일한다.** 섞이면 빠진 것이 있는지 판단할 근거가 없다.
|
|
245
|
+
*/
|
|
246
|
+
seq?: number;
|
|
247
|
+
/**
|
|
248
|
+
* 이 봉투가 말하는 **발생 시각** — 레코드가 자기 시각을 안 말할 때 쓴다.
|
|
249
|
+
*
|
|
250
|
+
* ── 왜 필요한가 (2026-09-06 측정) ─────────────────────────────────────────
|
|
251
|
+
* 시각을 안 싣는 레코드는 `defaultEventTime`(= ingest 시각)으로 떨어진다. 그 값이 **실행할 때마다
|
|
252
|
+
* 다르다.** 그런데 fact identity 가 시각을 포함하므로, 같은 사실을 다시 받으면 dedupe 가 안 되고
|
|
253
|
+
* 새 사실로 앉는다.
|
|
254
|
+
*
|
|
255
|
+
* 실제로 그렇게 됐다. `fillTwinScope(from: 0)` 을 두 번 돌렸더니 mes-line-a 저널이
|
|
256
|
+
* 40 → 69건이 되고 중복이 27가지 생겼다. 시각을 말하는 레코드 12건만 되풀이로 걸러졌다.
|
|
257
|
+
*
|
|
258
|
+
* ── 봉투는 그 시각을 알고 있었다 ──────────────────────────────────────────
|
|
259
|
+
* plant 아웃박스가 `eventTime` 을 실어 보낸다. 그것이 갈 자리가 없어서 버려지고 있었다 —
|
|
260
|
+
* connector 주석이 그 위험을 적어 두고 자리를 요청해 두었다(`operato-plant.ts`).
|
|
261
|
+
*
|
|
262
|
+
* **레코드가 자기 시각을 말하면 그것이 이긴다.** 봉투의 시각은 「그 사실을 언제 보냈나」에 가깝고,
|
|
263
|
+
* 레코드의 시각은 「언제 일어났나」다. 둘이 다르면 뒤엣것이 맞다.
|
|
264
|
+
*/
|
|
265
|
+
at?: string;
|
|
266
|
+
}
|
|
127
267
|
/**
|
|
128
268
|
* 재기동을 넘어 이어지는 읽기 상태 — 참조 계층이 소유하고 어댑터에 건넨다(§`openLiveFeed`).
|
|
129
269
|
*
|
|
130
270
|
* 흐름 열쇠는 **어댑터가 정한다**(`Record`). 계약이 이름을 닫으면 새 원본마다 계약을 고치게 된다.
|
|
131
271
|
*/
|
|
132
272
|
export interface LiveFeedContinuity {
|
|
273
|
+
/**
|
|
274
|
+
* The name to take a task lease under, so only one instance polls this feed.
|
|
275
|
+
*
|
|
276
|
+
* ── Why this layer composes it ────────────────────────────────────────────
|
|
277
|
+
* `TaskLease` has no domain column on purpose: what is made exclusive is a
|
|
278
|
+
* loop, not a tenant's slice of one, and a task that does need to be
|
|
279
|
+
* per-tenant puts the tenant in the name so the unique index keeps meaning
|
|
280
|
+
* what it says.
|
|
281
|
+
*
|
|
282
|
+
* An adapter cannot follow that rule. It is handed `cfg` and `site`, and
|
|
283
|
+
* neither carries a domain — so a name built from `siteId` alone would let
|
|
284
|
+
* two domains that happen to use the same plant code block each other's
|
|
285
|
+
* channel. Silently, and looking exactly like "someone else holds it".
|
|
286
|
+
*
|
|
287
|
+
* So the name is composed here, where `domainId` and `instanceId` are known,
|
|
288
|
+
* and the rule lives in one place.
|
|
289
|
+
*
|
|
290
|
+
* ── Always present, unlike `cursor` ───────────────────────────────────────
|
|
291
|
+
* A feed needs its lease on the very first attach, before there is any
|
|
292
|
+
* cursor to carry. So this object is now handed over even when nothing has
|
|
293
|
+
* been read yet; `cursor` being absent is what still says "first attach",
|
|
294
|
+
* which is how every connector already reads it (`continuity?.cursor`).
|
|
295
|
+
*/
|
|
296
|
+
leaseName: string;
|
|
133
297
|
/** 지난번에 어디까지 읽었나 — 없으면 첫 붙음이다(그때만 되돌아볼 날수로 창을 만든다). */
|
|
134
298
|
cursor?: {
|
|
135
299
|
streams?: Record<string, LiveFeedCursor>;
|
|
@@ -261,6 +425,23 @@ export interface LiveFeedContinuity {
|
|
|
261
425
|
count: number;
|
|
262
426
|
}) => void;
|
|
263
427
|
}
|
|
428
|
+
/**
|
|
429
|
+
* 저쪽이 조치를 받을 준비가 됐나 — **「모른다」를 「안 된다」로 답하지 않는다.**
|
|
430
|
+
*
|
|
431
|
+
* `ready` 가 거짓이면 `reason` 이 사람의 말로 무엇이 없는지 말하고, `code` 가 화면이 다음 할 일을
|
|
432
|
+
* 가를 값이다(문장을 파싱하지 않게 — 번역하면 문장이 바뀐다).
|
|
433
|
+
*/
|
|
434
|
+
export interface ActuationReadiness {
|
|
435
|
+
/** 받을 수 있어 보이나. **모르면 `undefined`** — 거짓이 아니다. */
|
|
436
|
+
ready?: boolean;
|
|
437
|
+
/** 어디까지 봤나. `local` = 우리 설정만 봤다(망을 타지 않았다). `remote` = 저쪽에 물었다. */
|
|
438
|
+
checked: 'local' | 'remote';
|
|
439
|
+
/** 무엇이 없나 — 사람의 말로. */
|
|
440
|
+
reason?: string;
|
|
441
|
+
/** 화면이 가를 값. 커넥터가 정한다(예: `no-endpoint` · `no-secret` · `unreachable` · `not-configured`). */
|
|
442
|
+
code?: string;
|
|
443
|
+
}
|
|
444
|
+
import type { LiveCadence } from './live-cadence.js';
|
|
264
445
|
export interface ReferenceAdapter {
|
|
265
446
|
/** 레지스트리 키 (예: 'virtual' | 'sap-ewm' | 'custom-rest'). */
|
|
266
447
|
type: string;
|
|
@@ -283,6 +464,20 @@ export interface ReferenceAdapter {
|
|
|
283
464
|
* 원본에 없는 자리는 선언하지 않는다. 그러면 「이 원본으로 채울 수 있는 만큼」이 곧 분모가 된다.
|
|
284
465
|
*/
|
|
285
466
|
masterSteps?: readonly ReferenceStep[];
|
|
467
|
+
/**
|
|
468
|
+
* 이 원천이 **축마다 언제·얼마나 자주 내놓나** — 유입 건강이 이 선언으로 견준다.
|
|
469
|
+
*
|
|
470
|
+
* 선언하지 않은 축은 **지금까지처럼** 창 하나(10분)로 견준다. 그러면 밤에 발전하지 않는
|
|
471
|
+
* 태양광과 업무시간만 도는 원천이 **정상인데 매일 밤 빨갛게** 난다 — 거짓 빨강이 쌓이면 진짜
|
|
472
|
+
* 빨강도 같이 안 읽힌다.
|
|
473
|
+
*
|
|
474
|
+
* `masterSteps` 와 같은 규율이다: **어댑터만 자기 시간의 결을 안다.** 호스트가 짐작하면 그것은
|
|
475
|
+
* 지어낸 판정이다.
|
|
476
|
+
*
|
|
477
|
+
* 자세한 것은 §`live-cadence.ts` — 특히 「해 있는 동안」을 **고정 시각으로 박지 말 것**
|
|
478
|
+
* (오늘 잰 일몰은 두 달 뒤에 틀리다).
|
|
479
|
+
*/
|
|
480
|
+
liveCadence?: readonly LiveCadence[];
|
|
286
481
|
/**
|
|
287
482
|
* @param onStep 진행을 알리는 통로 — **선택이다.** 주지 않으면 예전과 같이 동작한다.
|
|
288
483
|
*
|
|
@@ -344,10 +539,168 @@ export interface ReferenceAdapter {
|
|
|
344
539
|
* ── 판단은 여기서 한다 ────────────────────────────────────────────────────
|
|
345
540
|
* 통신이 끊긴 설비의 값을 보내지 않는 것, 잰 시각이 나아가지 않은 줄을 거르는 것 — 폴링에서 하던
|
|
346
541
|
* 판단을 여기서도 한다. 그래야 두 길이 같은 답을 낸다.
|
|
542
|
+
*
|
|
543
|
+
* ── 번호는 프레임워크가 본다 (2026-08-31) ─────────────────────────────────
|
|
544
|
+
* 빠진 번호를 알아채는 일은 밀어 주는 모든 연결에 같은 규율이라야 한다. 커넥터마다 만들면 한 곳이
|
|
545
|
+
* 빠지고, 빠진 그 연결에서만 사실이 없어진다. 그래서 커넥터는 **번호를 꺼내 주기만** 하고 판정은
|
|
546
|
+
* 프레임워크가 한다(§`reference-hook`).
|
|
347
547
|
*/
|
|
348
548
|
handleInbound?(cfg: ConnectionConfig, site: {
|
|
349
549
|
siteId: string;
|
|
350
|
-
}, body: unknown, headers: Record<string, unknown>):
|
|
550
|
+
}, body: unknown, headers: Record<string, unknown>): InboundBatch;
|
|
551
|
+
/**
|
|
552
|
+
* **현장에 조치를 내린다** — 인바운드의 반대 면(§`command-routing.md` §8.1).
|
|
553
|
+
*
|
|
554
|
+
* 별개 어댑터를 두지 않는다. 같은 연결이 사실을 읽고 조치를 내리므로, 인증과 설정이 한 자리에 있어야
|
|
555
|
+
* 한다. 둘로 나누면 같은 시스템에 두 벌의 연결 설정이 생긴다.
|
|
556
|
+
*
|
|
557
|
+
* ── 승인은 이미 지났다 (2026-08-31) ───────────────────────────────────────
|
|
558
|
+
* 인자가 `ApprovedCommand` 다 — 그 표식은 승인을 지난 커맨드에만 붙고, 디스패처가 붙인다
|
|
559
|
+
* (§`command-dispatcher.ts`). **어댑터는 승인을 다시 확인하지 않는다.** 확인이 두 곳에 있으면
|
|
560
|
+
* 규칙이 두 벌이 되고 한쪽만 고쳐지는 날이 온다.
|
|
561
|
+
*
|
|
562
|
+
* 이 자리를 게이트보다 먼저 열지 않은 이유가 있다 — 자리가 있으면 누군가 부르고, 그때 사람 승인 없이
|
|
563
|
+
* 현장에 작업지시가 나간다. 작업지시는 취소해도 이미 만든 것이 남는다.
|
|
564
|
+
*
|
|
565
|
+
* ── 돌려줄 것 ─────────────────────────────────────────────────────────────
|
|
566
|
+
* `ref` 를 **반드시** 돌려준다. 그것이 없으면 넘긴 것이 저쪽에서 무엇이 되었는지 되짚을 수 없고,
|
|
567
|
+
* 되돌릴 때 무엇을 되돌릴지 말할 수 없다.
|
|
568
|
+
*/
|
|
569
|
+
actuate?(cfg: ConnectionConfig, site: SiteDescriptor, command: ApprovedCommand): Promise<{
|
|
570
|
+
ok: boolean;
|
|
571
|
+
ref?: string;
|
|
572
|
+
/**
|
|
573
|
+
* **받아들였으나 남은 것이 있다** — 실패가 아니다. 사람이 저쪽에서 해야 할 일이 있으면 여기 적는다.
|
|
574
|
+
*
|
|
575
|
+
* `error` 에 적지 말 것 — 실패로 읽혀 커맨드가 `failed` 로 앉고, 다시 넘기게 된다. 실제로 MES 가
|
|
576
|
+
* 「지시서를 못 붙였다」를 답했을 때 커넥터가 적을 칸이 없어 로그로만 남겼고, 트윈 쪽에서는 성공한
|
|
577
|
+
* 조치와 구별되지 않았다.
|
|
578
|
+
*/
|
|
579
|
+
note?: string;
|
|
580
|
+
/**
|
|
581
|
+
* 그 말 중 **다음에 할 일** 한 줄 — 원인은 위 `note` 다.
|
|
582
|
+
*
|
|
583
|
+
* 붙여 보내지 말 것. 읽는 사람은 「그래서 내가 뭘 해야 하나」를 먼저 찾고, 한 문장으로 오면
|
|
584
|
+
* **화면이 자르게 되며 자르는 규칙이 화면마다 생긴다.** 어댑터는 이미 둘로 알고 있다.
|
|
585
|
+
*/
|
|
586
|
+
noteNext?: string;
|
|
587
|
+
error?: string;
|
|
588
|
+
/**
|
|
589
|
+
* **다시 해서 될 일인가** — 실패했을 때만.
|
|
590
|
+
*
|
|
591
|
+
* again 그대로 다시 해 볼 만하다 못 닿았거나 저쪽이 잠깐 흔들렸다
|
|
592
|
+
* after-fix 사람이 고친 뒤 그대로 나간다 설정 문제
|
|
593
|
+
* never 이 조치로는 영원히 안 된다 지시 내용이 틀렸다
|
|
594
|
+
*
|
|
595
|
+
* 가르는 자리는 **「조치를 다시 낼 필요가 있나」**다. 설정이 틀린 것은 조치가 멀쩡하므로
|
|
596
|
+
* `after-fix`, 지시 내용이 틀린 것은 그 조치가 영원히 틀렸으므로 `never` 다.
|
|
597
|
+
*
|
|
598
|
+
* **문장에 담지 말 것** — 일꾼이 그것을 쓰려면 파싱해야 하고, 번역되면 깨진다.
|
|
599
|
+
*
|
|
600
|
+
* 말하지 않으면 일꾼이 **집지 않는다.** 모르는 것을 `never` 로 접으면 고칠 수 있는 것을 사람이
|
|
601
|
+
* 포기하고, `again` 으로 접으면 없는 자재를 끝없이 두드린다.
|
|
602
|
+
*/
|
|
603
|
+
retry?: 'again' | 'after-fix' | 'never';
|
|
604
|
+
}>;
|
|
605
|
+
/**
|
|
606
|
+
* **저쪽이 조치를 받을 준비가 됐나** — 보내기 전에 묻는다. 선택이다.
|
|
607
|
+
*
|
|
608
|
+
* ── 왜 필요한가 (2026-09-03 실측) ──────────────────────────────────────────
|
|
609
|
+
* 승인된 조치를 넘겼더니 저쪽이 503 을 답했다 — **저쪽 프로세스에 비밀값이 실려 있지 않았다.**
|
|
610
|
+
* 트윈 쪽 연결 설정에는 있었고, 주소도 맞았고, 서명도 맞았다. 저쪽이 재기동되면서 환경 변수에만
|
|
611
|
+
* 살던 값을 잃은 것이다.
|
|
612
|
+
*
|
|
613
|
+
* 그것을 보내 보기 전에는 알 수 없었다. 그래서 사람이 승인 화면까지 가서 누르고, 실패를 보고,
|
|
614
|
+
* 다시 로그인했다. **승인이 사라지지는 않는다**(`failed → dispatch` 가 열려 있다) — 없어진 것은
|
|
615
|
+
* 사람의 시간이다.
|
|
616
|
+
*
|
|
617
|
+
* ── 문이 아니다. 알림이다 ──────────────────────────────────────────────────
|
|
618
|
+
* **이 답으로 넘김을 막지 않는다.** 막으면 새 실패 방식이 생긴다 — 점검이 틀렸거나 잠깐 못 닿은
|
|
619
|
+
* 사이에, 성공할 수 있었던 조치가 못 나간다. 화면이 「지금 저쪽이 못 받는 것으로 보입니다」를
|
|
620
|
+
* 미리 말하는 데까지가 이 얼굴의 일이다.
|
|
621
|
+
*
|
|
622
|
+
* ── 두 겹을 구별한다 ──────────────────────────────────────────────────────
|
|
623
|
+
* 우리 쪽에 무엇이 없는 것(주소·비밀값을 설정하지 않았다)은 **망을 타지 않고** 알 수 있다.
|
|
624
|
+
* 저쪽이 받을 준비가 됐는지는 물어야 안다. 앞엣것만 답하고 뒤엣것을 안 물어도 되고, 그때
|
|
625
|
+
* `checked: 'local'` 로 그 사실을 말한다 — 「살아 있다」고 말한 적 없는 것과 「죽었다」는 다르다.
|
|
626
|
+
*
|
|
627
|
+
* 화면이 그릴 때마다 부를 수 있으므로 **망을 타는 구현은 짧게 끝내야 한다.**
|
|
628
|
+
*/
|
|
629
|
+
actuationReadiness?(cfg: ConnectionConfig, site: SiteDescriptor): Promise<ActuationReadiness>;
|
|
630
|
+
/**
|
|
631
|
+
* **놓친 구간을 backfill 한다** — 밀어 주는 길의 짝.
|
|
632
|
+
*
|
|
633
|
+
* ── 왜 필요한가 (2026-08-31, 인티그레이션 레인 지적) ──────────────────────
|
|
634
|
+
* 훅은 반드시 놓친다 — 우리가 내려가 있을 때, 그쪽이 못 보냈을 때, 네트워크가 끊겼을 때. 받는 쪽이
|
|
635
|
+
* 번호로 그것을 **알아채게** 되었지만(§`takeInSequence`), 알아챈 뒤 **그 사이를 채우는 길이 없었다.**
|
|
636
|
+
* 설계가 그 길을 적어 두었는데 만들지 않았다.
|
|
637
|
+
*
|
|
638
|
+
* ── 왜 `since` 가 번호인가 ────────────────────────────────────────────────
|
|
639
|
+
* 커서에 사는 것이 번호이고, 보내는 쪽이 되풀어 주는 단위도 번호다. 시각으로 두면 두 축이 섞이고,
|
|
640
|
+
* 같은 밀리초의 두 행이 갈리지 않는다.
|
|
641
|
+
*
|
|
642
|
+
* ── 왜 `scope` 를 프레임워크가 주나 ───────────────────────────────────────
|
|
643
|
+
* 그것이 커서 열쇠의 절반이다. 커넥터가 만들면 열쇠를 만드는 자리가 둘이 되고, 어긋난 그곳은 조용하다.
|
|
644
|
+
* 그래서 프레임워크가 커서에서 읽어 그대로 넘긴다.
|
|
645
|
+
*
|
|
646
|
+
* 답이 `InboundBatch` 인 이유도 하나다 — **backfill 한 것이 밀어 받은 것과 같은 번호 검사를 지난다.**
|
|
647
|
+
* 다른 모양으로 돌려주면 그 검사를 다시 만들게 되고, 두 길이 다른 규칙으로 받는다.
|
|
648
|
+
*/
|
|
649
|
+
fetchSince?(cfg: ConnectionConfig, site: SiteDescriptor, scope: string, since: number): Promise<InboundBatch>;
|
|
650
|
+
/**
|
|
651
|
+
* (선택) **원본에만 있는 관계를 조회한다** — 트윈으로 복제하지 않고 그때그때 물어본다.
|
|
652
|
+
*
|
|
653
|
+
* ── 왜 필요한가 ─────────────────────────────────────────────────────────────
|
|
654
|
+
* 트윈은 표준 어휘로 옮길 수 있는 것만 담는다. 원본에는 그 밖의 관계가 있다 — MES 의 생산 실적,
|
|
655
|
+
* 설비 상태 구간, 정비 계획. 설비 상세 화면에서 사람이 실제로 묻는 것이 그런 것들이다.
|
|
656
|
+
*
|
|
657
|
+
* 이것을 트윈으로 복제하면 원본의 표를 전부 미러링하게 된다. 조회용 참조는 복제하지 않고 그때
|
|
658
|
+
* 물어보는 것이 맞다.
|
|
659
|
+
*
|
|
660
|
+
* ── 왜 어댑터가 답하나 ──────────────────────────────────────────────────────
|
|
661
|
+
* 어느 테이블에 무엇이 있는지는 원본마다 다르다. 커널이 그것을 알면 원본 하나의 스키마에 묶이고,
|
|
662
|
+
* 다음 원본이 다른 구조를 쓰면 커널을 또 고친다.
|
|
663
|
+
*
|
|
664
|
+
* 어댑터는 이미 그 원본에 붙는 방법과 인증을 갖고 있다. 연결 설정이 한 자리에 있어야 한다는 것은
|
|
665
|
+
* `actuate` 를 별개 어댑터로 두지 않은 것과 같은 이유다.
|
|
666
|
+
*
|
|
667
|
+
* ── 실패하면 그것을 알린다 ──────────────────────────────────────────────────
|
|
668
|
+
* 예외를 던져도 됩니다. 호출하는 쪽이 잡아서 「조회 실패」로 표시하고, 나머지 관계는 그대로
|
|
669
|
+
* 표시합니다. 빈 배열은 「가리키는 것이 없다」는 뜻이고 실패와 다릅니다.
|
|
670
|
+
*
|
|
671
|
+
* @param axis `equipment` · `locations` 등 계약의 축 이름
|
|
672
|
+
* @param itemId 그 축에서의 식별자. 원본이 아는 이름이다(설비는 `ops_equipment.name`)
|
|
673
|
+
*/
|
|
674
|
+
fetchLinks?(cfg: ConnectionConfig, site: SiteDescriptor | undefined, axis: string, itemId: string): Promise<ReferenceLinkGroup[]>;
|
|
675
|
+
/**
|
|
676
|
+
* (선택) **그 번호가 무엇이었나** — 구멍을 만났을 때 묻는다.
|
|
677
|
+
*
|
|
678
|
+
* ── 왜 필요한가 (2026-09-06 실물) ──────────────────────────────────────────
|
|
679
|
+
* 커넥터가 구멍을 만나면 「418 다음이 420」이라고만 말한다. **419 가 무엇이었는지 알 방법이
|
|
680
|
+
* 없다.** 그날 plant 레인이 자기 아웃박스를 손으로 뒤져서 그것이 부하 시험의 흔적임을 찾았다.
|
|
681
|
+
*
|
|
682
|
+
* 구멍은 채널을 세운다 — 그 뒤의 사실이 통째로 못 온다. 그래서 「이게 무엇이었나」가 급한 물음인데
|
|
683
|
+
* 물을 자리가 없었다.
|
|
684
|
+
*
|
|
685
|
+
* ── 세 가지를 가른다. 넷째는 「모른다」다 ──────────────────────────────────
|
|
686
|
+
* ```
|
|
687
|
+
* present 그 행이 있다 — 봉투를 함께 낸다
|
|
688
|
+
* lost 번호는 나갔는데 행이 없다 — 쓰기 하나를 잃었다
|
|
689
|
+
* unissued 아직 그 번호까지 안 갔다 — 잃은 것이 아니다
|
|
690
|
+
* unknown 원본이 그 셋을 구별하지 못한다
|
|
691
|
+
* ```
|
|
692
|
+
*
|
|
693
|
+
* **`unknown` 이 있어야 한다.** 채번을 따로 들지 않는 원본은 「행이 없다」에서 `lost` 와
|
|
694
|
+
* `unissued` 를 가를 수 없다. 그때 `lost` 로 단정하면 사람이 없는 사실을 찾으러 간다.
|
|
695
|
+
*
|
|
696
|
+
* ── 판정을 여기서 하지 않는다 ─────────────────────────────────────────────
|
|
697
|
+
* 이 문은 **원본이 아는 것을 그대로 낸다.** 「그러니 이 번호는 포기해도 된다」는 판정은 사람이
|
|
698
|
+
* 한다 — 그 판단은 되돌릴 수 없어서(커서가 지나가면 끝이다) 코드가 대신할 자리가 아니다.
|
|
699
|
+
*
|
|
700
|
+
* @param from 이 번호부터(포함)
|
|
701
|
+
* @param to 이 번호까지(포함). 원본이 상한을 두면 그만큼만 내고 `truncated` 로 말한다
|
|
702
|
+
*/
|
|
703
|
+
seqReport?(cfg: ConnectionConfig, site: SiteDescriptor | undefined, scope: string, from: number, to: number): Promise<SeqReport>;
|
|
351
704
|
openLiveFeed?(cfg: ConnectionConfig, site: SiteDescriptor, onRecords: (records: unknown[]) => void, continuity?: LiveFeedContinuity): () => void;
|
|
352
705
|
/**
|
|
353
706
|
* 이 원본이 **선언하는 능력** — 없으면 「구조만 준다」는 뜻이다(ADR-0029 §8).
|
|
@@ -38,6 +38,14 @@ function capabilitiesOf(adapter) {
|
|
|
38
38
|
out.push('live');
|
|
39
39
|
if (declared.has('control') && typeof adapter.control === 'function')
|
|
40
40
|
out.push('control');
|
|
41
|
+
if (declared.has('actuate') && typeof adapter.actuate === 'function')
|
|
42
|
+
out.push('actuate');
|
|
43
|
+
/*
|
|
44
|
+
* **선언만으로 성립한다** — 부를 메서드가 없다. 「두 번 해도 같은가」는 어댑터가 하는 일이 아니고
|
|
45
|
+
* 저쪽 시스템의 성질이다. 그래서 구현 검사를 하지 않는다.
|
|
46
|
+
*/
|
|
47
|
+
if (declared.has('idempotent-actuation'))
|
|
48
|
+
out.push('idempotent-actuation');
|
|
41
49
|
return out;
|
|
42
50
|
}
|
|
43
51
|
/* 어댑터 "타입" 레지스트리(전역·인메모리) — 레퍼런스 데이터는 DB(TwinReference), 어댑터 동작은 여기. */
|
|
@@ -63,7 +71,17 @@ const adapters = new Map();
|
|
|
63
71
|
*/
|
|
64
72
|
function registerAdapterType(adapter) {
|
|
65
73
|
const declared = new Set(adapter.capabilities ?? []);
|
|
66
|
-
|
|
74
|
+
/* 능력 이름과 그것을 증명하는 메서드 — **한 자리에 적는다.** 두 벌이면 새 능력이 한쪽에만 늘어난다. */
|
|
75
|
+
const METHOD_OF = {
|
|
76
|
+
live: 'openLiveFeed',
|
|
77
|
+
control: 'control',
|
|
78
|
+
actuate: 'actuate',
|
|
79
|
+
/* 성질 선언이라 부를 메서드가 없다 — 어댑터가 `capabilities` 에 적는 것으로 끝난다. */
|
|
80
|
+
'idempotent-actuation': ''
|
|
81
|
+
};
|
|
82
|
+
const undeclared = Object.keys(METHOD_OF).filter(
|
|
83
|
+
/* 메서드 이름이 없는 능력(선언만으로 성립하는 것)은 이 경고의 대상이 아니다. */
|
|
84
|
+
c => METHOD_OF[c] !== '' && typeof adapter[METHOD_OF[c]] === 'function' && !declared.has(c));
|
|
67
85
|
if (undeclared.length) {
|
|
68
86
|
(0, log_js_1.twinWarn)(`[reference] connector "${adapter.type}" implements ${undeclared.join(' and ')} but does not declare it — ` +
|
|
69
87
|
`add capabilities: [${undeclared.map(c => `'${c}'`).join(', ')}] or remove the implementation. ` +
|