@things-factory/headless-twin 10.1.278 → 10.1.280
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/package.json +21 -7
- package/dist-server/engine/attention-digest.js.map +0 -1
- package/dist-server/engine/canonical-ingest.js.map +0 -1
- package/dist-server/engine/checkpoint-fold.js.map +0 -1
- package/dist-server/engine/command-routing.js.map +0 -1
- package/dist-server/engine/declared-stimulus.js.map +0 -1
- package/dist-server/engine/energy-topology.js.map +0 -1
- package/dist-server/engine/event-time.js.map +0 -1
- package/dist-server/engine/index.js.map +0 -1
- package/dist-server/engine/ingest-dedupe.js.map +0 -1
- package/dist-server/engine/ingest-health.js.map +0 -1
- package/dist-server/engine/integration-coverage.js.map +0 -1
- package/dist-server/engine/integration-probes.js.map +0 -1
- package/dist-server/engine/integration-runner.js.map +0 -1
- package/dist-server/engine/integration-target-profile.js.map +0 -1
- package/dist-server/engine/kpi-baseline.js.map +0 -1
- package/dist-server/engine/kpi-fold.js.map +0 -1
- package/dist-server/engine/kpi-query.js.map +0 -1
- package/dist-server/engine/kpi-target.js.map +0 -1
- package/dist-server/engine/live-attentions.js.map +0 -1
- package/dist-server/engine/live-feed-registry.js.map +0 -1
- package/dist-server/engine/load-meter.js.map +0 -1
- package/dist-server/engine/local-declarations.js.map +0 -1
- package/dist-server/engine/log.js.map +0 -1
- package/dist-server/engine/loop-lag.js.map +0 -1
- package/dist-server/engine/measured-estimator.js.map +0 -1
- package/dist-server/engine/measured-yield.js.map +0 -1
- package/dist-server/engine/model-basis.js.map +0 -1
- package/dist-server/engine/model-gap.js.map +0 -1
- package/dist-server/engine/model-refusal.js.map +0 -1
- package/dist-server/engine/model-vocabulary.js.map +0 -1
- package/dist-server/engine/oee-accumulator.js.map +0 -1
- package/dist-server/engine/operation-basis.js.map +0 -1
- package/dist-server/engine/producer-guard.js.map +0 -1
- package/dist-server/engine/property-effects.js.map +0 -1
- package/dist-server/engine/read-time.js.map +0 -1
- package/dist-server/engine/restart-policy.js.map +0 -1
- package/dist-server/engine/runtime-key.js.map +0 -1
- package/dist-server/engine/spec-coverage.js.map +0 -1
- package/dist-server/engine/stage-path.js.map +0 -1
- package/dist-server/engine/state-axes.js.map +0 -1
- package/dist-server/engine/structure-diff.js.map +0 -1
- package/dist-server/engine/travel-estimator.js.map +0 -1
- package/dist-server/engine/twin-engine.js.map +0 -1
- package/dist-server/engine/twin-state-channel.js.map +0 -1
- package/dist-server/engine/warm-start.js.map +0 -1
- package/dist-server/index.js.map +0 -1
- package/dist-server/migrations/1786000000000-RenameTwinInstanceBoardToModel.js.map +0 -1
- package/dist-server/migrations/1786100000000-PromoteEventActionAndSyncWarnings.js.map +0 -1
- package/dist-server/migrations/1786200000000-CarryLiveFeedCursor.js.map +0 -1
- package/dist-server/migrations/1786300000000-IndexEventTypeByTime.js.map +0 -1
- package/dist-server/migrations/1786400000000-IndexEventCreatedAt.js.map +0 -1
- package/dist-server/migrations/1786500000000-CreateTwinSubjectEvents.js.map +0 -1
- package/dist-server/migrations/1786600000000-RenameOperatoMesAdapterType.js.map +0 -1
- package/dist-server/migrations/1786700000000-AddDispatchRetryColumns.js.map +0 -1
- package/dist-server/migrations/1786800000000-CreateTwinReferenceReconciliations.js.map +0 -1
- package/dist-server/migrations/index.js.map +0 -1
- package/dist-server/routes.js.map +0 -1
- package/dist-server/service/actuation/actuation-advisor.js.map +0 -1
- package/dist-server/service/actuation/actuation-outcome.js.map +0 -1
- package/dist-server/service/actuation/actuation-rule-resolver.js.map +0 -1
- package/dist-server/service/actuation/actuation-rule.js.map +0 -1
- package/dist-server/service/actuation/approval-gateway.js.map +0 -1
- package/dist-server/service/actuation/catch-up-effects.js.map +0 -1
- package/dist-server/service/actuation/command-dispatcher.js.map +0 -1
- package/dist-server/service/actuation/command-store.js.map +0 -1
- package/dist-server/service/actuation/dispatch-after-approval.js.map +0 -1
- package/dist-server/service/actuation/effect-match.js.map +0 -1
- package/dist-server/service/actuation/index.js.map +0 -1
- package/dist-server/service/actuation/retry-plan.js.map +0 -1
- package/dist-server/service/actuation/rule-evaluate.js.map +0 -1
- package/dist-server/service/actuation/rule-loop.js.map +0 -1
- package/dist-server/service/actuation/rule-runner.js.map +0 -1
- package/dist-server/service/actuation/rule-wiring.js.map +0 -1
- package/dist-server/service/actuation/settle-effects.js.map +0 -1
- package/dist-server/service/actuation/sweep-dispatch.js.map +0 -1
- package/dist-server/service/actuation/twin-command-resolver.js.map +0 -1
- package/dist-server/service/actuation/twin-command.js.map +0 -1
- package/dist-server/service/actuation/twin-now.js.map +0 -1
- package/dist-server/service/index.js.map +0 -1
- package/dist-server/service/reference/actuation-routing.js.map +0 -1
- package/dist-server/service/reference/actuation-target.js.map +0 -1
- package/dist-server/service/reference/actuation-verification.js.map +0 -1
- package/dist-server/service/reference/attention-lane.js.map +0 -1
- package/dist-server/service/reference/connection-portability-resolver.js.map +0 -1
- package/dist-server/service/reference/connection-portability.js.map +0 -1
- package/dist-server/service/reference/control-routing.js.map +0 -1
- package/dist-server/service/reference/discovery-result.js.map +0 -1
- package/dist-server/service/reference/fill-cadence.js.map +0 -1
- package/dist-server/service/reference/fill-dedupe.js.map +0 -1
- package/dist-server/service/reference/fill-loop.js.map +0 -1
- package/dist-server/service/reference/fill-span.js.map +0 -1
- package/dist-server/service/reference/hook-contract.js.map +0 -1
- package/dist-server/service/reference/hook-rejected.js.map +0 -1
- package/dist-server/service/reference/hook-store.js.map +0 -1
- package/dist-server/service/reference/index.js.map +0 -1
- package/dist-server/service/reference/ingest-space.js.map +0 -1
- package/dist-server/service/reference/knob-defaults.js.map +0 -1
- package/dist-server/service/reference/live-cadence.js.map +0 -1
- package/dist-server/service/reference/live-feed-lease.js.map +0 -1
- package/dist-server/service/reference/live-ingest.js.map +0 -1
- package/dist-server/service/reference/reference-adapter.js.map +0 -1
- package/dist-server/service/reference/reference-assessment.js.map +0 -1
- package/dist-server/service/reference/reference-fill-run.js.map +0 -1
- package/dist-server/service/reference/reference-fill.js.map +0 -1
- package/dist-server/service/reference/reference-hook.js.map +0 -1
- package/dist-server/service/reference/reference-link-groups.js.map +0 -1
- package/dist-server/service/reference/reference-links.js.map +0 -1
- package/dist-server/service/reference/reference-live.js.map +0 -1
- package/dist-server/service/reference/reference-master.js.map +0 -1
- package/dist-server/service/reference/reference-probe.js.map +0 -1
- package/dist-server/service/reference/reference-progress-channel.js.map +0 -1
- package/dist-server/service/reference/reference-progress-subscription.js.map +0 -1
- package/dist-server/service/reference/reference-progress.js.map +0 -1
- package/dist-server/service/reference/reference-reconciliation-query.js.map +0 -1
- package/dist-server/service/reference/reference-reconciliation-writer.js.map +0 -1
- package/dist-server/service/reference/reference-reconciliation.js.map +0 -1
- package/dist-server/service/reference/reference-registry.js.map +0 -1
- package/dist-server/service/reference/reference-resolver.js.map +0 -1
- package/dist-server/service/reference/template-registry.js.map +0 -1
- package/dist-server/service/reference/twin-reference-reconciliation.js.map +0 -1
- package/dist-server/service/reference/twin-reference.js.map +0 -1
- package/dist-server/service/twin-attention/index.js.map +0 -1
- package/dist-server/service/twin-attention/twin-attention-query.js.map +0 -1
- package/dist-server/service/twin-audit/command-audit.js.map +0 -1
- package/dist-server/service/twin-audit/index.js.map +0 -1
- package/dist-server/service/twin-audit/twin-audit-event.js.map +0 -1
- package/dist-server/service/twin-audit/twin-audit-query.js.map +0 -1
- package/dist-server/service/twin-backfill/backfill-period-facts.js.map +0 -1
- package/dist-server/service/twin-backfill/backfill-shape.js.map +0 -1
- package/dist-server/service/twin-backfill/index.js.map +0 -1
- package/dist-server/service/twin-backfill/twin-backfill-resolver.js.map +0 -1
- package/dist-server/service/twin-control/index.js.map +0 -1
- package/dist-server/service/twin-control/twin-control-mutation.js.map +0 -1
- package/dist-server/service/twin-event/index.js.map +0 -1
- package/dist-server/service/twin-event/journal-count.js.map +0 -1
- package/dist-server/service/twin-event/twin-event-keys.js.map +0 -1
- package/dist-server/service/twin-event/twin-event-type.js.map +0 -1
- package/dist-server/service/twin-event/twin-event.js.map +0 -1
- package/dist-server/service/twin-forecast/forecast-metrics.js.map +0 -1
- package/dist-server/service/twin-forecast/forecast-tuning.js.map +0 -1
- package/dist-server/service/twin-forecast/gap-analytics.js.map +0 -1
- package/dist-server/service/twin-forecast/index.js.map +0 -1
- package/dist-server/service/twin-forecast/twin-forecast-query.js.map +0 -1
- package/dist-server/service/twin-ingest-window/index.js.map +0 -1
- package/dist-server/service/twin-ingest-window/twin-ingest-window-query.js.map +0 -1
- package/dist-server/service/twin-ingest-window/twin-ingest-window-writer.js.map +0 -1
- package/dist-server/service/twin-ingest-window/twin-ingest-window.js.map +0 -1
- package/dist-server/service/twin-instance/index.js.map +0 -1
- package/dist-server/service/twin-instance/twin-instance.js.map +0 -1
- package/dist-server/service/twin-journal/event-type-split-shape.js.map +0 -1
- package/dist-server/service/twin-journal/event-type-split.js.map +0 -1
- package/dist-server/service/twin-journal/index.js.map +0 -1
- package/dist-server/service/twin-journal/journal-order.js.map +0 -1
- package/dist-server/service/twin-journal/twin-journal-query.js.map +0 -1
- package/dist-server/service/twin-lifecycle/domain-catalog.js.map +0 -1
- package/dist-server/service/twin-lifecycle/index.js.map +0 -1
- package/dist-server/service/twin-lifecycle/twin-lifecycle-mutation.js.map +0 -1
- package/dist-server/service/twin-metrics/index.js.map +0 -1
- package/dist-server/service/twin-metrics/twin-metrics-query.js.map +0 -1
- package/dist-server/service/twin-model/axis-journal-evidence.js.map +0 -1
- package/dist-server/service/twin-model/choose-recipe.js.map +0 -1
- package/dist-server/service/twin-model/epcis-coverage.js.map +0 -1
- package/dist-server/service/twin-model/external-resolver.js.map +0 -1
- package/dist-server/service/twin-model/iec61850-coverage.js.map +0 -1
- package/dist-server/service/twin-model/index.js.map +0 -1
- package/dist-server/service/twin-model/isa95-coverage.js.map +0 -1
- package/dist-server/service/twin-model/item-ref.js.map +0 -1
- package/dist-server/service/twin-model/name-index.js.map +0 -1
- package/dist-server/service/twin-model/project-structure.js.map +0 -1
- package/dist-server/service/twin-model/standard-coverage.js.map +0 -1
- package/dist-server/service/twin-model/status-tally.js.map +0 -1
- package/dist-server/service/twin-model/twin-equipment.js.map +0 -1
- package/dist-server/service/twin-model/twin-lineage-query.js.map +0 -1
- package/dist-server/service/twin-model/twin-location.js.map +0 -1
- package/dist-server/service/twin-model/twin-model-item-query.js.map +0 -1
- package/dist-server/service/twin-model/twin-model-mutation.js.map +0 -1
- package/dist-server/service/twin-model/twin-model-query.js.map +0 -1
- package/dist-server/service/twin-model/twin-model-tree-query.js.map +0 -1
- package/dist-server/service/twin-model/twin-operation.js.map +0 -1
- package/dist-server/service/twin-readiness/index.js.map +0 -1
- package/dist-server/service/twin-readiness/twin-readiness-query.js.map +0 -1
- package/dist-server/service/twin-space/area-resolver.js.map +0 -1
- package/dist-server/service/twin-space/index.js.map +0 -1
- package/dist-server/service/twin-space/move-space.js.map +0 -1
- package/dist-server/service/twin-space/representation-role.js.map +0 -1
- package/dist-server/service/twin-space/space-integrity.js.map +0 -1
- package/dist-server/service/twin-space/twin-area.js.map +0 -1
- package/dist-server/service/twin-space/twin-space-area.js.map +0 -1
- package/dist-server/service/twin-space/twin-space-representation.js.map +0 -1
- package/dist-server/service/twin-space/twin-space-resolver.js.map +0 -1
- package/dist-server/service/twin-space/twin-space.js.map +0 -1
- package/dist-server/service/twin-state/index.js.map +0 -1
- package/dist-server/service/twin-state/twin-state-subscription.js.map +0 -1
- package/dist-server/service/twin-structure/index.js.map +0 -1
- package/dist-server/service/twin-structure/twin-structure.js.map +0 -1
- package/dist-server/service/twin-subject/event-subjects.js.map +0 -1
- package/dist-server/service/twin-subject/index.js.map +0 -1
- package/dist-server/service/twin-subject/item-resolver.js.map +0 -1
- package/dist-server/service/twin-subject/subject-query-shape.js.map +0 -1
- package/dist-server/service/twin-subject/twin-subject-backfill.js.map +0 -1
- package/dist-server/service/twin-subject/twin-subject-event.js.map +0 -1
- package/dist-server/service/twin-subject/twin-subject-fast-path.js.map +0 -1
- package/dist-server/service/twin-subject/twin-subject-query.js.map +0 -1
- package/dist-server/service/twin-subject/twin-subject-writer.js.map +0 -1
- package/dist-server/service/twin-target/index.js.map +0 -1
- package/dist-server/service/twin-target/twin-target-resolver.js.map +0 -1
- package/dist-server/service/twin-target/twin-target.js.map +0 -1
- package/dist-shared/axis-read.js.map +0 -1
- package/dist-shared/entity-delta.js.map +0 -1
- package/dist-shared/kpi-broadcast.js.map +0 -1
- package/dist-shared/touched-items.js.map +0 -1
- package/dist-shared/twin-level.js.map +0 -1
- package/server/engine/attention-digest.ts +0 -102
- package/server/engine/canonical-ingest.ts +0 -511
- package/server/engine/checkpoint-fold.ts +0 -12
- package/server/engine/command-routing.ts +0 -67
- package/server/engine/declared-stimulus.ts +0 -66
- package/server/engine/energy-topology.ts +0 -189
- package/server/engine/event-time.ts +0 -96
- package/server/engine/index.ts +0 -51
- package/server/engine/ingest-dedupe.ts +0 -24
- package/server/engine/ingest-health.ts +0 -24
- package/server/engine/integration-coverage.ts +0 -147
- package/server/engine/integration-probes.ts +0 -144
- package/server/engine/integration-runner.ts +0 -95
- package/server/engine/integration-target-profile.ts +0 -103
- package/server/engine/kpi-baseline.ts +0 -202
- package/server/engine/kpi-fold.ts +0 -1516
- package/server/engine/kpi-query.ts +0 -1210
- package/server/engine/kpi-target.ts +0 -248
- package/server/engine/live-attentions.ts +0 -30
- package/server/engine/live-feed-registry.ts +0 -59
- package/server/engine/load-meter.ts +0 -393
- package/server/engine/local-declarations.ts +0 -779
- package/server/engine/log.ts +0 -72
- package/server/engine/loop-lag.ts +0 -120
- package/server/engine/measured-estimator.ts +0 -91
- package/server/engine/measured-yield.ts +0 -89
- package/server/engine/model-basis.ts +0 -162
- package/server/engine/model-gap.ts +0 -168
- package/server/engine/model-refusal.ts +0 -31
- package/server/engine/model-vocabulary.ts +0 -82
- package/server/engine/oee-accumulator.ts +0 -195
- package/server/engine/operation-basis.ts +0 -131
- package/server/engine/producer-guard.ts +0 -64
- package/server/engine/property-effects.ts +0 -216
- package/server/engine/read-time.ts +0 -77
- package/server/engine/restart-policy.ts +0 -55
- package/server/engine/runtime-key.ts +0 -58
- package/server/engine/spec-coverage.ts +0 -105
- package/server/engine/stage-path.ts +0 -172
- package/server/engine/state-axes.ts +0 -60
- package/server/engine/structure-diff.ts +0 -88
- package/server/engine/travel-estimator.ts +0 -138
- package/server/engine/twin-engine.ts +0 -4979
- package/server/engine/twin-state-channel.ts +0 -39
- package/server/engine/warm-start.ts +0 -265
- package/server/index.ts +0 -90
- package/server/migrations/1786000000000-RenameTwinInstanceBoardToModel.ts +0 -43
- package/server/migrations/1786100000000-PromoteEventActionAndSyncWarnings.ts +0 -54
- package/server/migrations/1786200000000-CarryLiveFeedCursor.ts +0 -53
- package/server/migrations/1786300000000-IndexEventTypeByTime.ts +0 -48
- package/server/migrations/1786400000000-IndexEventCreatedAt.ts +0 -38
- package/server/migrations/1786500000000-CreateTwinSubjectEvents.ts +0 -93
- package/server/migrations/1786600000000-RenameOperatoMesAdapterType.ts +0 -66
- package/server/migrations/1786700000000-AddDispatchRetryColumns.ts +0 -82
- package/server/migrations/1786800000000-CreateTwinReferenceReconciliations.ts +0 -39
- package/server/migrations/index.ts +0 -25
- package/server/routes.ts +0 -75
- package/server/service/actuation/actuation-advisor.ts +0 -131
- package/server/service/actuation/actuation-outcome.ts +0 -97
- package/server/service/actuation/actuation-rule-resolver.ts +0 -147
- package/server/service/actuation/actuation-rule.ts +0 -139
- package/server/service/actuation/approval-gateway.ts +0 -44
- package/server/service/actuation/catch-up-effects.ts +0 -152
- package/server/service/actuation/command-dispatcher.ts +0 -474
- package/server/service/actuation/command-store.ts +0 -236
- package/server/service/actuation/dispatch-after-approval.ts +0 -71
- package/server/service/actuation/effect-match.ts +0 -124
- package/server/service/actuation/index.ts +0 -27
- package/server/service/actuation/retry-plan.ts +0 -145
- package/server/service/actuation/rule-evaluate.ts +0 -352
- package/server/service/actuation/rule-loop.ts +0 -160
- package/server/service/actuation/rule-runner.ts +0 -216
- package/server/service/actuation/rule-wiring.ts +0 -84
- package/server/service/actuation/settle-effects.ts +0 -115
- package/server/service/actuation/sweep-dispatch.ts +0 -179
- package/server/service/actuation/twin-command-resolver.ts +0 -387
- package/server/service/actuation/twin-command.ts +0 -232
- package/server/service/actuation/twin-now.ts +0 -97
- package/server/service/index.ts +0 -100
- package/server/service/reference/actuation-routing.ts +0 -192
- package/server/service/reference/actuation-target.ts +0 -163
- package/server/service/reference/actuation-verification.ts +0 -85
- package/server/service/reference/attention-lane.ts +0 -21
- package/server/service/reference/connection-portability-resolver.ts +0 -171
- package/server/service/reference/connection-portability.ts +0 -329
- package/server/service/reference/control-routing.ts +0 -62
- package/server/service/reference/discovery-result.ts +0 -95
- package/server/service/reference/fill-cadence.ts +0 -29
- package/server/service/reference/fill-dedupe.ts +0 -66
- package/server/service/reference/fill-loop.ts +0 -153
- package/server/service/reference/fill-span.ts +0 -31
- package/server/service/reference/hook-contract.ts +0 -364
- package/server/service/reference/hook-rejected.ts +0 -53
- package/server/service/reference/hook-store.ts +0 -28
- package/server/service/reference/index.ts +0 -18
- package/server/service/reference/ingest-space.ts +0 -104
- package/server/service/reference/knob-defaults.ts +0 -59
- package/server/service/reference/live-cadence.ts +0 -129
- package/server/service/reference/live-feed-lease.ts +0 -56
- package/server/service/reference/live-ingest.ts +0 -94
- package/server/service/reference/reference-adapter.ts +0 -985
- package/server/service/reference/reference-assessment.ts +0 -250
- package/server/service/reference/reference-fill-run.ts +0 -179
- package/server/service/reference/reference-fill.ts +0 -223
- package/server/service/reference/reference-hook.ts +0 -479
- package/server/service/reference/reference-link-groups.ts +0 -21
- package/server/service/reference/reference-links.ts +0 -77
- package/server/service/reference/reference-live.ts +0 -420
- package/server/service/reference/reference-master.ts +0 -999
- package/server/service/reference/reference-probe.ts +0 -264
- package/server/service/reference/reference-progress-channel.ts +0 -26
- package/server/service/reference/reference-progress-subscription.ts +0 -78
- package/server/service/reference/reference-progress.ts +0 -95
- package/server/service/reference/reference-reconciliation-query.ts +0 -28
- package/server/service/reference/reference-reconciliation-writer.ts +0 -38
- package/server/service/reference/reference-reconciliation.ts +0 -55
- package/server/service/reference/reference-registry.ts +0 -17
- package/server/service/reference/reference-resolver.ts +0 -969
- package/server/service/reference/template-registry.ts +0 -85
- package/server/service/reference/twin-reference-reconciliation.ts +0 -27
- package/server/service/reference/twin-reference.ts +0 -190
- package/server/service/twin-attention/index.ts +0 -3
- package/server/service/twin-attention/twin-attention-query.ts +0 -70
- package/server/service/twin-audit/command-audit.ts +0 -114
- package/server/service/twin-audit/index.ts +0 -5
- package/server/service/twin-audit/twin-audit-event.ts +0 -158
- package/server/service/twin-audit/twin-audit-query.ts +0 -72
- package/server/service/twin-backfill/backfill-period-facts.ts +0 -168
- package/server/service/twin-backfill/backfill-shape.ts +0 -86
- package/server/service/twin-backfill/index.ts +0 -3
- package/server/service/twin-backfill/twin-backfill-resolver.ts +0 -35
- package/server/service/twin-control/index.ts +0 -3
- package/server/service/twin-control/twin-control-mutation.ts +0 -150
- package/server/service/twin-event/index.ts +0 -3
- package/server/service/twin-event/journal-count.ts +0 -53
- package/server/service/twin-event/twin-event-keys.ts +0 -215
- package/server/service/twin-event/twin-event-type.ts +0 -68
- package/server/service/twin-event/twin-event.ts +0 -250
- package/server/service/twin-forecast/forecast-metrics.ts +0 -106
- package/server/service/twin-forecast/forecast-tuning.ts +0 -40
- package/server/service/twin-forecast/gap-analytics.ts +0 -139
- package/server/service/twin-forecast/index.ts +0 -3
- package/server/service/twin-forecast/twin-forecast-query.ts +0 -486
- package/server/service/twin-ingest-window/index.ts +0 -7
- package/server/service/twin-ingest-window/twin-ingest-window-query.ts +0 -125
- package/server/service/twin-ingest-window/twin-ingest-window-writer.ts +0 -57
- package/server/service/twin-ingest-window/twin-ingest-window.ts +0 -113
- package/server/service/twin-instance/index.ts +0 -3
- package/server/service/twin-instance/twin-instance.ts +0 -199
- package/server/service/twin-journal/event-type-split-shape.ts +0 -112
- package/server/service/twin-journal/event-type-split.ts +0 -144
- package/server/service/twin-journal/index.ts +0 -3
- package/server/service/twin-journal/journal-order.ts +0 -20
- package/server/service/twin-journal/twin-journal-query.ts +0 -615
- package/server/service/twin-lifecycle/domain-catalog.ts +0 -51
- package/server/service/twin-lifecycle/index.ts +0 -3
- package/server/service/twin-lifecycle/twin-lifecycle-mutation.ts +0 -285
- package/server/service/twin-metrics/index.ts +0 -3
- package/server/service/twin-metrics/twin-metrics-query.ts +0 -172
- package/server/service/twin-model/axis-journal-evidence.ts +0 -57
- package/server/service/twin-model/choose-recipe.ts +0 -31
- package/server/service/twin-model/epcis-coverage.ts +0 -251
- package/server/service/twin-model/external-resolver.ts +0 -173
- package/server/service/twin-model/iec61850-coverage.ts +0 -111
- package/server/service/twin-model/index.ts +0 -25
- package/server/service/twin-model/isa95-coverage.ts +0 -320
- package/server/service/twin-model/item-ref.ts +0 -80
- package/server/service/twin-model/name-index.ts +0 -94
- package/server/service/twin-model/project-structure.ts +0 -213
- package/server/service/twin-model/standard-coverage.ts +0 -35
- package/server/service/twin-model/status-tally.ts +0 -37
- package/server/service/twin-model/twin-equipment.ts +0 -191
- package/server/service/twin-model/twin-lineage-query.ts +0 -327
- package/server/service/twin-model/twin-location.ts +0 -147
- package/server/service/twin-model/twin-model-item-query.ts +0 -1029
- package/server/service/twin-model/twin-model-mutation.ts +0 -503
- package/server/service/twin-model/twin-model-query.ts +0 -792
- package/server/service/twin-model/twin-model-tree-query.ts +0 -211
- package/server/service/twin-model/twin-operation.ts +0 -157
- package/server/service/twin-readiness/index.ts +0 -3
- package/server/service/twin-readiness/twin-readiness-query.ts +0 -96
- package/server/service/twin-space/area-resolver.ts +0 -75
- package/server/service/twin-space/index.ts +0 -8
- package/server/service/twin-space/move-space.ts +0 -262
- package/server/service/twin-space/representation-role.ts +0 -15
- package/server/service/twin-space/space-integrity.ts +0 -293
- package/server/service/twin-space/twin-area.ts +0 -63
- package/server/service/twin-space/twin-space-area.ts +0 -66
- package/server/service/twin-space/twin-space-representation.ts +0 -99
- package/server/service/twin-space/twin-space-resolver.ts +0 -582
- package/server/service/twin-space/twin-space.ts +0 -148
- package/server/service/twin-state/index.ts +0 -3
- package/server/service/twin-state/twin-state-subscription.ts +0 -62
- package/server/service/twin-structure/index.ts +0 -3
- package/server/service/twin-structure/twin-structure.ts +0 -96
- package/server/service/twin-subject/event-subjects.ts +0 -162
- package/server/service/twin-subject/index.ts +0 -10
- package/server/service/twin-subject/item-resolver.ts +0 -92
- package/server/service/twin-subject/subject-query-shape.ts +0 -84
- package/server/service/twin-subject/twin-subject-backfill.ts +0 -196
- package/server/service/twin-subject/twin-subject-event.ts +0 -101
- package/server/service/twin-subject/twin-subject-fast-path.ts +0 -346
- package/server/service/twin-subject/twin-subject-query.ts +0 -210
- package/server/service/twin-subject/twin-subject-writer.ts +0 -189
- package/server/service/twin-target/index.ts +0 -5
- package/server/service/twin-target/twin-target-resolver.ts +0 -142
- package/server/service/twin-target/twin-target.ts +0 -97
- package/server/types/global.d.ts +0 -22
- package/shared/axis-read.ts +0 -28
- package/shared/entity-delta.ts +0 -335
- package/shared/kpi-broadcast.ts +0 -13
- package/shared/touched-items.ts +0 -73
- package/shared/twin-level.ts +0 -48
- package/test/ack-shape-alignment.test.ts +0 -97
- package/test/actuation-advisor.test.ts +0 -55
- package/test/actuation-approval-door.test.ts +0 -411
- package/test/actuation-dispatch.test.ts +0 -209
- package/test/actuation-effect.test.ts +0 -162
- package/test/actuation-outcome.test.ts +0 -152
- package/test/actuation-rule-runner.test.ts +0 -281
- package/test/actuation-rule.test.ts +0 -266
- package/test/actuation-seam.test.ts +0 -255
- package/test/actuation-settle.test.ts +0 -164
- package/test/actuation-target.test.ts +0 -145
- package/test/actuation-verification-state.test.ts +0 -139
- package/test/adopt-structure-live.test.ts +0 -133
- package/test/aggregate-not-findone.test.ts +0 -112
- package/test/area-resolver-db.test.ts +0 -110
- package/test/attention-digest.test.ts +0 -161
- package/test/axis-declaration-passthrough-db.test.ts +0 -152
- package/test/axis-journal-evidence.test.ts +0 -71
- package/test/axis-read.test.ts +0 -188
- package/test/backfill-shape.test.ts +0 -89
- package/test/boot-resume.test.ts +0 -287
- package/test/broadcast-cost-baseline.test.ts +0 -201
- package/test/broadcast-period.test.ts +0 -58
- package/test/broadcast-queue-overflow.test.ts +0 -244
- package/test/canonical-ingest-vocabularies.test.ts +0 -451
- package/test/canonical-quantity-door.test.ts +0 -61
- package/test/capability-mapping.test.ts +0 -89
- package/test/checkpoint-refuses-empty.test.ts +0 -103
- package/test/choose-recipe.test.ts +0 -117
- package/test/column-type-portability.test.ts +0 -122
- package/test/command-routing.test.ts +0 -61
- package/test/command-store-writes-columns.test.ts +0 -126
- package/test/connection-portability-doors.test.ts +0 -87
- package/test/connector-capability-declaration.test.ts +0 -195
- package/test/contract-layer-guard.test.ts +0 -48
- package/test/control-capability.test.ts +0 -98
- package/test/cursor-stall-not-read-failure.test.ts +0 -126
- package/test/declaration-reaches-model.test.ts +0 -226
- package/test/declared-location-types.test.ts +0 -89
- package/test/declared-stimulus.test.ts +0 -88
- package/test/dedupe-transformation.test.ts +0 -112
- package/test/discovery-result.test.ts +0 -75
- package/test/dispatch-after-approval-source.test.ts +0 -81
- package/test/duration-estimators.test.ts +0 -144
- package/test/energy-topology.test.ts +0 -113
- package/test/entity-delta.test.ts +0 -352
- package/test/equipment-identity-reaches.test.ts +0 -57
- package/test/event-subjects.test.ts +0 -148
- package/test/event-time-column.test.ts +0 -67
- package/test/event-type-split.test.ts +0 -178
- package/test/external-resolver.test.ts +0 -177
- package/test/fact-scope-wiring.test.ts +0 -96
- package/test/fill-dedupe.test.ts +0 -59
- package/test/fill-loop.test.ts +0 -35
- package/test/first-envelope.test.ts +0 -153
- package/test/fold-gap-speaks.test.ts +0 -53
- package/test/fold-shift-dst.test.ts +0 -110
- package/test/forecast-metrics.test.ts +0 -157
- package/test/forecast-tuning.test.ts +0 -42
- package/test/gap-analytics.test.ts +0 -113
- package/test/generated-not-counted.test.ts +0 -99
- package/test/guard-roots.ts +0 -76
- package/test/home-in-area.test.ts +0 -90
- package/test/hook-address.test.ts +0 -28
- package/test/hook-rejected-shape.test.ts +0 -86
- package/test/hook-response-sum.test.ts +0 -193
- package/test/hook-sequence.test.ts +0 -333
- package/test/ingest-bench.test.ts +0 -70
- package/test/ingest-dedupe.test.ts +0 -56
- package/test/ingest-expected-quiet.test.ts +0 -111
- package/test/ingest-health-engine.test.ts +0 -248
- package/test/ingest-health-wiring.test.ts +0 -120
- package/test/ingest-health.test.ts +0 -306
- package/test/ingest-history.test.ts +0 -247
- package/test/ingest-idempotent.test.ts +0 -211
- package/test/ingest-reconcile-four-ways.test.ts +0 -97
- package/test/ingest-rules-header.test.ts +0 -100
- package/test/ingest-running-guard.test.ts +0 -136
- package/test/ingest-space.test.ts +0 -78
- package/test/ingest-window-rolls-unobserved.test.ts +0 -72
- package/test/ingest-wiring-guard.test.ts +0 -197
- package/test/instance-cache-lifecycle.test.ts +0 -110
- package/test/intake-mapping-parity.test.ts +0 -175
- package/test/integration-probes.test.ts +0 -103
- package/test/integration-runner.test.ts +0 -95
- package/test/item-ref.test.ts +0 -78
- package/test/journal-order-axis.test.ts +0 -80
- package/test/journal-read-discipline.test.ts +0 -186
- package/test/journal-retention.test.ts +0 -275
- package/test/journal-sort-axis.test.ts +0 -142
- package/test/journal-write-door.test.ts +0 -110
- package/test/journal-write-trend.test.ts +0 -115
- package/test/kernel-kind-guard.test.ts +0 -98
- package/test/knob-defaults.test.ts +0 -72
- package/test/kpi-baseline-db.test.ts +0 -216
- package/test/kpi-baseline.test.ts +0 -196
- package/test/kpi-fold.test.ts +0 -1456
- package/test/kpi-query-bench.test.ts +0 -130
- package/test/lens-own-places.test.ts +0 -50
- package/test/lineage-survives-restart.test.ts +0 -234
- package/test/live-cadence.test.ts +0 -170
- package/test/live-cursor-wiring.test.ts +0 -87
- package/test/live-feed-lease.test.ts +0 -63
- package/test/live-feed-registry.test.ts +0 -75
- package/test/live-kernel-facts.test.ts +0 -161
- package/test/live-mirror-parity.test.ts +0 -286
- package/test/load-meter.test.ts +0 -328
- package/test/local-declarations.test.ts +0 -662
- package/test/log-stamp.test.ts +0 -59
- package/test/loop-lag.test.ts +0 -82
- package/test/master-to-twin.test.ts +0 -279
- package/test/measured-yield.test.ts +0 -90
- package/test/merge-streams.test.ts +0 -70
- package/test/mirror-resumes-from-checkpoint.test.ts +0 -192
- package/test/model-basis.test.ts +0 -141
- package/test/model-gap.test.ts +0 -153
- package/test/model-refusal.test.ts +0 -75
- package/test/model-vocabulary.test.ts +0 -114
- package/test/move-space.test.ts +0 -149
- package/test/mutation-gate.test.ts +0 -122
- package/test/oee-accumulator.test.ts +0 -204
- package/test/oee-site-calendar.test.ts +0 -146
- package/test/open-doors.test.ts +0 -197
- package/test/operation-basis.test.ts +0 -127
- package/test/operational-vocabulary.test.ts +0 -108
- package/test/operations-capability-db.test.ts +0 -165
- package/test/order-and-transaction-split.test.ts +0 -107
- package/test/order-fold-host.test.ts +0 -112
- package/test/producer-guard.test.ts +0 -66
- package/test/project-structure-db.test.ts +0 -226
- package/test/projection-reaches-screen.test.ts +0 -277
- package/test/projection-reads-declared.test.ts +0 -109
- package/test/property-effects.test.ts +0 -128
- package/test/provenance-promotion.test.ts +0 -99
- package/test/read-failure-ledger.test.ts +0 -106
- package/test/read-failure-visible.test.ts +0 -145
- package/test/read-time.test.ts +0 -118
- package/test/reference-fill.test.ts +0 -235
- package/test/reference-grounding.test.ts +0 -70
- package/test/reference-hook.test.ts +0 -177
- package/test/reference-links.test.ts +0 -56
- package/test/reference-reconciliation.test.ts +0 -39
- package/test/registry-key-guard.test.ts +0 -80
- package/test/rejection-carries-event-id.test.ts +0 -101
- package/test/rename-twin.test.ts +0 -89
- package/test/resolve-ts-siblings.mjs +0 -52
- package/test/restart-policy.test.ts +0 -111
- package/test/resync-origin-site.test.ts +0 -83
- package/test/retry-plan.test.ts +0 -139
- package/test/revision-axis.test.ts +0 -110
- package/test/runtime-key.test.ts +0 -66
- package/test/save-intake-collision.test.ts +0 -91
- package/test/scale-twin-bench.test.ts +0 -103
- package/test/secrets-at-rest.test.ts +0 -135
- package/test/snapshot-freshness.test.ts +0 -60
- package/test/source-outcome-audit.test.ts +0 -104
- package/test/space-integrity.test.ts +0 -223
- package/test/space-representation.test.ts +0 -66
- package/test/space-scope-includes-stopped.test.ts +0 -55
- package/test/spec-coverage.test.ts +0 -113
- package/test/stage-path.test.ts +0 -95
- package/test/standard-coverage.test.ts +0 -148
- package/test/state-axes.test.ts +0 -74
- package/test/status-tally.test.ts +0 -55
- package/test/streamline-e2e.test.ts +0 -76
- package/test/structure-revision-db.test.ts +0 -315
- package/test/subject-fast-path.test.ts +0 -148
- package/test/subject-read-model.test.ts +0 -175
- package/test/sweep-dispatch.test.ts +0 -191
- package/test/tenant-registry-db.test.ts +0 -149
- package/test/time-range.test.ts +0 -152
- package/test/touched-items.test.ts +0 -61
- package/test/twin-audit.test.ts +0 -83
- package/test/twin-event-keys.test.ts +0 -193
- package/test/twin-model-item-db.test.ts +0 -319
- package/test/twin-model-parent-relation-db.test.ts +0 -125
- package/test/twin-model-tree-db.test.ts +0 -209
- package/test/twin-origin-resync.test.ts +0 -133
- package/test/twin-state-channel.test.ts +0 -111
- package/test/vocabulary-guard.test.ts +0 -43
- package/test/warm-start-seam.test.ts +0 -162
- package/test/warm-start.test.ts +0 -297
- package/test/withheld-door.test.ts +0 -95
- package/test/yield-loop.test.ts +0 -199
- package/tsconfig.json +0 -15
- package/tsconfig.shared.json +0 -23
- package/tsconfig.shared.tsbuildinfo +0 -1
- package/tsconfig.tsbuildinfo +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"twin-model-query.js","sourceRoot":"","sources":["../../../server/service/twin-model/twin-model-query.ts"],"names":[],"mappings":";;;;AAAA,yEAA8D;AAC9D,4DAAwD;AACxD,uDAA+C;AAC/C,+DAAuD;AACvD,+CAAuE;AAEvE,iDAAkF;AAElF,oDAAkD;AAClD,4DAAsD;AACtD,wDAA0D;AAC1D,wEAAgE;AAChE,+DAAuD;AACvD,sEAA8D;AAC9D,8EAA4E;AAC5E,wEAAgE;AAChE,yDAAiD;AACjD,2DAAmD;AACnD,2DAAmD;AACnD,iEAA0E;AAC1E,2DAAmD;AACnD,iEAAyD;AACzD,2DAAmD;AAEnD;;;;;GAKG;AACH,SAAS,wBAAwB,CAAC,IAAY,EAAE,aAAqB,EAAE,UAAkB;IACvF,MAAM,IAAI,GAAG,CAAC,KAAa,EAAE,EAAE;QAC7B,MAAM,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,WAAW,IAAI,MAAM,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,KAAK,IAAI,CAAC,CAAA;QAC5F,OAAO,CAAC,CAAC,EAAE,UAAU,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,KAAK,oBAAoB,CAAC,CAAA;IAC/E,CAAC,CAAA;IACD,MAAM,CAAC,GAAG,IAAI,CAAC,aAAa,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,CAAA;IACjD,IAAI,CAAC,CAAC;QAAE,OAAO,EAAE,CAAA;IACjB,OAAO,CAAC,EAAE,EAAE,EAAE,oBAAoB,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAA;AAChI,CAAC;AAED,+DAA+D;AAC/D,MAAM,QAAQ,GAAgD,EAAE,KAAK,EAAE,iCAAa,EAAE,KAAK,EAAE,iCAAa,EAAE,QAAQ,EAAE,uCAAgB,EAAE,CAAA;AACxI,8DAAwD;AACxD,yEAAyE;AACzE,yFAAoF;AAEpF,qDAAqD;AACrD,MAAM,EAAE,SAAS,EAAE,cAAc,EAAE,QAAQ,EAAE,UAAU,EAAE,aAAa,EAAE,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAAA;AAE3G;;;;GAIG;AACH,MAAM,UAAU,GAAwB;IACtC,SAAS,EAAE,+BAAY;IACvB,SAAS,EAAE,iCAAa;IACxB,UAAU,EAAE,iCAAa;CAC1B,CAAA;AAED,4DAA4D;AAC5D,MAAM,EAAE,GAAG,CAAC,CAAM,EAAE,IAAY,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAM,EAAE,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;AAErH,SAAS,eAAe,CAAC,KAAU,EAAE,IAAY;IAC/C,MAAM,CAAC,GAAG,EAAE,CAAC,KAAK,EAAE,IAAI,CAAC,CAAA;IACzB,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;QAAE,OAAO,CAAC,CAAC,MAAM,CAAA;IACrC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;AAClB,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,uEAAuE;AACvE,SAAS,QAAQ,CAAC,GAAQ,EAAE,KAAa;IACvC,IAAI,GAAG,GAAU,CAAC,GAAG,CAAC,CAAA;IACtB,KAAK,MAAM,GAAG,IAAI,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QACnC,MAAM,GAAG,GAAG,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAA;QACvD,MAAM,IAAI,GAAU,EAAE,CAAA;QACtB,KAAK,MAAM,CAAC,IAAI,GAAG,EAAE,CAAC;YACpB,IAAI,CAAC,IAAI,IAAI;gBAAE,SAAQ;YACvB,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAA;YAChB,IAAI,CAAC,IAAI,IAAI;gBAAE,SAAQ;YACvB,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;gBAAE,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAA;;gBAChC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QACnB,CAAC;QACD,GAAG,GAAG,IAAI,CAAA;IACZ,CAAC;IACD,OAAO,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,IAAI,CAAC,CAAA;AACnC,CAAC;AAED,MAAM,IAAI,GAAG,CAAC,CAAM,EAAiB,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,EAAE,IAAI,IAAI,IAAI,CAAC,CAAA;AAExG,6DAA6D;AAC7D,KAAK,UAAU,gBAAgB,CAAC,QAAgB,EAAE,UAAkB,EAAE,IAAY;IAChF,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,IAAA,4CAAiB,EAAC,IAAA,qBAAa,EAAC,yBAAS,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,UAAU,EAAE,EAAE,IAAI,CAAC,CAAA;QAC9G,8DAA8D;QAC9D,OAAO,IAAI,CAAC,CAAC,CAAC,uBAAuB,CAAC,CAAC,CAAC,UAAU,CAAA;IACpD,CAAC;IAAC,MAAM,CAAC;QACP,mCAAmC;QACnC,OAAO,UAAU,CAAA;IACnB,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,YAAY,GAAG,IAAI,GAAG,EAAiD,CAAA;AAC7E,MAAM,gBAAgB,GAAG,CAAC,CAAA;AAInB,IAAM,cAAc,GAApB,MAAM,cAAc;IACzB;;;;;;;;;;;;;;OAcG;IACK,QAAQ,CAAC,KAAU,EAAE,CAAM;QACjC,MAAM,QAAQ,GAAG,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;QACjC,MAAM,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;QACtC,IAAI,CAAC,QAAQ,IAAI,CAAC,MAAM;YAAE,OAAO,EAAE,CAAA;QAEnC;;;;WAIG;QACH,IAAI,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,UAAU,IAAI,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,UAAU;YAAE,OAAO,EAAE,CAAA;QAE5F,MAAM,MAAM,GAAG,CAAC,IAAS,EAAE,EAAE;YAC3B,MAAM,GAAG,GAAG,EAAE,CAAC,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,CAAA;YAChC,OAAO,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;QACpD,CAAC,CAAA;QACD,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAa,CAAC,CAAA;QAC7E,IAAI,MAAM,GAAG,CAAC,CAAA;QACd,IAAI,QAAQ,GAAG,CAAC,CAAA;QAChB,IAAI,OAAO,GAAG,CAAC,CAAA;QACf,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;YACpC,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;YACvH,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;gBAAC,OAAO,EAAE,CAAC;gBAAC,SAAQ;YAAC,CAAC;YACzC;yCAC6B;YAC7B,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;gBAAE,MAAM,EAAE,CAAA;;gBACxC,QAAQ,EAAE,CAAA;QACjB,CAAC;QACD,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,CAAA;IAC7D,CAAC;IAOK,AAAN,KAAK,CAAC,gBAAgB,CAAoB,UAAkB,EAAS,OAAwB;QAC3F,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAA;QACxC,MAAM,IAAI,GAAG,MAAM,IAAA,qBAAa,EAAC,+BAAY,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,UAAU,EAAE,EAAE,CAAC,CAAA;QAC3G,IAAI,CAAC,IAAI;YAAE,OAAO,IAAI,CAAA;QAEtB;;;;;;;;;;;;;;;;;WAiBG;QACH,MAAM,MAAM,GAAI,IAAI,CAAC,MAAc,EAAE,MAAM,IAAI,UAAU,CAAA;QACzD,MAAM,GAAG,GAAG,MAAM,IAAA,qBAAa,EAAC,iCAAa,CAAC;aAC3C,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC;aAChE,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAA;QAEpB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,EAAE,CAAA;QAC9B;;;;;;;;;WASG;QACH,IAAI,YAAY,GAAuE,IAAI,CAAA;QAC3F,MAAM,SAAS,GAAG,GAAG,EAAE,CACrB,CAAC,YAAY,KAAK,CAAC,KAAK,IAAI,EAAE;YAC5B,MAAM,SAAS,GAAG,qBAAU,CAAC,SAAS,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAA;YAC5D,IAAI,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,IAAA,2BAAW,EAAC,qBAAU,CAAC,QAAQ,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;YACpF,IAAI,MAAM,GAAG,KAAK,CAAA;YAClB,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,IAAI,CAAC;oBACH,IAAI,GAAG,IAAA,2BAAW,EAAC,MAAM,qBAAU,CAAC,OAAO,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAA;oBAClE,MAAM,GAAG,CAAC,CAAC,IAAI,CAAA;gBACjB,CAAC;gBAAC,MAAM,CAAC;oBACP,iDAAiD;gBACnD,CAAC;YACH,CAAC;YACD,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,CAAA;QACpC,CAAC,CAAC,EAAE,CAAC,CAAA;QAEP;;;;;;;;;;;;;;;;;;WAkBG;QACH,IAAI,cAAc,GAAiE,IAAI,CAAA;QACvF,MAAM,WAAW,GAAG,GAAG,EAAE,CACvB,CAAC,cAAc,KAAK,CAAC,KAAK,IAAI,EAAE;YAC9B,IAAI,CAAC;gBACH;;;mBAGG;gBACH,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;oBAC5C,IAAA,qBAAa,EAAC,yBAAS,CAAC;yBACrB,kBAAkB,CAAC,GAAG,CAAC;yBACvB,MAAM,CAAC,iBAAiB,EAAE,KAAK,CAAC;yBAChC,KAAK,CAAC,sBAAsB,EAAE,EAAE,QAAQ,EAAE,CAAC;yBAC3C,QAAQ,CAAC,4BAA4B,EAAE,EAAE,UAAU,EAAE,CAAC;yBACtD,SAAS,EAAoB;oBAChC;;;;uBAIG;oBACH,IAAA,qBAAa,EAAC,yBAAS,CAAC;yBACrB,kBAAkB,CAAC,GAAG,CAAC;yBACvB,MAAM,CAAC,kBAAkB,EAAE,IAAI,CAAC;yBAChC,KAAK,CAAC,sBAAsB,EAAE,EAAE,QAAQ,EAAE,CAAC;yBAC3C,QAAQ,CAAC,4BAA4B,EAAE,EAAE,UAAU,EAAE,CAAC;yBACtD,SAAS,EAAmB;iBAChC,CAAC,CAAA;gBACF,MAAM,GAAG,GAAG,EAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,IAAA,2BAAY,EAAC,IAAA,qBAAa,EAAC,yBAAS,CAAC,EAAE,WAAW,EAAE,SAAS,EAAE,EAAE,CAAC,EAAE,CAAA;gBACjI,IAAI,CAAC,GAAG,CAAC,QAAQ;oBAAE,OAAO,IAAI,CAAA;gBAC9B;;;;;;;mBAOG;gBACH,MAAM,GAAG,GAAG,GAAG,QAAQ,IAAI,UAAU,IAAI,GAAG,CAAC,QAAQ,EAAE,CAAA;gBACvD,MAAM,GAAG,GAAG,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;gBACjC,IAAI,GAAG;oBAAE,OAAO,GAAG,CAAA;gBACnB,MAAM,IAAI,GAAG,IAAA,2BAAW,EAAC,MAAM,qBAAU,CAAC,OAAO,CAAC,QAAQ,EAAE,UAAU,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAA;gBACtF,IAAI,CAAC,IAAI;oBAAE,OAAO,IAAI,CAAA;gBACtB,oDAAoD;gBACpD,MAAM,GAAG,GAAG,EAAE,IAAI,EAAE,OAAO,EAAG,IAAY,CAAC,OAAO,IAAI,GAAG,CAAC,SAAS,EAAE,WAAW,EAAE,IAAI,IAAI,EAAE,CAAA;gBAC5F,YAAY,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAA;gBAC1B,gDAAgD;gBAChD,OAAO,YAAY,CAAC,IAAI,GAAG,gBAAgB;oBAAE,YAAY,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAe,CAAC,CAAA;gBAC5G,OAAO,GAAG,CAAA;YACZ,CAAC;YAAC,MAAM,CAAC;gBACP,kDAAkD;gBAClD,OAAO,IAAI,CAAA;YACb,CAAC;QACH,CAAC,CAAC,EAAE,CAAC,CAAA;QAEP;;;;;;;WAOG;QACH,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,GAAG,CAChC,SAAS,CAAC,GAAG,CAAC,KAAK,EAAE,CAAM,EAAE,EAAE;YAC7B;;;;;;;;eAQG;YACH,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;gBACtC,OAAO;oBACL,IAAI,EAAE,CAAC,CAAC,IAAI;oBACZ,KAAK,EAAE,CAAC,CAAC,KAAK;oBACd,IAAI,EAAE,CAAC,CAAC,IAAI;oBACZ,SAAS,EAAE,KAAK;oBAChB,aAAa,EAAE,CAAC,CAAC,aAAa;oBAC9B,QAAQ,EAAE,CAAC,CAAC,QAAQ,IAAI,IAAI;oBAC5B,WAAW,EAAE,CAAC,CAAC,WAAW,IAAI,IAAI;oBAClC,WAAW,EAAE,CAAC,CAAC,WAAW,IAAI,IAAI;oBAClC,KAAK,EAAE,IAAI;oBACX,aAAa,EAAE,IAAI;oBACnB,YAAY,EAAE,gBAAgB;oBAC9B;;;;;;;;;uBASG;oBACH,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC;oBAC1B,KAAK,EAAE,aAAa;iBACrB,CAAA;YACH,CAAC;YACD,MAAM,MAAM,GAAG,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;YACjC,2DAA2D;YAC3D,MAAM,UAAU,GAAG,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,UAAU,CAAC,CAAC,CAAC,eAAe,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;YACzF,MAAM,MAAM,GAAG,MAAM;gBACnB,CAAC,CAAC,MAAM,IAAA,qBAAa,EAAC,MAAM,CAAC,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAS,EAAE,QAAQ,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAS,EAAE,EAAE,CAAC;gBACrH,CAAC,CAAC,SAAS,CAAA;YACb;;;;;;;;;eASG;YACH,MAAM,KAAK,GAAG,MAAM,KAAK,SAAS,IAAI,MAAM,KAAK,UAAU,CAAA;YAC3D;;;;;;eAMG;YACH,MAAM,GAAG,GAAG,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;YAC7E;;;;eAIG;YACH;;;;;;;;eAQG;YACH,IAAI,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,OAAO,EAAE,CAAC;gBACnC;+EAC+D;gBAC/D;;;;;mBAKG;gBACH,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,SAAS,EAAE,CAAA;gBACrD;8EAC8D;gBAC9D,IAAI,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,IAAA,0BAAW,EAAC,IAAI,EAAE,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAA;gBACvD,IAAI,OAAO,GAAkB,IAAI,CAAA;gBACjC,IAAI,WAAW,GAAG,KAAK,CAAA;gBACvB;;;mBAGG;gBACH,IAAI,CAAC,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;oBAC5D,MAAM,IAAI,GAAG,MAAM,IAAA,4CAAiB,EAAC,IAAA,qBAAa,EAAC,yBAAS,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,UAAU,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAA;oBAClI,IAAI,IAAI,EAAE,CAAC;wBACT,MAAM,CAAC,GAAG,MAAM,WAAW,EAAE,CAAA;wBAC7B,MAAM,EAAE,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,IAAA,0BAAW,EAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAA;wBAC1D,IAAI,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,MAAM,EAAE,CAAC;4BACnC,MAAM,GAAG,EAAE,CAAA;4BACX,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,IAAI,CAAA;4BAC5B,WAAW,GAAG,IAAI,CAAA;wBACpB,CAAC;oBACH,CAAC;gBACH,CAAC;gBACD,OAAO;oBACL,IAAI,EAAE,CAAC,CAAC,IAAI;oBACZ,KAAK,EAAE,CAAC,CAAC,KAAK;oBACd,IAAI,EAAE,CAAC,CAAC,IAAI;oBACZ,SAAS,EAAE,KAAK;oBAChB,aAAa,EAAE,CAAC,CAAC,aAAa;oBAC9B,QAAQ,EAAE,CAAC,CAAC,QAAQ,IAAI,IAAI;oBAC5B,WAAW,EAAE,CAAC,CAAC,WAAW,IAAI,IAAI;oBAClC,WAAW,EAAE,CAAC,CAAC,WAAW,IAAI,IAAI;oBAClC,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI;oBACnD;;;;;;;;;uBASG;oBACH,GAAG,IAAA,6BAAW,EAAC,MAAM,CAAC;oBACtB;;;;uBAIG;oBACH,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;wBACvB,CAAC,CAAC,MAAM,CAAC,MAAM;4BACb,CAAC,CAAC,EAAE;4BACJ,CAAC,CAAC,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC,QAAQ,EAAE,UAAU,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE;wBAC1E,CAAC,CAAC,EAAE,YAAY,EAAE,cAAc,EAAE,CAAC;oBACrC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC;oBAC1B,KAAK,EAAE,MAAM,IAAI,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO;oBAClD;;;uBAGG;oBACH,GAAG,CAAC,WAAW,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;oBAC9D,SAAS;oBACT,qDAAqD;oBACrD,YAAY,EAAE,IAAI;oBAClB,kBAAkB,EAAE,CAAC,CAAC,CAAC,aAAa,EAAE,KAAK,IAAI,CAAC,CAAC,CAAC,aAAa,EAAE,KAAK,IAAI,CAAC,CAAC,CAAC,aAAa,EAAE,QAAQ;iBACrG,CAAA;YACH,CAAC;YACD,OAAO;gBACL,IAAI,EAAE,CAAC,CAAC,IAAI;gBACZ,KAAK,EAAE,CAAC,CAAC,KAAK;gBACd,IAAI,EAAE,CAAC,CAAC,IAAI;gBACZ,SAAS,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,IAAI;gBAC7C,aAAa,EAAE,CAAC,CAAC,aAAa;gBAC9B,QAAQ,EAAE,CAAC,CAAC,QAAQ,IAAI,IAAI;gBAC5B,WAAW,EAAE,CAAC,CAAC,WAAW,IAAI,IAAI;gBAClC,WAAW,EAAE,CAAC,CAAC,WAAW,IAAI,IAAI;gBAClC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU;gBACnC;;;;;;;;mBAQG;gBACH,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC;oBAChC,CAAC,CAAC,EAAE;oBACJ,CAAC,CAAC;wBACE,YAAY,EACV,MAAM,IAAI,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,gBAAgB;qBAC/F,CAAC;gBACN,8DAA8D;gBAC9D,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC;gBAC1B,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU;gBACnC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACvD,iDAAiD;gBACjD,kBAAkB,EAAE,CAAC,CAAC,CAAC,aAAa,EAAE,KAAK,IAAI,CAAC,CAAC,CAAC,aAAa,EAAE,KAAK,IAAI,CAAC,CAAC,CAAC,aAAa,EAAE,QAAQ;aACrG,CAAA;QACH,CAAC,CAAC,CACH,CAAA;QAED;;;;;;;;;;;WAWG;QACH;;;;;;WAMG;QACH,MAAM,IAAI,GAAG,qBAAU,CAAC,QAAQ,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAA;QACtD,MAAM,GAAG,GAAG,IAAA,yBAAU,EAAC,IAAI,CAAC,CAAA;QAC5B,MAAM,YAAY,GAAG,IAAI;YACvB,CAAC,CAAC;gBACE,SAAS,EAAE,CAAC,IAAI,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACpG,SAAS,EAAE,CAAC,IAAI,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACpG,OAAO,EAAE,CAAC,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAChG,sDAAsD;gBACtD,SAAS,EAAE,GAAG,EAAE,SAAS,IAAI,EAAE;gBAC/B,uBAAuB,EAAE,GAAG,EAAE,uBAAuB,IAAI,IAAI;gBAC7D,UAAU,EAAE,GAAG,EAAE,UAAU,IAAI,EAAE;aAClC;YACH,CAAC,CAAC,IAAI,CAAA;QAER,4DAA4D;QAC5D,kEAAkE;QAClE,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,CAAE,CAAS,CAAC,aAAa,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAA;QAC1H,8DAA8D;QAC9D,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,GAAG,CAC7B,cAAc,CAAC,MAAM,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,KAAK,MAAM,IAAI,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CACpH,KAAK,EAAE,CAAM,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,GAAG,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC,CACxH,CACF,CAAA;QAED,OAAO;YACL,UAAU;YACV,kDAAkD;YAClD,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,IAAI;YACvB;;;;;;eAMG;YACH;;;;;;eAMG;YACH,2DAA2D;YAC3D,SAAS,EAAE,IAAA,uCAAgB,EAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAE,SAAmB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;YACrG,UAAU,EAAE,CAAC,GAAG,EAAE;gBAChB,MAAM,IAAI,GAAS,IAAI,CAAC,KAAa,EAAE,cAAc,CAAA;gBACrD,IAAI,CAAC,IAAI;oBAAE,OAAO,IAAI,CAAA;gBACtB,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,IAAI,IAAI,CAAA;gBAClC,MAAM,QAAQ,GAAG,CAAC,IAAI,CAAC,UAAU,EAAE,SAAS,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,EAAE,CAAC,KAAK,GAAG,CAAC,CAAA;gBAC7F,OAAO;oBACL,aAAa,EAAE,IAAI,CAAC,aAAa,IAAI,IAAI;oBACzC,SAAS,EAAE,GAAG;oBACd,+CAA+C;oBAC/C,WAAW,EAAE,QAAQ,EAAE,KAAK,IAAI,QAAQ,EAAE,IAAI,IAAI,IAAI;iBACvD,CAAA;YACH,CAAC,CAAC,EAAE;YACJ;;;;;;;;;;;;;;;eAeG;YACH,iBAAiB,EAAE,CAAC,MAAM,SAAS,EAAE,CAAC,CAAC,IAAI,EAAE,iBAAiB,IAAI,IAAI;YACtE,WAAW,EAAE,IAAI,CAAC,WAAW,IAAI,IAAI;YACrC,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,aAAa,EAAE,IAAI,CAAC,aAAa;YACjC,MAAM,EAAE,GAAG;gBACT,CAAC,CAAC;oBACE,WAAW,EAAE,GAAG,CAAC,MAAM;oBACvB,WAAW,EAAE,GAAG,CAAC,WAAW;oBAC5B,MAAM,EAAE,GAAG,CAAC,MAAM;oBAClB,YAAY,EAAE,GAAG,CAAC,YAAY;oBAC9B;;;;;;;;;;;;;;;;;;;;;;uBAsBG;oBACH,OAAO,EAAE,MAAM,CAAC,OAAO,CAAE,GAAG,CAAC,UAAkB,EAAE,OAAO,IAAI,EAAE,CAAC;yBAC5D,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAgB,EAAE,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,IAAI,IAAI,EAAE,CAAC,CAAC;wBAC3E,0DAA0D;yBACzD,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC;oBAC7E,eAAe,EAAG,GAAG,CAAC,UAAkB,EAAE,eAAe,IAAI,IAAI;iBAClE;gBACH,CAAC,CAAC,IAAI;YACR;;;;;;eAMG;YACH,MAAM,EAAE,IAAI,CAAC,MAAM,IAAI,IAAI;YAC3B,SAAS,EAAE,CAAC,CAAE,IAAI,CAAC,MAAc,EAAE,IAAI;YACvC,QAAQ;YACR,KAAK;YACL,2DAA2D;YAC3D,YAAY;YACZ;;;eAGG;YACH,KAAK,EAAE;gBACL,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC;gBAC7B,QAAQ,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;gBACnF,8CAA8C;gBAC9C,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;aACpE;SACF,CAAA;IACH,CAAC;IACD;;;;;;;;;;OAUG;IAMG,AAAN,KAAK,CAAC,gBAAgB,CAAoB,UAAkB,EAAS,OAAwB;QAC3F,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAA;QACxC,MAAM,IAAI,GAAG,MAAM,IAAA,qBAAa,EAAC,+BAAY,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,UAAU,EAAE,EAAE,CAAC,CAAA;QAC3G,IAAI,CAAC,IAAI;YAAE,OAAO,IAAI,CAAA;QACtB,MAAM,KAAK,GAAG,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAQ,CAAA;QACvC;;;;WAIG;QACH,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO;YACxB,CAAC,CAAC,MAAM,IAAA,qBAAa,EAAC,yBAAS,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC;YACxG,CAAC,CAAC,IAAI,CAAA;QACR;;;WAGG;QACH,MAAM,UAAU,GAAG,IAAA,mCAAc,EAC/B,KAAK,EACL,qBAAU,CAAC,MAAM,CAAC,QAAQ,EAAE,UAAU,CAAC,EACvC,MAAM,qBAAU,CAAC,sBAAsB,CAAC,QAAQ,EAAE,UAAU,CAAC,CAC9D,CAAA;QACD,OAAO;YACL,UAAU;YACV,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,SAAS,EAAE,KAAK,EAAE,IAAI;YACtB,UAAU,EAAE,IAAA,+CAAuB,EAAC,IAAI,CAAC,IAAI,CAAC;YAC9C,QAAQ,EAAE,CAAC,IAAI,CAAC,iBAAiB,IAAI,EAAE,CAAU;YACjD,eAAe,EAAE,CAAC,KAAK,EAAE,iBAAiB,IAAI,EAAE,CAAU;YAC1D,0DAA0D;YAC1D,OAAO,EAAE;gBACP,GAAG,CAAC,KAAK,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC,UAAU,IAAI,EAAE,EAAE,CAAC,CAAC;gBAC1I,GAAG,CAAC,IAAA,iCAAkB,EAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC,UAAU,IAAI,EAAE,EAAE,CAAC,CAAC;gBAC/J;;;;;;mBAMG;gBACH,GAAG,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;oBACvB,MAAM,EAAE,WAAW;oBACnB,EAAE,EAAE,EAAE,CAAC,IAAI;oBACX,IAAI,EAAE,EAAE,CAAC,KAAK;oBACd,UAAU,EAAE,wBAAwB,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,iBAA0B,EAAE,KAAK,EAAE,iBAA0B,CAAC;iBAClH,CAAC,CAAC;aACJ;YACD;;;eAGG;YACH,UAAU;SACX,CAAA;IACH,CAAC;IACD;;;;;;;;;;OAUG;IAMG,AAAN,KAAK,CAAC,iBAAiB,CAAiB,OAAe,EAAS,OAAwB;QACtF,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAA;QACxC,MAAM,KAAK,GAAG,MAAM,IAAA,qBAAa,EAAC,yBAAS,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,OAAO,EAAE,EAAE,CAAC,CAAA;QACtG,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAA;QACvB,MAAM,KAAK,GAAG,MAAM,IAAA,qBAAa,EAAC,+BAAY,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,OAAO,EAAE,EAAE,CAAC,CAAA;QAEtG,yDAAyD;QACzD,MAAM,IAAI,GAAG,IAAI,GAAG,EAAe,CAAA;QACnC,KAAK,MAAM,CAAC,IAAI,KAAK;YAAE,KAAK,MAAM,IAAI,IAAI,IAAA,+CAAuB,EAAC,CAAC,CAAC,IAAI,CAAC;gBAAE,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;oBAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,CAAA;QAE1H,oEAAoE;QACpE,MAAM,OAAO,GAAG,IAAI,GAAG,EAAyF,CAAA;QAChH,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;YACtB,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAQ,CAAA;YACpC,MAAM,GAAG,GAAG,CAAC,MAA8C,EAAE,CAAM,EAAE,EAAE;gBACrE,MAAM,GAAG,GAAG,GAAG,MAAM,IAAI,CAAC,CAAC,EAAE,EAAE,CAAA;gBAC/B,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;gBAC5B,IAAI,GAAG,EAAE,CAAC;oBAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;oBAAC,OAAM;gBAAC,CAAC;gBACjD,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,CAAA;YACrG,CAAC,CAAA;YACD,KAAK,MAAM,CAAC,IAAI,KAAK,CAAC,SAAS,IAAI,EAAE;gBAAE,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC,CAAA;YACzD,KAAK,MAAM,CAAC,IAAI,IAAA,iCAAkB,EAAC,KAAK,CAAC,IAAI,EAAE;gBAAE,GAAG,CAAC,WAAW,EAAE,CAAC,CAAC,CAAA;YACpE;;;eAGG;YACH,KAAK,MAAM,EAAE,IAAI,IAAA,mCAAc,EAC7B,KAAK,EACL,qBAAU,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,UAAU,CAAC,EACzC,MAAM,qBAAU,CAAC,sBAAsB,CAAC,QAAQ,EAAE,CAAC,CAAC,UAAU,CAAC,CAChE;gBACC,GAAG,CAAC,WAAW,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC,KAAK,EAAE,CAAC,CAAA;QACrD,CAAC;QAED,OAAO;YACL,OAAO;YACP,SAAS,EAAE,KAAK,CAAC,IAAI;YACrB,UAAU,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;YAC9B,QAAQ,EAAE,CAAC,KAAK,CAAC,iBAAiB,IAAI,EAAE,CAAU;YAClD,OAAO,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;YAC9B,+CAA+C;YAC/C,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;SAClF,CAAA;IACH,CAAC;CACF,CAAA;AAvpBY,wCAAc;AAoDnB;IALL,IAAA,oBAAK,EAAC,OAAO,CAAC,EAAE,CAAC,oBAAY,EAAE;QAC9B,QAAQ,EAAE,IAAI;QACd,WAAW,EACT,iNAAiN;KACpN,CAAC;IACsB,mBAAA,IAAA,kBAAG,EAAC,YAAY,CAAC,CAAA;IAAsB,mBAAA,IAAA,kBAAG,GAAE,CAAA;;;;sDA+dnE;AAiBK;IALL,IAAA,oBAAK,EAAC,OAAO,CAAC,EAAE,CAAC,oBAAY,EAAE;QAC9B,QAAQ,EAAE,IAAI;QACd,WAAW,EACT,mUAAmU;KACtU,CAAC;IACsB,mBAAA,IAAA,kBAAG,EAAC,YAAY,CAAC,CAAA;IAAsB,mBAAA,IAAA,kBAAG,GAAE,CAAA;;;;sDAsDnE;AAiBK;IALL,IAAA,oBAAK,EAAC,OAAO,CAAC,EAAE,CAAC,oBAAY,EAAE;QAC9B,QAAQ,EAAE,IAAI;QACd,WAAW,EACT,mQAAmQ;KACtQ,CAAC;IACuB,mBAAA,IAAA,kBAAG,EAAC,SAAS,CAAC,CAAA;IAAmB,mBAAA,IAAA,kBAAG,GAAE,CAAA;;;;uDA2C9D;yBAtpBU,cAAc;IAF1B,IAAA,uBAAQ,GAAE;IACV,IAAA,4BAAa,EAAC,qBAAa,CAAC;GAChB,cAAc,CAupB1B","sourcesContent":["import { axisSeenInJournal } from './axis-journal-evidence.js'\nimport { hydratedDate } from '../../engine/read-time.js'\nimport { statusTally } from './status-tally.js'\nimport { TwinEvent } from '../twin-event/twin-event.js'\nimport { Arg, Ctx, Query, Resolver, UseMiddleware } from 'type-graphql'\n\nimport { ScalarObject, SpeakRefusals, getRepository } from '@things-factory/shell'\n\nimport { TwinEngine } from '../../engine/index.js'\nimport { modelGapOf } from '../../engine/model-gap.js'\nimport { readBoardEquipment } from '@operato/ops-contract'\nimport { TwinInstance } from '../twin-instance/twin-instance.js'\nimport { TwinSpace } from '../twin-space/twin-space.js'\nimport { TwinReference } from '../reference/twin-reference.js'\nimport { declarablePropertySpecs } from '../../engine/local-declarations.js'\nimport { operationBasis } from '../../engine/operation-basis.js'\nimport { TwinLocation } from './twin-location.js'\nimport { TwinEquipment } from './twin-equipment.js'\nimport { TwinOperation } from './twin-operation.js'\nimport { standardsForKind, type StandardId } from './standard-coverage.js'\nimport { isa95Coverage } from './isa95-coverage.js'\nimport { iec61850Coverage } from './iec61850-coverage.js'\nimport { epcisCoverage } from './epcis-coverage.js'\n\n/**\n * 이 공정에 선언된 시간을 **겹에서** 든다 — 좁은 겹이 이긴다(트윈 먼저, 없으면 현장).\n *\n * 모델에는 ISO 8601 로 구워지지만 화면에는 **사용자가 넣은 수와 단위**를 보인다: 「PT240S」를 보이면\n * 자기가 넣은 값인지 알아볼 수 없다. 선언이 없으면 빈 배열이다(빈 값을 지어내지 않는다).\n */\nfunction declaredDurationProperty(kind: string, instanceLayer?: any[], spaceLayer?: any[]): any[] {\n const find = (layer?: any[]) => {\n const d = (layer ?? []).find(x => x?.target === 'operation' && String(x?.id ?? '') === kind)\n return (d?.properties ?? []).find((p: any) => p?.id === 'operation.duration')\n }\n const p = find(instanceLayer) ?? find(spaceLayer)\n if (!p) return []\n return [{ id: 'operation.duration', value: String(p.value ?? ''), ...(p.uom ? { uom: String(p.uom) } : {}), source: 'local' }]\n}\n\n/** 표준 id → 그 표의 함수. 정책은 `standardsForKind` 가, 표는 각 파일이 가진다. */\nconst COVERAGE: Record<StandardId, (axes: string[]) => any> = { isa95: isa95Coverage, epcis: epcisCoverage, iec61850: iec61850Coverage }\nimport { unwrapState } from '../../engine/warm-start.js'\n/* 공유 모듈은 빌드 산출물로 참조한다 — 서버·클라이언트가 같은 규칙을 쓰는 자리다(같은 관행: entity-delta). */\nimport { axisValueOf } from '@things-factory/headless-twin/dist-shared/axis-read.js'\n\n/* 커널 런타임 로드 — CJS 번들(엔진과 같은 방식). 축·관계 선언의 SSOT 다. */\nconst { TWIN_AXES, TWIN_RELATIONS, axisInfo, axisSource, axisAppliesTo } = require('@operato/ops-contract')\n\n/**\n * 축 → 그 축이 이미 **행으로 옮겨졌나**. 옮겨진 축은 DB 가 세고, 아직인 축은 문서를 세어야 한다.\n *\n * 이 표가 곧 `ADR-0032` 이주의 진척이다 — 여기 없는 축은 아직 `TwinModelDef` 문서 안에 산다.\n */\nconst ROW_BACKED: Record<string, any> = {\n locations: TwinLocation,\n equipment: TwinEquipment,\n operations: TwinOperation\n}\n\n/** `productionSpec.definition.recipes` 같은 경로를 문서에서 따라간다. */\nconst at = (o: any, path: string) => path.split('.').reduce((a: any, k: string) => (a == null ? undefined : a[k]), o)\n\nfunction countInDocument(model: any, path: string): number {\n const v = at(model, path)\n if (Array.isArray(v)) return v.length\n return v ? 1 : 0\n}\n\n/*\n * 트윈 모델 조회 — **이 트윈은 표준 모델의 어디를 채우고 있나**(`plans/twin-inspection.md` §2 ②).\n *\n * ── 답의 크기가 개념 수에 비례한다 ─────────────────────────────────────────\n * 엔티티를 **절대 싣지 않는다.** 실으면 계약이 곧 무너지고, 규모가 오는 날 이 질의가 그대로\n * 병목이 된다. 항목은 별도 질의(`twinModelEntities`)가 페이징으로 낸다.\n *\n * ── 개념 목록을 이 코드가 갖지 않는다 ───────────────────────────────────────\n * 축·관계는 **커널 카탈로그가 선언**한다(`TWIN_AXES`·`TWIN_RELATIONS`). 그래서 야드의 `dock-door`\n * 나 에너지의 계량기가 늘어도 여기 손댈 것이 없다 — 도메인마다 화면·질의가 하나씩 늘어나던\n * 구조를 끊는 것이 이 설계의 요점이다(`ADR-0031`).\n *\n * ── 어떻게 셌는지 밝힌다 ───────────────────────────────────────────────────\n * 지금은 축 셋만 행이고 나머지는 문서 안에 있다. 그 사실을 `basis` 로 **축마다** 말한다.\n * 밝히지 않으면 \"이 트윈은 3개 축뿐\" 으로 읽히고, 이주가 어디까지 왔는지도 아무도 모른다.\n */\n/** `inputs[].material` 처럼 배열을 지나는 선언 경로를 따라간다 — 배열 표기가 관계 선언의 문법이다. */\nfunction valuesAt(obj: any, field: string): any[] {\n let cur: any[] = [obj]\n for (const seg of field.split('.')) {\n const key = seg.endsWith('[]') ? seg.slice(0, -2) : seg\n const next: any[] = []\n for (const c of cur) {\n if (c == null) continue\n const v = c[key]\n if (v == null) continue\n if (Array.isArray(v)) next.push(...v)\n else next.push(v)\n }\n cur = next\n }\n return cur.filter(v => v != null)\n}\n\nconst idOf = (o: any): string | null => (typeof o === 'string' ? o : o?.id ?? o?.key ?? o?.gtin ?? null)\n\n/** 상태가 빈 축의 이유 — 저널에 그 사실이 있으면 그렇게 말한다. 판단할 수 없으면 예전 그대로. */\nasync function emptyStateReason(domainId: string, instanceId: string, axis: string): Promise<string> {\n try {\n const seen = await axisSeenInJournal(getRepository(TwinEvent), { domain: { id: domainId }, instanceId }, axis)\n /* 판단할 수 없는 축(`null`)은 예전 답을 그대로 쓴다 — 모르는 것을 새 사실로 만들지 않는다. */\n return seen ? 'observed-not-in-state' : 'none-yet'\n } catch {\n /* 저널을 못 읽었다고 카드가 없는 말을 하지는 않는다. */\n return 'none-yet'\n }\n}\n\n/**\n * 되세운 상태를 담아 둔다 — **열쇠에 저널 끝 리비전이 들어 있어** 새 사건이 오면 저절로 낡는다.\n *\n * 계산은 저널 전체를 훑는 일이라(리비전 12만에서 2~3초) 모델 화면을 열 때마다 그 값을 낼 수 없다.\n * 프로세스 안에만 두고 몇 개만 남긴다 — 다시 뜨면 다시 계산한다(정확함이 캐시보다 앞선다).\n */\nconst RECALL_CACHE = new Map<string, { snap: any; heardAt: string | null }>()\nconst RECALL_CACHE_MAX = 8\n\n@Resolver()\n@UseMiddleware(SpeakRefusals)\nexport class TwinModelQuery {\n /**\n * 이 선이 **얼마나 이어져 있나** — 그리고 **얼마나 끊겨 있나.**\n *\n * 선이 \"선언되었고 양끝이 존재한다\" 만 말하면 지도는 그림일 뿐이다. 관계에서 가장 중요한 정보는\n * 대개 **부재**다 — 기준 자리가 비어 있는 설비 열두 대, 어느 라우트에도 안 실린 공정. 그것이\n * 조감도에서 보여야 사람이 끊긴 데를 찾아다니지 않는다.\n *\n * 셋을 센다:\n * · `linked` — 값이 있고 그 값이 상대편에 **실제로 있다**\n * · `dangling` — 값은 있는데 **가리키는 것이 없다**(끊어진 참조 — 가장 나쁜 부류)\n * · `missing` — 값 자체가 없다(선택 관계면 정상, 필수 관계면 결손)\n *\n * 문서 어휘로 푼다 — 관계 선언의 필드 이름이 원본 문서의 어휘이기 때문이다(행은 자기 컬럼\n * 이름을 쓴다). 그 사실을 `fillBasis` 로 함께 낸다.\n */\n private edgeFill(model: any, r: any): any {\n const fromInfo = axisInfo(r.from)\n const toInfo = axisInfo(r.target.axis)\n if (!fromInfo || !toInfo) return {}\n\n /*\n * **문서로 셀 수 없는 관계는 세지 않는다.** 선 채움(이어짐·끊어짐·빈 것)은 두 축을 문서에서\n * 살펴 센다. 그런데 일정·실적은 문서에 없다(관측 축) — 그 관계를 문서로 세면 언제나 0 이 나오고,\n * 화면은 그것을 \"전부 끊어졌다\" 로 읽는다. 셀 수 없으면 **수를 내지 않는 편이 정직하다.**\n */\n if (axisSource(r.from) !== 'document' || axisSource(r.target.axis) !== 'document') return {}\n\n const listOf = (info: any) => {\n const raw = at(model, info.path)\n return Array.isArray(raw) ? raw : raw ? [raw] : []\n }\n const targets = new Set(listOf(toInfo).map(idOf).filter(Boolean) as string[])\n let linked = 0\n let dangling = 0\n let missing = 0\n for (const item of listOf(fromInfo)) {\n const vals = valuesAt(item, r.field).map(v => (typeof v === 'object' ? idOf(v) : v)).filter(v => v != null).map(String)\n if (!vals.length) { missing++; continue }\n /* 한 항목이 여럿을 가리킬 수 있다(`steps[]`). 하나라도 끊겼으면 끊긴 쪽으로 센다 —\n \"대체로 이어져 있다\" 는 진단이 아니다. */\n if (vals.every(v => targets.has(v))) linked++\n else dangling++\n }\n return { linked, dangling, missing, fillBasis: 'document' }\n }\n\n @Query(returns => ScalarObject, {\n nullable: true,\n description:\n 'What this twin reflects and where it fills the standard model: per-concept counts, how each was counted, and the declared relations between concepts. Never carries entities — use twinModelEntities for items.'\n })\n async twinModelSummary(@Arg('instanceId') instanceId: string, @Ctx() context: ResolverContext): Promise<any | null> {\n const domainId = context.state.domain.id\n const inst = await getRepository(TwinInstance).findOne({ where: { domain: { id: domainId }, instanceId } })\n if (!inst) return null\n\n /*\n * 어느 원본을 반영하나 — 없을 수 있다(템플릿으로 세운 트윈). 그 사실도 사실이다.\n *\n * ── **레퍼런스 열쇠는 인스턴스 이름이 아니다** (2026-08-24 실측) ──────────────\n * 여기서 `source: instanceId` 로 찾고 있었다. 레퍼런스 하나가 인스턴스 하나를 낳던 시절에는\n * 두 값이 같았지만, **레퍼런스 하나가 여러 트윈을 먹이는 순간 어긋난다.**\n *\n * 인스턴스 operato-chef-v1-pocheon\n * origin { kind: 'reference', source: 'seunghwa' } ← 이것이 레퍼런스 열쇠다\n * 레퍼런스 seunghwa\n *\n * 그래서 요약의 `source` 가 **언제나 `null`** 이었다. 레퍼런스로 세운 트윈인데 화면이 그 원본을\n * 못 찾았고, 「마지막 동기화」도 흐름별 신선도도 그릴 자리가 아예 없었다 — 그런데 오류는 없었다\n * (`ref ? … : null` 이 알리지 않고 갈렸다).\n *\n * 인스턴스가 자기 원본을 말하고 있으므로 **그 말을 먼저 듣는다.** 옛 트윈은 두 값이 같으므로\n * 뒤의 것으로 여전히 찾힌다 — 가산적이다.\n */\n const refKey = (inst.origin as any)?.source || instanceId\n const ref = await getRepository(TwinReference)\n .findOne({ where: { domain: { id: domainId }, source: refKey } })\n .catch(() => null)\n\n const model = inst.model ?? {}\n /*\n * **한 요청에 저널은 한 번만 계산한다.**\n *\n * 관측 축(`orders`·`tasks`)은 상태에서 센다. 그 둘이 각자 `recover()` 를 부르고 있었고, 커널이\n * 멈춰 있으면 그것은 **저널 전체를 다시 계산하는 일**이다(23,731건짜리 트윈에서 4.6초, 두 번이면 곱절).\n * 트윈을 전부 멈춰도 이 화면이 5~7초 걸린 이유가 이것이다 — 부하가 아니라 같은 일을 두 번 한 것이다.\n *\n * 한 번만 계산해 나눠 쓴다. 값이 같아지는 것은 덤이 아니라 **옳음**이다: 두 번 계산하면 그 사이에\n * 들어온 이벤트 때문에 오더와 작업이 서로 다른 시점의 사실이 될 수 있다.\n */\n let statePromise: Promise<{ snap: any; folded: boolean; observing: boolean }> | null = null\n const stateOnce = () =>\n (statePromise ??= (async () => {\n const observing = TwinEngine.isRunning(domainId, instanceId)\n let snap = observing ? unwrapState(TwinEngine.snapshot(domainId, instanceId)) : null\n let folded = false\n if (!snap) {\n try {\n snap = unwrapState(await TwinEngine.recover(domainId, instanceId))\n folded = !!snap\n } catch {\n /* 다시 계산할 것이 없다 — 0 으로 메우지 않는다(카드는 \"모름\" 을 낸다). */\n }\n }\n return { snap, folded, observing }\n })())\n\n /*\n * ── **라이브가 잊은 것을 저널이 안다** (2026-08-23) ─────────────────────────\n *\n * 미러의 관측은 메모리에만 산다. 재기동하면 빈 채로 시작하고, 원본이 다시 말해 줄 때 채워진다 —\n * 그런데 읽기 커서가 정직해진 뒤로는 원본이 **지난 것을 다시 말하지 않는다.** 그래서 재고 741건이\n * 저널에 있는데 화면은 「0」을 보였다. 사용자가 「재고현황이 없다」고 물은 자리가 이것이다.\n *\n * 그 0 은 사실이 아니라 **우리가 잊은 것**이다. 저널을 계산하면 그대로 되살아난다(실측: 리비전\n * 97,689 을 2.4초에 계산해 물품 741 · 작업 9,145 · 지시 2,856).\n *\n * ── 그래서 계산한다. 다만 **언제 들은 값인지 함께 낸다** ──────────────────────\n * 저널을 계산하는 것은 **원천이 우리에게 말한 것을 다시 세우는 일**이지, 없는 값을 심는 일이 아니다.\n * 그러나 물품·재고처럼 **절대값인 축**은 우리가 못 듣는 사이 떠났을 수 있다 — 그래서 값과 함께\n * `heardAt`(그 계산의 시계)을 낸다. 사용자가 신선도를 스스로 판정할 수 있어야 하고, 화면은 그것을\n * 값 옆에 적는다. 시각 없이 수만 내면 낡은 값을 지금으로 읽는다.\n *\n * 계산하는 조건을 좁게 둔다: **관측 축이 비어 있고, 저널에 그 축의 사실이 있을 때만**(그 판정은 색인\n * 한 줄이다). 그리고 한 요청에 **한 번만** 계산한다 — 위 `stateOnce` 와 같은 규율이다.\n */\n let journalPromise: Promise<{ snap: any; heardAt: string | null } | null> | null = null\n const journalOnce = () =>\n (journalPromise ??= (async () => {\n try {\n /*\n * 관계로 묻지 않는다 — 두 단계 질의가 되어 안쪽에 상한이 없고, 그 트윈의 저널을 전부 만든 뒤\n * 한 줄을 고른다(2026-08-28 · 같은 모양이 현장 성과 화면에서 7.2초였다). 색인의 끝만 읽는다.\n */\n const [tipRow, latestRow] = await Promise.all([\n getRepository(TwinEvent)\n .createQueryBuilder('e')\n .select('MAX(e.revision)', 'max')\n .where('e.domain = :domainId', { domainId })\n .andWhere('e.instanceId = :instanceId', { instanceId })\n .getRawOne<{ max: unknown }>(),\n /*\n * 「저널 끝의 사건 시각」은 **가장 늦은 사건 시각**이다 — 리비전이 가장 큰 행의 시각이\n * 아니다. 그 둘은 어긋난다(연결된 시스템을 되읽는 트윈은 원본의 시각을 싣고 도착 순서로\n * 리비전을 받는다). 색인의 끝을 집으므로 질의 둘이어도 각각 한 줄이다.\n */\n getRepository(TwinEvent)\n .createQueryBuilder('e')\n .select('MAX(e.eventTime)', 'at')\n .where('e.domain = :domainId', { domainId })\n .andWhere('e.instanceId = :instanceId', { instanceId })\n .getRawOne<{ at: unknown }>()\n ])\n const tip = { revision: Number(tipRow?.max) || 0, eventTime: hydratedDate(getRepository(TwinEvent), 'eventTime', latestRow?.at) }\n if (!tip.revision) return null\n /*\n * **한 번 계산한 것을 다시 계산하지 않는다.** 계산은 저널 전체를 훑는 일이다(리비전 12만에서 2~3초).\n * 이 화면은 사람이 여러 번 들어오는 자리이므로 그대로 두면 매번 그 값을 낸다 — 그리고 저널이\n * 수백만 행이 되면 그 비용이 화면을 못 쓰게 만든다.\n *\n * 열쇠에 **저널 끝의 리비전**을 넣는다: 새 사건이 오면 열쇠가 달라지므로 캐시가 저절로 낡는다\n * (캐시가 사실을 이기지 않는다). 프로세스 안에만 두고 몇 개만 남긴다.\n */\n const key = `${domainId}:${instanceId}:${tip.revision}`\n const hit = RECALL_CACHE.get(key)\n if (hit) return hit\n const snap = unwrapState(await TwinEngine.recover(domainId, instanceId, tip.revision))\n if (!snap) return null\n /* 그 계산의 시계가 「언제 들은 값인가」다. 없으면 저널 끝의 사건 시각으로 답한다. */\n const out = { snap, heardAt: (snap as any).nowTime ?? tip.eventTime?.toISOString() ?? null }\n RECALL_CACHE.set(key, out)\n /* 오래된 열쇠부터 버린다 — 트윈 몇 개를 번갈아 봐도 메모리가 자라지 않게. */\n while (RECALL_CACHE.size > RECALL_CACHE_MAX) RECALL_CACHE.delete(RECALL_CACHE.keys().next().value as string)\n return out\n } catch {\n /* 계산하지 못했으면 아무 말도 만들지 않는다 — 라이브가 말한 것을 그대로 둔다. */\n return null\n }\n })())\n\n /*\n * 개념 카드가 선언을 그대로 나른다 (2026-09-18, ADR-0074).\n *\n * `journalAxis` 는 「이 축의 개체 이력을 저널의 어느 축으로 묻나」이고, 없으면 저널이 그 축으로\n * 기록하지 않는다는 뜻이다. `describedBy` 는 식별자 말고 무엇이 그 개체를 말하나이다. 둘 다 앱의\n * 화면 상수에 있었고, 축 이름이 바뀌었을 때 따라오지 못해 세 축의 이력이 조용히 비었다.\n * 여기서 내보내면 화면은 목록을 갖지 않는다 — 축이 늘어도 화면은 그대로다.\n */\n const concepts = await Promise.all(\n TWIN_AXES.map(async (a: any) => {\n /*\n * **이 종류에 없는 개념인가** — 「아직 없음」과 「해당 없음」은 다른 말이다.\n *\n * 에너지 트윈에는 옮겨 다니는 물건도, 배정할 사람도, 공정도 없다(커널이 축마다 선언한다).\n * 그것을 「로트 0」으로 그리면 사용자는 채우러 갈 곳을 찾고, 적합성 표는 채우지 못한 것으로\n * 센다 — 둘 다 거짓이다. 수는 `null`(모름이 아니라 셀 대상이 아님)이고 이유를 코드로 낸다.\n *\n * 세지도 않는다: 없는 개념을 행에서 세는 것은 질의만 늘리고 답을 바꾸지 않는다.\n */\n if (!axisAppliesTo(a.axis, inst.kind)) {\n return {\n axis: a.axis,\n label: a.label,\n kind: a.kind,\n container: false,\n standardClass: a.standardClass,\n typeRole: a.typeRole ?? null,\n journalAxis: a.journalAxis ?? null,\n describedBy: a.describedBy ?? null,\n count: null,\n notApplicable: true,\n emptyBecause: 'not-applicable',\n /*\n * **그 개념의 성질** — 선언인가 관측인가 (2026-08-22).\n *\n * `basis` 와 다르다: `basis` 는 「이 값이 어디서 왔나」이고 트윈마다·시점마다 달라진다(같은\n * 축이 한 트윈에서 `journal`, 다른 트윈에서 `state` 로 온다). 그것으로 묶으면 같은 축이 화면\n * 마다 다른 묶음에 들어간다. `source` 는 트윈과 무관하게 고정이므로 묶는 축이 된다.\n *\n * 화면이 축 이름을 열거하지 않아도 되고, 축이 늘면 자동으로 맞는 묶음에 들어간다 —\n * 카탈로그가 정본이다.\n */\n source: axisSource(a.axis),\n basis: 'declaration'\n }\n }\n const entity = ROW_BACKED[a.axis]\n /* 문서 축만 문서로 센다 — 경로 없는 축을 세면 모델 루트를 훑는다(상태 축은 아래에서 센다). */\n const inDocument = axisSource(a.axis) === 'document' ? countInDocument(model, a.path) : 0\n const inRows = entity\n ? await getRepository(entity).count({ where: { domain: { id: domainId } as any, instance: { id: inst.id } as any } })\n : undefined\n /*\n * **둘을 함께 세고 어긋나면 말한다.**\n *\n * 행으로 옮긴 축이라도 그 트윈이 투영을 거치지 않았으면 행은 0이다(인제스트 없이\n * warm-start 된 트윈이 그렇다). 행만 보고 답하면 문서에 자리 6개가 있는데 화면은\n * **0 이라고 말한다** — 들어온 것이 없는 거짓이고, 이 프로젝트가 내내 잡아 온 바로 그 부류다.\n *\n * 그래서 어느 하나로 메우지 않는다. 행 수를 답하되 문서 수를 함께 내고, 다르면\n * `stale` 로 표시한다 — 그 차이 자체가 \"이 트윈은 투영 이후 인제스트되지 않았다\" 는 정보다.\n */\n const stale = entity !== undefined && inRows !== inDocument\n /*\n * **그릇인가** — 문서에 객체 하나로 있는 축(`productionSpec`).\n *\n * `kind` 로는 갈리지 않는다: 커널은 공정·레시피·라우트도 `spec` 이라 부른다(같은 선언 부류라는\n * 뜻이다). 그릇인지 아닌지는 **모양**이 말한다 — 목록이 되는 축은 배열이고, 한 벌뿐인 선언은\n * 객체 하나다. 개념 지도는 개체를 세는 면이므로 그릇은 자기 면에서 통째로 읽는다.\n */\n const raw = axisSource(a.axis) === 'document' ? at(model, a.path) : undefined\n /*\n * **관측 축은 상태가 센다**(일정·실적 — ISA-95 Part 4). 커널이 멈춰 있으면 `null` 이다:\n * 0 으로 내면 \"작업이 없는 공장\" 으로 읽히고, 그건 거짓이다(관측이 없는 것과 0 건은 다르다).\n * 이 화면이 관측 열에서 내내 지켜 온 구분을 카드에서도 지킨다.\n */\n /*\n * **「아직 없다」와 「왔는데 상태에 없다」는 다른 사실이다** (2026-08-22).\n *\n * 화면이 「작업 — 아직 하나도 없습니다」라고 말했는데 저널에는 `task.status` 5,786건이 있었고\n * 마지막 상태가 `in-progress` 였다(원인은 커널의 내보내기였고 그 레인에 넘겼다). 카드가 단정한\n * 탓에 사용자가 그 차이를 직접 조사해야 했다 — 화면이 아는 것을 말하지 않은 자리다.\n *\n * 그래서 상태가 빈 축은 저널을 **한 건만** 물어본다(색인 한 줄, `journal-count` 의 문).\n */\n if (axisSource(a.axis) === 'state') {\n /* 스냅샷은 `{revision, state}` 봉투다 — 벗기지 않으면 축이 한 겹 안에 있어 언제나 `null` 이\n 된다(커널은 도는데 카드가 \"모름\" 으로 보였다). 벗기는 규칙의 집은 `warm-start` 하나다. */\n /*\n * 관측 중인지는 **런타임이 있는지**로 본다 — 캐시된 스냅샷은 관측이 아니다.\n *\n * 동작하지 않으면 저널을 계산해 답한다(라이브=권위 · 히스토리=파생). 카드는 그 차이를 `basis` 로\n * 말한다: 파생을 권위처럼 내면 다시 계산한 수를 \"지금 이만큼\" 으로 읽게 된다.\n */\n const { snap, folded, observing } = await stateOnce()\n /* 축이 사는 자리는 **커널 선언이 말한다**(`path`) — 축 이름으로만 읽으면 중첩된 축이\n 언제나 「관측 없음」이 된다(에너지의 수요 구간이 그렇다). 규칙은 `axisValueOf` 한 곳. */\n let bucket = snap ? axisValueOf(snap, a) ?? null : null\n let heardAt: string | null = null\n let fromJournal = false\n /*\n * 라이브가 잊은 축은 **저널에서 되세운다**(§`journalOnce`). 그 축의 사실이 저널에 있을 때만\n * 계산하고, 값과 함께 「언제 들은 값인가」를 낸다 — 시각 없이 수만 내면 낡은 값을 지금으로 읽는다.\n */\n if (!folded && Array.isArray(bucket) && bucket.length === 0) {\n const seen = await axisSeenInJournal(getRepository(TwinEvent), { domain: { id: domainId }, instanceId }, a.axis).catch(() => null)\n if (seen) {\n const j = await journalOnce()\n const jb = j?.snap ? axisValueOf(j.snap, a) ?? null : null\n if (Array.isArray(jb) && jb.length) {\n bucket = jb\n heardAt = j?.heardAt ?? null\n fromJournal = true\n }\n }\n }\n return {\n axis: a.axis,\n label: a.label,\n kind: a.kind,\n container: false,\n standardClass: a.standardClass,\n typeRole: a.typeRole ?? null,\n journalAxis: a.journalAxis ?? null,\n describedBy: a.describedBy ?? null,\n count: Array.isArray(bucket) ? bucket.length : null,\n /*\n * **수 하나가 뜻을 바꾸는 자리** (2026-08-23).\n *\n * 미러가 완료된 작업까지 상태에 들고 있게 되면서 「작업 2,820」이 되었다. 이 카드는 상태의\n * 인구조사이므로 그 수가 맞다 — 그런데 사람은 그것을 「지금 할 일 2,820건」으로 읽는다.\n * 수를 줄여 거짓으로 만드는 대신 **무엇으로 이루어진 수인지** 함께 낸다.\n *\n * 낱말은 커널의 것을 그대로 쓴다(`created`·`assigned`·`in-progress`·`completed`). 화면이\n * 라벨을 입히고, 없으면 낱말이 그대로 보여 누락이 드러난다.\n */\n ...statusTally(bucket),\n /*\n * **비었으면 왜 비었는지 말한다.** 0 과 `null` 만 내면 화면은 \"없다\" 까지만 말하고, 사용자는\n * \"안 적어 놨나 · 아직 안 일어났나 · 못 세었나\" 를 구별할 수 없다. 이 화면이 관측 열에서\n * 내내 지켜 온 구분(§observedAbsence)을 카드에서도 지킨다.\n */\n ...(Array.isArray(bucket)\n ? bucket.length\n ? {}\n : { emptyBecause: await emptyStateReason(domainId, instanceId, a.axis) }\n : { emptyBecause: 'not-observed' }),\n source: axisSource(a.axis),\n basis: folded || fromJournal ? 'journal' : 'state',\n /*\n * **언제 들은 값인가** — 저널에서 되세운 축만 갖는다. 라이브가 답한 축은 지금이므로 없다.\n * 이 값이 없으면 화면이 낡은 수를 지금으로 읽는다(그 구별이 이 카드의 전부다).\n */\n ...(fromJournal && heardAt ? { heardAt, recalled: true } : {}),\n observing,\n /* 선언이 아니라 관측인 축 — 화면이 \"원본이 침묵했다\" 로 읽지 않게 사실로 말한다. */\n observedOnly: true,\n standardUndeclared: !a.standardClass?.isa95 && !a.standardClass?.epcis && !a.standardClass?.iso55000\n }\n }\n return {\n axis: a.axis,\n label: a.label,\n kind: a.kind,\n container: !Array.isArray(raw) && raw != null,\n standardClass: a.standardClass,\n typeRole: a.typeRole ?? null,\n journalAxis: a.journalAxis ?? null,\n describedBy: a.describedBy ?? null,\n count: entity ? inRows : inDocument,\n /*\n * 비었으면 왜 비었는지 — 선언 쪽은 세 갈래다.\n * · `not-declared` 이 트윈의 모델이 그 축을 아예 말하지 않는다(대개 템플릿이 안 적었다)\n * · `declared-empty` 선언은 있는데 목록이 비어 있다(적었다가 지운 것도 사실이다)\n * · `not-projected` 문서엔 있는데 행에 없다 — 투영을 거치지 않은 트윈이다(`stale` 과 같은 사실)\n *\n * 셋을 \"0\" 하나로 합치면 사용자가 손볼 곳을 찾지 못한다: 첫째는 템플릿, 둘째는 원본,\n * 셋째는 다시 읽기다. 셋 다 다른 일이다.\n */\n ...((entity ? inRows : inDocument)\n ? {}\n : {\n emptyBecause:\n entity && inDocument > 0 ? 'not-projected' : raw == null ? 'not-declared' : 'declared-empty'\n }),\n /* 'rows' = DB 가 셌다(질의 가능) · 'document' = 문서를 세었다(아직 이주 전). */\n source: axisSource(a.axis),\n basis: entity ? 'rows' : 'document',\n ...(entity ? { documentCount: inDocument, stale } : {}),\n /* 표준 투영이 없는 축은 **숨기지 않고** 그 사실을 낸다(ADR-0031). */\n standardUndeclared: !a.standardClass?.isa95 && !a.standardClass?.epcis && !a.standardClass?.iso55000\n }\n })\n )\n\n /*\n * **원본이 모르는데 실행 중인 것** — 커널은 마스터에 없던 자원도 이벤트로 알게 되고\n * `origin: 'observed'` 를 단다(`observed-reducer`). 그것을 표에 밀어 넣지 않는다 — 그러면\n * 틱 루프에서 DB 로 쓰는 **두 번째 쓰기 경로**가 생기고, 실패하면 알리지 않고 어긋난다\n * (쓰기 경로는 인제스트 하나, ADR-0032-D).\n *\n * 대신 **여기서 비교해 낸다.** 이 차이는 숨겨야 할 불일치가 아니라 인스펙션이 답해야 할\n * 질문이다 — \"원본이 말한 적 없는 설비가 실제로 실행 중이다.\"\n *\n * 트윈이 안 실행 중이면 비교할 상대가 없다 — 그때는 `null` 이다(0 이 아니다. 없는 것과\n * 세어 보지 못한 것은 다르다).\n */\n /*\n * 도출은 **한 벌**이다(`engine/model-gap.ts`). 예전에는 이 자리에 인라인으로 있었는데, 같은 사실을\n * 「현장과 맞춰지고 있나」 화면도 물어야 해서 두 곳이 다른 수를 말할 위험이 생겼다.\n *\n * 이 화면은 **전체 목록**이 필요하다(인스펙션이니까). 그래서 상한 없는 원본을 여기서 만들고,\n * 상한이 걸린 요약은 `modelGapOf` 가 답한다 — 같은 판정(`origin === 'observed'`)을 쓴다.\n */\n const snap = TwinEngine.snapshot(domainId, instanceId)\n const gap = modelGapOf(snap)\n const observedOnly = snap\n ? {\n equipment: (snap.equipment ?? []).filter((e: any) => e?.origin === 'observed').map((e: any) => e.id),\n locations: (snap.locations ?? []).filter((l: any) => l?.origin === 'observed').map((l: any) => l.id),\n persons: (snap.persons ?? []).filter((p: any) => p?.origin === 'observed').map((p: any) => p.id),\n /* 커널이 담을 줄 몰라 세어 둔 사건·모르는 설비 보고 — 인스펙션이 이미 물을 자리다. */\n unhandled: gap?.unhandled ?? [],\n unknownEquipmentReports: gap?.unknownEquipmentReports ?? null,\n notCovered: gap?.notCovered ?? []\n }\n : null\n\n /* 지도의 선 — 선언된 관계 중 **양끝이 이 트윈에 실재하는 것만**. 없는 선을 그리지 않는다. */\n /* 선의 양끝 판정은 **문서든 행이든 있으면 있는 것**으로 본다 — 투영이 낡았다고 관계가 없어지진 않는다. */\n const nonEmpty = new Set(concepts.filter(c => (c.count ?? 0) > 0 || ((c as any).documentCount ?? 0) > 0).map(c => c.axis))\n /* 선은 **얼마나 이어졌고 얼마나 끊겼는지**까지 말한다 — 관계에서 가장 중요한 정보는 대개 부재다. */\n const edges = await Promise.all(\n TWIN_RELATIONS.filter((r: any) => r.target.kind === 'axis' && nonEmpty.has(r.from) && nonEmpty.has(r.target.axis)).map(\n async (r: any) => ({ from: r.from, to: r.target.axis, via: r.via, optional: !!r.optional, ...this.edgeFill(model, r) })\n )\n )\n\n return {\n instanceId,\n /* 사람이 부르는 이름 — 결선 줄이 업무키만 보이지 않게(업무키는 곁에 남는다). */\n name: inst.name ?? null,\n /*\n * **생산 선언에서 갈 곳이 없는 두 값** — GS1 발행자와 대표 산출물.\n *\n * 나머지 선언(자재·레시피·라우트·공정)은 각자 개념 축이 있고, 자재의 GS1 참조는 자재가 보인다.\n * 이 둘만 자기 축이 없다: 회사 접두사는 이 트윈의 **정체**(발행자)이고, 대표 레시피는 이 공장이\n * 무엇을 만드는 곳인가다. 둘 다 결선 줄(어느 원본을 반영하나)과 같은 성격이라 그 줄에 둔다.\n */\n /*\n * **표준 적합성** — 채운 것과 빠진 것을 함께.\n *\n * 이 화면은 \"이 트윈이 표준 모델의 어디를 채우고 있나\" 를 묻는다. 그런데 지금까지 답은 우리\n * 축만 세었다 — 없는 것은 화면에 없으므로 아무도 묻지 않았다. 기준(표준의 목록)을 함께 내면\n * 그 질문이 실제로 답을 갖는다(`isa95-coverage.ts` 의 머리말 참조).\n */\n /* 종류가 기대는 표준을 **모두** 낸다 — 하나만 말하면 그 트윈의 다른 기준이 보이지 않는다. */\n standards: standardsForKind(inst.kind).map(id => COVERAGE[id]((TWIN_AXES as any[]).map(a => a.axis))),\n production: (() => {\n const spec: any = (inst.model as any)?.productionSpec\n if (!spec) return null\n const key = spec.recipeKey ?? null\n const material = (spec.definition?.materials ?? []).find((m: any) => (m.key ?? m.id) === key)\n return {\n companyPrefix: spec.companyPrefix ?? null,\n recipeKey: key,\n /* 이름은 자재 선언이 말한다(i18n 키일 수 있으므로 번역은 화면의 일). */\n recipeLabel: material?.label ?? material?.name ?? null\n }\n })(),\n /*\n * ── **식별자가 무엇에 근거하나** (2026-08-24) ──────────────────────────────\n * 요약이 `production.companyPrefix` 를 그대로 보이는데 **그것이 발급받은 번호인지 말할 근거가\n * 없었다.** 그래서 사용자가 긴 URI 를 보고 「GS1 을 강제하는 것인가」를 물었다 — 강제는 **이미\n * 없고**(GS1 프리픽스가 없는 현장은 자기 도메인 아래에서 식별자를 만든다, CBV 2.0 §8.3.4)\n * 없다는 사실이 화면에 없었던 것이 문제였다.\n *\n * ★ **이 축만은 무표를 쓰지 않는다.** GS1 형태의 식별자를 본 사람은 그것이 진짜 발급받은\n * 번호라고 가정하므로, 표식이 없으면 그 가정이 곧 거짓 안심이 된다. 계약도 그렇게 적고 있다 —\n * 「없으면 소비처는 판정하지 않는다. 기본값으로 `issued` 를 가정하면 그 화면이 곧 거짓이 된다.」\n * 그래서 화면이 네 갈래 모두에 낱말을 붙일 수 있게 **그대로** 낸다\n * (`claimed-issued`·`declared-namespace`·`gs1-shaped`·`kernel-constant`).\n *\n * 커널이 내는 것을 그대로 넘긴다 — 여기서 다시 판정하면 스냅샷과 요약이 다른 말을 한다.\n * 트윈이 돌지 않거나 커널이 말하지 않으면 `null` 이고, 그때 화면은 **재지 않는다.**\n */\n identityGrounding: (await stateOnce()).snap?.identityGrounding ?? null,\n description: inst.description ?? null,\n kind: inst.kind,\n restartPolicy: inst.restartPolicy,\n source: ref\n ? {\n referenceId: ref.source,\n adapterType: ref.adapterType,\n status: ref.status,\n lastSyncedAt: ref.lastSyncedAt,\n /*\n * ── **원본의 어느 흐름이 어디까지 살아 있나** (2026-08-24) ──────────────\n * 사용자가 「지금 데이터가 들어오는 것이 사실이냐」고 물었고, 화면이 답할 것이 「붙어 있다」\n * 뿐이었다. 그런데 한 원본 안에서 흐름마다 신선도가 **크게 다르다**(실측: 재고 08-23 ·\n * 계측 08-12 · 작업지시 05-10 · 공정·로트 04-15). 「붙어 있다」 하나로 뭉치면 넉 달 멈춘\n * 흐름이 살아 있는 것으로 읽힌다.\n *\n * **계약에는 자리가 있다** — `LiveFeedCursor.since` 가 「그 흐름에서 마지막으로 본 시각\n * (원본의 시각)」이고 `onCursor` 가 그것을 `TwinReference.liveCursor` 에 적는다. 없던 것은\n * **화면으로 가는 문**이고, 그 문이 여기다.\n *\n * ★ **다만 지금은 비어 있다** — 실 저장값을 확인했다:\n * `{\"streams\":{},\"firstAttachedAt\":\"2026-03-25T…\"}`. 즉 어댑터가 흐름별 커서를 적지 않는다.\n * 그래서 이 문을 열어도 당장은 빈 목록이 나오고, **그것이 정직한 답이다**: 어댑터가 말하지\n * 않는 것을 여기서 지어내지 않는다. 채우는 것은 어댑터의 몫이고 그쪽에 알렸다.\n *\n * 빈 목록과 「흐름이 없다」를 화면이 구별할 수 있어야 한다 — 이 값이 비면 그것은\n * 「어댑터가 아직 말하지 않는다」이고 「원본에 흐름이 없다」가 아니다.\n *\n * `seen`(중복 걸러낸 행 id)은 내지 않는다 — 읽기 내부 상태이고 수천 개가 될 수 있다.\n * 흐름 열쇠는 **어댑터가 정한다**(계약이 이름을 닫지 않는다). 그래서 이름을 번역하지 않고\n * 그대로 낸다 — 화면이 모르는 이름을 만나면 그 이름을 보이는 것이 맞다.\n */\n streams: Object.entries((ref.liveCursor as any)?.streams ?? {})\n .map(([stream, c]: [string, any]) => ({ stream, since: c?.since ?? null }))\n /* 시각을 말하지 않는 흐름도 낸다 — 「모른다」와 「없다」는 다르고, 빼면 그 흐름이 사라진다. */\n .sort((a, b) => String(b.since ?? '').localeCompare(String(a.since ?? ''))),\n firstAttachedAt: (ref.liveCursor as any)?.firstAttachedAt ?? null\n }\n : null,\n /*\n * **다시 읽을 수 있는가** — 이 트윈이 자기 원본을 기억하고 있나(`TwinInstance.origin`).\n *\n * 없는 트윈이 실제로 있다(이 자리가 생기기 전에 만들어진 것). 그때 화면이 버튼을 그대로\n * 내면 누를 때마다 실패하고, 사용자는 무엇이 잘못됐는지 알 수 없다. 그래서 **할 수 있는지를\n * 먼저 답한다** — 못 하는 것을 못 한다고 말하는 것도 이 화면의 일이다.\n */\n origin: inst.origin ?? null,\n canResync: !!(inst.origin as any)?.kind,\n concepts,\n edges,\n /* 원본이 모르는데 관측에는 있는 것. `null` = 트윈이 실행 중이 아니어서 비교하지 못했다. */\n observedOnly,\n /*\n * 축 셋만 행이고 나머지는 문서에서 셌다는 사실. 축마다 `basis` 가 있지만 여기서도 한 번 말한다 —\n * 화면이 \"이 숫자는 무엇으로 셌나\" 를 한눈에 보여야 규모 한계가 드러난다(ADR-0032 이주 압력).\n */\n basis: {\n rows: Object.keys(ROW_BACKED),\n document: TWIN_AXES.filter((a: any) => !ROW_BACKED[a.axis]).map((a: any) => a.axis),\n /* 투영이 낡은 축 — 있으면 이 트윈은 인제스트를 한 번 더 태워야 한다. */\n stale: concepts.filter((c: any) => c.stale).map((c: any) => c.axis)\n }\n }\n }\n /**\n * **이 트윈에 무엇을 선언할 수 있나** — 값을 넣는 화면이 도메인의 모양을 알지 않게.\n *\n * 커널이 정한 명세(속성 id·단위·범위·설명)를 그대로 낸다. 화면이 「에너지 트윈이면 계약전력·요금\n * 단가…」를 알고 있으면 도메인이 늘 때마다 화면을 고쳐야 하고 단위가 두 곳에 적힌다(ADR-0031).\n *\n * 지금 무엇이 선언돼 있는지도 함께 낸다(`declared`) — 화면이 두 번 묻지 않게, 그리고 「원천이 말한\n * 값」과 「우리가 정한 값」을 한자리에서 견줄 수 있게(`PropertySource`, ADR-0034).\n *\n * 어휘가 없는 종류는 `properties: []` 다 — 「아직 없다」와 「아무 값이나 받는다」는 다르다.\n */\n @Query(returns => ScalarObject, {\n nullable: true,\n description:\n \"What can be declared on this twin and what already is: the kernel's property specification (id, unit, range, note) plus the current local declarations at both scopes — this twin and its facility — each with the value it overrode. Empty properties mean this kind has no declaration vocabulary yet — not that anything goes.\"\n })\n async twinDeclarations(@Arg('instanceId') instanceId: string, @Ctx() context: ResolverContext): Promise<any | null> {\n const domainId = context.state.domain.id\n const inst = await getRepository(TwinInstance).findOne({ where: { domain: { id: domainId }, instanceId } })\n if (!inst) return null\n const model = (inst.model ?? {}) as any\n /*\n * 겹이 둘이다 — **현장의 것과 이 트윈의 것**. 화면이 둘을 함께 봐야 「이 값이 어느 범위의 것인가」를\n * 말할 수 있고, 철회 버튼이 어느 겹을 겨눌지 고를 수 있다(요금을 현장에 넣었는데 트윈에서 철회하려\n * 하면 「겹에 없다」로 끝난다 — 사용자는 이유를 알 수 없다).\n */\n const space = inst.spaceId\n ? await getRepository(TwinSpace).findOne({ where: { domain: { id: domainId }, spaceId: inst.spaceId } })\n : null\n /*\n * 돌고 있으면 커널이 「무엇으로 돌고 있나」를 스스로 답한다. 그 보고는 **작업이 새로 생길 때** 채워지\n * 므로 재기동 직후에는 비는데, 이력에서 배운 종류는 그때도 남아 있다(실측으로 이 빈칸에 부딪혔다).\n */\n const operations = operationBasis(\n model,\n TwinEngine.kernel(domainId, instanceId),\n await TwinEngine.measuredOperationKinds(domainId, instanceId)\n )\n return {\n instanceId,\n kind: inst.kind,\n spaceId: inst.spaceId,\n spaceName: space?.name,\n properties: declarablePropertySpecs(inst.kind),\n declared: (inst.localDeclarations ?? []) as any[],\n declaredAtSpace: (space?.localDeclarations ?? []) as any[],\n /* 어디에 얹을 수 있나 — 모델의 자리·설비·공정. 화면이 대상을 지어내지 않게 목록으로 준다. */\n targets: [\n ...(model.locations ?? []).map((l: any) => ({ target: 'location', id: l.id, name: l.name, type: l.type, properties: l.properties ?? [] })),\n ...(readBoardEquipment(model) ?? []).map((e: any) => ({ target: 'equipment', id: e.id, name: e.name, type: e.type ?? e.kind, properties: e.properties ?? [] })),\n /*\n * 공정은 **자원이 아니다** — 값은 종류에 붙고, 그 종류에 명세 행이 없어도 된다(창고·야드에는 행이\n * 0개다). 그래서 대상 목록을 커널의 자기보고까지 합쳐 만든다(`operationBasis`).\n *\n * 지금 값은 **겹에서** 든다(사용자가 넣은 수와 단위 그대로). 모델에는 ISO 8601 로 구워지지만\n * 화면에 「PT240S」를 보이면 자기가 넣은 값인지 알아볼 수 없다.\n */\n ...operations.map(op => ({\n target: 'operation',\n id: op.kind,\n name: op.label,\n properties: declaredDurationProperty(op.kind, inst.localDeclarations as any[], space?.localDeclarations as any[])\n }))\n ],\n /*\n * 이 트윈이 돌리는 공정과 **그 시간이 어디서 오나** — 선언 화면이 「무엇이 상수로 도나」를 보여야\n * 사람이 채울 곳을 안다. `basis` 가 비면 아직 돌지 않은 것이다(공정이 없는 것이 아니다).\n */\n operations\n }\n }\n /**\n * **이 현장에 무엇을 선언할 수 있나** — 현장 값은 트윈의 것이 아니므로 트윈 없이 묻는다.\n *\n * ── 왜 트윈으로 묻지 않나 (2026-08-18) ─────────────────────────────────────\n * 처음에는 트윈 화면에서 범위만 골라 현장 값을 넣게 했다. 그런데 **현장 값을 넣으려고 트윈을 골라야\n * 하는 것**은 개념이 거꾸로다 — 트윈은 그 값을 읽는 쪽이다(사용자가 그 어긋남을 지적했다).\n *\n * 어휘와 대상은 **그 현장 트윈들의 합집합**이다: 한 현장에 여러 종류가 살고(에너지·창고·야드), 요금은\n * 에너지 트윈만 읽는다. 합집합으로 내되 **어느 트윈이 그 대상을 가졌는지** 함께 낸다 — 아무 트윈도\n * 읽지 않는 값을 넣는 일을 화면이 미리 보여 줄 수 있어야 한다.\n */\n @Query(returns => ScalarObject, {\n nullable: true,\n description:\n 'What can be declared for a whole facility (space) and what already is: the union of the property specifications of the twin kinds living there, the union of their declarable targets (with which twins carry each), and the current facility-scope declarations.'\n })\n async spaceDeclarations(@Arg('spaceId') spaceId: string, @Ctx() context: ResolverContext): Promise<any | null> {\n const domainId = context.state.domain.id\n const space = await getRepository(TwinSpace).findOne({ where: { domain: { id: domainId }, spaceId } })\n if (!space) return null\n const twins = await getRepository(TwinInstance).find({ where: { domain: { id: domainId }, spaceId } })\n\n /* 어휘 합집합 — 같은 속성이 여러 종류에 있어도 한 번만 낸다(명세는 커널 하나에서 온다). */\n const byId = new Map<string, any>()\n for (const t of twins) for (const spec of declarablePropertySpecs(t.kind)) if (!byId.has(spec.id)) byId.set(spec.id, spec)\n\n /* 대상 합집합 — 같은 id 가 여러 트윈에 있으면 **그 트윈들을 함께** 든다(현장 값은 그 전부에 얹힌다). */\n const targets = new Map<string, { target: string; id: string; name?: string; type?: string; twins: string[] }>()\n for (const t of twins) {\n const model = (t.model ?? {}) as any\n const add = (target: 'location' | 'equipment' | 'operation', e: any) => {\n const key = `${target}:${e.id}`\n const cur = targets.get(key)\n if (cur) { cur.twins.push(t.instanceId); return }\n targets.set(key, { target, id: e.id, name: e.name, type: e.type ?? e.kind, twins: [t.instanceId] })\n }\n for (const l of model.locations ?? []) add('location', l)\n for (const e of readBoardEquipment(model) ?? []) add('equipment', e)\n /*\n * 공정도 대상이다 — 「우리 현장의 적재는 4분」은 그 현장 창고 전부가 읽어야 하는 수다. 목록은 각\n * 트윈의 것을 합집합으로 든다(돌고 있으면 커널이 스스로 답한다).\n */\n for (const op of operationBasis(\n model,\n TwinEngine.kernel(domainId, t.instanceId),\n await TwinEngine.measuredOperationKinds(domainId, t.instanceId)\n ))\n add('operation', { id: op.kind, name: op.label })\n }\n\n return {\n spaceId,\n spaceName: space.name,\n properties: [...byId.values()],\n declared: (space.localDeclarations ?? []) as any[],\n targets: [...targets.values()],\n /* 이 현장에 사는 트윈들 — 화면이 「누가 이 값을 읽나」를 말할 수 있게. */\n twins: twins.map(t => ({ instanceId: t.instanceId, kind: t.kind, name: t.name }))\n }\n }\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"twin-model-tree-query.js","sourceRoot":"","sources":["../../../server/service/twin-model/twin-model-tree-query.ts"],"names":[],"mappings":"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","sourcesContent":["import { nameIndex, namesFor } from './name-index.js'\nimport { Arg, Ctx, Int, Query, Resolver } from 'type-graphql'\n\nimport { ScalarObject, getRepository } from '@things-factory/shell'\n\nimport { TwinInstance } from '../twin-instance/twin-instance.js'\n\nconst { TWIN_RELATIONS, axisInfo } = require('@operato/ops-contract')\n\n/**\n * 재귀 전개 — **자기 축으로 돌아오는 선언을 따라간다.**\n *\n * ── 왜 자재가 자재를 품지 않는가 ───────────────────────────────────────────────\n * 다단 BOM 을 \"자재 안에 자재\" 로 적으면 같은 부품이 여러 완제품에 들어갈 때마다 복제되고,\n * 수량이 어디 붙는지도 애매해진다. 표준(ISA-95)이 택한 모양은 **자재와 레시피가 번갈아 나오는\n * 그래프**다: 완제품 ←산출— 레시피 —투입→ 부품들, 그리고 그 부품이 또 어느 레시피의 산출이면\n * 거기서 다시 내려간다. 우리 선언(`ops.rel.input`·`ops.rel.output`)이 이미 그 두 홉이다.\n *\n * ── 패턴을 코드가 알지 않는다 ──────────────────────────────────────────────────\n * \"BOM 은 산출→투입\" 이라고 적어 두면 그 순간 이 파일이 도메인을 알게 된다(ADR-0031 위반).\n * 대신 **선언 그래프에서 자기 축으로 돌아오는 두 홉 순환을 찾는다.** 자재만이 아니라 앞으로\n * 같은 모양을 갖는 어떤 축이든 그대로 펼쳐진다.\n *\n * ── 알리지 않고 고르지 않는다 ───────────────────────────────────────────────────────\n * 순환이 여럿이면 **아무거나 집지 않는다.** 후보를 돌려주고 부르는 쪽이 고르게 한다 — 한쪽을\n * 집으면 역전개(누가 나를 쓰나)를 전개(내가 무엇으로 되나)로 보여 주고도 아무도 모른다.\n */\n\n/** 자기 축으로 돌아오는 두 홉 — `axis ←down(via)— through —up(via)→ axis`. */\ninterface WalkPattern {\n /** 중간에 거치는 축(레시피 등). */\n through: string\n /** 나로 들어오는 홉 — \"나를 이것의 산출로 삼는\" 쪽. */\n inVia: string\n /** 거기서 다시 나가는 홉 — \"그것이 투입하는\" 쪽. */\n outVia: string\n inField: string\n outField: string\n}\n\n/** 선언 그래프에서 이 축으로 돌아오는 순환들을 찾는다. */\nfunction patternsFor(axis: string): WalkPattern[] {\n const toMe = TWIN_RELATIONS.filter((r: any) => r.target?.kind === 'axis' && r.target.axis === axis)\n const out: WalkPattern[] = []\n for (const a of toMe)\n for (const b of toMe)\n if (a !== b && a.from === b.from)\n out.push({ through: a.from, inVia: a.via, outVia: b.via, inField: a.field, outField: b.field })\n return out\n}\n\nconst at = (o: any, path: string) => path.split('.').reduce((a: any, k: string) => (a == null ? undefined : a[k]), o)\nconst idOf = (o: any): string | null => (typeof o === 'string' ? o : o?.id ?? o?.key ?? o?.gtin ?? null)\n\n/** `inputs[].material` — 배열을 지나는 선언 경로. 값과 **그 값을 담은 객체**를 함께 돌려준다(수량이 거기 있다). */\nfunction entriesAt(obj: any, field: string): { value: any; holder: any }[] {\n let cur: { value: any; holder: any }[] = [{ value: obj, holder: obj }]\n for (const seg of field.split('.')) {\n const key = seg.endsWith('[]') ? seg.slice(0, -2) : seg\n const next: { value: any; holder: any }[] = []\n for (const c of cur) {\n const v = c.value?.[key]\n if (v == null) continue\n if (Array.isArray(v)) for (const x of v) next.push({ value: x, holder: x })\n else next.push({ value: v, holder: c.value })\n }\n cur = next\n }\n return cur\n}\n\n/** 이 홉이 실어 나르는 수량 — 선언에 있으면 쓰고, 없으면 **없다고 한다**(1 로 메우지 않는다). */\nfunction qtyOf(holder: any): number | null {\n const q = holder?.qty ?? holder?.quantity\n return typeof q === 'number' ? q : null\n}\n\n@Resolver()\nexport class TwinModelTreeQuery {\n @Query(returns => ScalarObject, {\n nullable: true,\n description:\n 'Recursively expand an item through a declared two-hop cycle (e.g. a multi-level BOM: product ←produced-by— recipe —consumes→ parts). The pattern is derived from the kernel relation declarations, never hardcoded. Reports the pattern used, any cycles found, and whether depth or item caps truncated the walk.'\n })\n async twinModelTree(\n @Arg('instanceId') instanceId: string,\n @Arg('axis') axis: string,\n @Arg('itemId') itemId: string,\n @Ctx() context: ResolverContext,\n @Arg('inVia', { nullable: true }) inVia?: string,\n @Arg('outVia', { nullable: true }) outVia?: string,\n @Arg('maxDepth', type => Int, { nullable: true }) maxDepth?: number,\n @Arg('maxItems', type => Int, { nullable: true }) maxItems?: number\n ): Promise<any | null> {\n const domainId = context.state.domain.id\n const info = axisInfo(axis)\n if (!info) throw new Error(`unknown concept axis: \"${axis}\" — the kernel catalog does not declare it`)\n\n const inst = await getRepository(TwinInstance).findOne({ where: { domain: { id: domainId }, instanceId } })\n if (!inst) return null\n\n const all = patternsFor(axis)\n if (!all.length) return { axis, itemId, patterns: [], items: [], edges: [], reason: 'no-recursive-relation' }\n\n\n const chosen = inVia && outVia ? all.find(p => p.inVia === inVia && p.outVia === outVia) : all.length === 1 ? all[0] : undefined\n if (!chosen)\n /* 여럿인데 안 고르면 **아무것도 펼치지 않는다.** 한쪽을 집으면 역전개를 전개로 보여 주고도\n 아무도 모른다 — 방향이 뒤집힌 BOM 은 틀린 답이 아니라 반대의 답이다. */\n return { axis, itemId, patterns: all, items: [], edges: [], reason: 'ambiguous-pattern' }\n\n /*\n * ── ★ **선언에 없는 축은 펼칠 것이 없다** (2026-08-24 실측으로 터짐) ────────\n *\n * 이 전개는 **트윈 모델의 선언**을 읽는다(`axisInfo(...).path` 로 모델 안을 찾아 들어간다). 그런데\n * 커널 카탈로그의 축 중 셋은 **선언되는 것이 아니라 일어나는 것**이다 — `orders`·`tasks`·`items`\n * 는 사건이 만들고 끝나면 사라진다. 모델이 그 목록을 가질 수 없으므로 `path` 가 비어 있다.\n *\n * 그래서 그런 축을 지나려 하면 `at(model, undefined)` 에서 터졌다:\n *\n * Cannot read properties of undefined (reading 'split')\n *\n * ★ **터진 것은 요청한 축이 아니라 「거쳐 가는 축」이다.** `locations` 를 물으면 그 순환이\n * `tasks` 를 거치는데(작업이 `from`·`at` 으로 자리를 두 번 가리킨다) 그 `tasks` 에 경로가 없다.\n * 그래서 요청한 축만 지켜서는 막히지 않는다 — 둘 다 본다.\n *\n * ── 터지지 않게 하는 것만으로는 모자라다 ──────────────────────────────────\n * 빈 트리를 돌려주면 화면이 **「이어진 것이 없다」**로 읽는다. 그것은 거짓이다 — 작업은 자리를\n * 가리키고 있고, 다만 **이 질의가 그것을 아는 곳이 아니다**(그 관계는 상태와 저널이 안다).\n * 그래서 이유를 말한다. 왜 못 하는지 말하지 않는 빈 화면이 이 저장소가 반복해 고친 결함이다.\n */\n if (!info.path || !axisInfo(chosen.through)?.path)\n return { axis, itemId, patterns: all, items: [], edges: [], reason: 'not-declared-in-model' }\n\n const model = inst.model ?? {}\n const throughInfo = axisInfo(chosen.through)\n const listOf = (i: any) => {\n const raw = i ? at(model, i.path) : undefined\n return Array.isArray(raw) ? raw : raw ? [raw] : []\n }\n const throughAll = listOf(throughInfo)\n const mineAll = listOf(info)\n const mineIds = new Set(mineAll.map(idOf).filter(Boolean) as string[])\n\n const depthCap = Math.min(Math.max(maxDepth ?? 6, 1), 12)\n const itemCap = Math.min(Math.max(maxItems ?? 200, 1), 2000)\n\n const items: any[] = [{ id: itemId, axis, depth: 0, qty: 1, known: mineIds.has(itemId) }]\n const edges: any[] = []\n const seen = new Set<string>([itemId])\n const cycles: string[] = []\n let depthTruncated = false\n let itemTruncated = false\n\n /* 너비 우선 — 깊이 상한에서 끊기면 **얕은 층은 온전히** 남는다(깊이 우선이면 한 가지만 깊게 파고 끊긴다). */\n let frontier: { id: string; depth: number; qty: number | null }[] = [{ id: itemId, depth: 0, qty: 1 }]\n while (frontier.length) {\n const nextFrontier: typeof frontier = []\n for (const cur of frontier) {\n if (cur.depth >= depthCap) { depthTruncated = true; continue }\n /* 나를 만들어 내는 중간 항목들(레시피)을 찾는다 — 선언된 홉을 따라. */\n for (const t of throughAll) {\n const producesMe = entriesAt(t, chosen.inField).some(e => String(idOf(e.value) ?? e.value) === cur.id)\n if (!producesMe) continue\n for (const e of entriesAt(t, chosen.outField)) {\n const childId = String(idOf(e.value) ?? e.value)\n const step = qtyOf(e.holder)\n /* 수량을 모르면 **곱하지 않는다.** 1 로 메우면 \"1개 필요\" 라는 사실 주장이 되고,\n 윗단에서 곱해진 값이 전부 거짓이 된다. */\n const qty = cur.qty != null && step != null ? cur.qty * step : null\n edges.push({ from: cur.id, to: childId, through: idOf(t), depth: cur.depth + 1, step, qty })\n\n if (seen.has(childId)) {\n /* 이미 지난 항목으로 돌아왔다 — 사이클이거나 공유 부품이다. 어느 쪽이든 **다시 파지\n 않고 말한다.** 파고 들어가면 돌아 나오지 못한다. */\n if (edges.some(x => x.to === cur.id && x.from === childId)) cycles.push(`${cur.id} ↔ ${childId}`)\n continue\n }\n if (items.length >= itemCap) { itemTruncated = true; continue }\n seen.add(childId)\n items.push({ id: childId, axis, depth: cur.depth + 1, qty, known: mineIds.has(childId) })\n nextFrontier.push({ id: childId, depth: cur.depth + 1, qty })\n }\n }\n }\n frontier = nextFrontier\n }\n\n return {\n axis,\n itemId,\n /* 어떤 순환을 따라 펼쳤는지 **밝힌다** — 방향이 뒤집힌 전개는 틀린 답이 아니라 반대의 답이라\n 화면만 보고는 구별되지 않는다. */\n pattern: chosen,\n patterns: all,\n items,\n edges,\n /* 수량을 하나라도 모르면 아래 합계가 성립하지 않는다는 사실을 그대로 낸다. */\n /*\n * **이름을 함께 낸다** (2026-08-22). 나무의 줄이 id 만 보이면 사용자는 그 노드가 무엇인지 알 수\n * 없다 — 사용자의 말: 「각 노드의 식별자가 반복되어서 이해가 어렵다. 식별자와 이름이 보이면.」\n * 목록·항목 화면이 쓰는 것과 **같은 표**를 쓴다(`name-index`) — 두 벌이면 한쪽만 고쳐진다.\n */\n names: namesFor(items, nameIndex(inst.model ?? {})),\n qtyIncomplete: edges.some(e => e.step == null),\n cycles: [...new Set(cycles)],\n truncated: { depth: depthTruncated, items: itemTruncated, depthCap, itemCap },\n basis: 'document'\n }\n }\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"twin-operation.js","sourceRoot":"","sources":["../../../server/service/twin-model/twin-operation.ts"],"names":[],"mappings":"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","sourcesContent":["import { CreateDateColumn, Entity, Index, Column, RelationId, ManyToOne, PrimaryGeneratedColumn, UpdateDateColumn } from 'typeorm'\nimport { ObjectType, Field, ID, Int } from 'type-graphql'\n\nimport { Domain, ScalarObject } from '@things-factory/shell'\n\nimport { TwinInstance } from '../twin-instance/twin-instance.js'\n\n/*\n * TwinOperation — 이 트윈이 반영하는 **공정 명세**. ISA-95 `OperationsSegment`.\n * 이 현장에서 각 작업이 **어디서·무엇으로·얼마나 걸리나**(선언값).\n *\n * ── 왜 이 표가 인스펙션의 중심인가 ──────────────────────────────────────────\n * 인스펙션 화면의 존재 이유는 `선언 | 관측` 두 열이고(`plans/twin-inspection.md` §2.4),\n * 그 첫 열이 여기서 온다. 둘째 열은 저널에서 계산된다(`kpi-fold.workTime`).\n * 실적은 보이는데 기준이 안 보이면 \"절단이 5분 걸렸다\" 를 보고도 빠른지 느린지 알 수 없다.\n *\n * 자리·설비와 같은 규율 — **원본에서 온 캐시**, `sourceRef`·`ingestedAt` 필수,\n * 쓰기 경로는 인제스트 하나(`twin-location.ts` 머리말).\n */\n@Entity({ name: 'twin_operations' })\n@Index('ix_twin_operation_0', (e: TwinOperation) => [e.domain, e.instance, e.operationKey], { unique: true })\n@ObjectType({ description: 'An operation spec reflected into the twin (ISA-95 OperationsSegment): where it runs, with what, and how long the source says it takes.' })\nexport class TwinOperation {\n @PrimaryGeneratedColumn('uuid')\n @Field(type => ID)\n readonly id: string\n\n @ManyToOne(type => Domain)\n @Field(type => Domain, { nullable: true, description: 'Owning tenant domain.' })\n domain?: Domain\n\n @RelationId((e: TwinOperation) => e.domain)\n domainId?: string\n\n @ManyToOne(type => TwinInstance, { onDelete: 'CASCADE' })\n @Field(type => TwinInstance, { nullable: true, description: 'Owning twin instance.' })\n instance?: TwinInstance\n\n @RelationId((e: TwinOperation) => e.instance)\n instanceRowId?: string\n\n /** 커널 계약의 `OperationDef.key` 그대로. 라우트의 단계가 이 키로 가리킨다. */\n @Column()\n @Field({ description: 'Operation key as declared by the source (kernel OperationDef.key). Route steps reference this.' })\n operationKey: string\n\n /**\n * **사람이 부르는 이름** — 프레임워크 엔티티 규약의 `name`/`description`.\n *\n * ── 왜 이것이 빠져 있었고, 무엇이 망가졌나 ────────────────────────────────────\n * 투영이 마스터의 `name` 을 버리고 있었다. 그래서 행에는 id 만 남고, 화면은 이름을 만들 재료가\n * 없어 `cut-station` 을 그대로 찍었다 — 그 결함이 목록·표·관계 그림마다 따로 나타나서 표면을\n * 하나씩 고치게 만들었다. 표면의 문제가 아니라 **행에 이름이 없던 문제**다.\n *\n * 원본이 이름을 말하지 않으면 비운다(id 를 이름으로 베끼지 않는다 — 그러면 \"이름이 있다\" 는\n * 거짓이 되고, 화면이 이름 없음을 알아볼 수 없게 된다).\n */\n @Column({ nullable: true })\n @Field({ nullable: true, description: 'Human name as declared by the source. Empty when the source does not name it (never copied from the id).' })\n name?: string\n\n @Column({ nullable: true })\n @Field({ nullable: true, description: 'Longer description when the source provides one.' })\n description?: string\n\n\n @Column({ nullable: true })\n @Field({ nullable: true, description: \"Intent: 'transport' | 'process' | 'dwell'.\" })\n intent?: string\n\n /*\n * 어디서·무엇으로 — 자리·설비의 **항목이 아니라 타입**을 가리킨다(\"절단은 cut-station 에서 수행된다\").\n * 그래서 FK 가 아니다. 화면은 이것을 \"그 타입의 자리·설비 목록\" 으로 푼다(관계 선언의 `type` 대상).\n */\n @Column({ nullable: true })\n @Field({ nullable: true, description: 'Location type this operation runs at (a catalog type key, not an item reference).' })\n locationType?: string\n\n @Column({ nullable: true })\n @Field({ nullable: true, description: 'Resource type that performs it (a catalog type key, not an item reference).' })\n resourceType?: string\n\n /**\n * 소요시간 — **ISO 8601 기간 문자열이 정본**(`PT1H10M`).\n *\n * 분으로 저장하면 `PT1H10M30S` 의 초가 사라지고 그 손실은 들어온 것이 없다. 사람이 읽을 분은\n * 화면이 곁들여 보여 주고, 못 읽는 값은 `—` 로 낸다(0 으로 채우면 \"즉시 끝나는 공정\" 이라는 거짓).\n */\n @Column({ nullable: true })\n @Field({ nullable: true, description: 'Declared duration as an ISO 8601 period (e.g. PT1H10M). The string is canonical — storing minutes would silently drop seconds.' })\n duration?: string\n\n /**\n * 변동성·파라미터(수율·셋업)는 형이 도메인마다 달라 **원형 그대로** 싣는다.\n * 여기를 컬럼으로 펴려면 커널이 그 형을 먼저 고정해야 한다 — 아직 아니다.\n */\n @Column({ type: 'simple-json', nullable: true })\n @Field(type => ScalarObject, { nullable: true, description: 'Declared variability (distribution/min/max/mode) as given by the source.' })\n variability?: any\n\n @Column({ type: 'simple-json', nullable: true })\n @Field(type => ScalarObject, { nullable: true, description: 'Declared parameters (yield, setup duration…) as given by the source.' })\n parameters?: any\n\n /**\n * **네 자원 명세 — 선언한 것만 제약이 된다.**\n *\n * ISA-95 는 한 공정이 무엇을 필요로 하는지를 넷으로 말한다: 설비(`resourceType`)·인원·자산·자재.\n * 커널도 그 넷을 그대로 본다 — 선언이 있으면 잡아야 작업이 시작되고, 없으면 그 자원을 보지 않는다.\n *\n * 이 셋이 투영에서 **떨어져 있었다.** 그래서 조회 화면의 \"원본이 말한 값\" 열에 넷 중 하나만\n * 나왔고, 사람이 필요한 공정을 보고도 **사람이 필요 없다고 결론 내게** 되어 있었다. 원본이 말한\n * 것을 화면이 말하지 않으면 그 화면은 원본을 반영하는 것이 아니다.\n *\n * 모양은 커널 계약 그대로 싣는다 — 인제스트 경계에서 모양을 바꾸면 그 자리에서 방언이 생긴다.\n */\n @Column({ type: 'simple-json', nullable: true })\n @Field(type => ScalarObject, { nullable: true, description: 'Personnel this operation requires (ISA-95 PersonnelSpecification): class + quantity. Absent means the operation runs without people.' })\n personnelSpecification?: any\n\n @Column({ type: 'simple-json', nullable: true })\n @Field(type => ScalarObject, { nullable: true, description: 'Physical assets this operation requires (ISA-95 PhysicalAssetSpecification). Absent means no asset constraint — an empty pallet is never the reason a job waits.' })\n physicalAssetSpecification?: any\n\n @Column({ type: 'simple-json', nullable: true })\n @Field(type => ScalarObject, { nullable: true, description: 'Materials this operation consumes or produces (ISA-95 MaterialSpecification). Absent means material shortage never shows up in the forecast for this step.' })\n materialSpecification?: any\n\n /** 라우트 안에서의 순서 — 라우트가 이 공정을 몇 번째로 부르나(라우트 표가 서면 그리로 옮긴다). */\n @Column({ type: 'int', nullable: true })\n @Field(type => Int, { nullable: true, description: 'Sequence within its route, when the source declares one.' })\n seq?: number\n\n /* ── 캐시라는 사실을 구조로 (ADR-0032-D) ── */\n @Column()\n @Field({ description: 'Which reference (source system) this row came from. Required.' })\n sourceRef: string\n\n /*\n * **타입 이름을 적지 않는다** (2026-08-19 Postgres 부팅 실패로 고침).\n *\n * `datetime` 은 sqlite·MySQL 의 이름이고 Postgres 는 `timestamp` 만 안다 — 거꾸로 `timestamp` 는\n * sqlite 가 모른다. **다섯 드라이버에 다 통하는 이름이 없다.** 그래서 이름 고르는 일을 TypeORM 에\n * 맡긴다(`emitDecoratorMetadata` 가 켜져 있어 `Date` 에서 드라이버별 타입을 고른다).\n */\n @Column()\n @Field({ description: 'When this row was projected from the source.' })\n ingestedAt: Date\n\n @CreateDateColumn()\n @Field({ nullable: true })\n createdAt?: Date\n\n @UpdateDateColumn()\n @Field({ nullable: true })\n updatedAt?: Date\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../server/service/twin-readiness/index.ts"],"names":[],"mappings":";;;AAAA,uEAA8D;AAEjD,QAAA,SAAS,GAAG,CAAC,4CAAkB,CAAC,CAAA","sourcesContent":["import { TwinReadinessQuery } from './twin-readiness-query.js'\n\nexport const resolvers = [TwinReadinessQuery]\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"twin-readiness-query.js","sourceRoot":"","sources":["../../../server/service/twin-readiness/twin-readiness-query.ts"],"names":[],"mappings":"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","sourcesContent":["import { Arg, Ctx, Query, Resolver } from 'type-graphql'\n\nimport { getRepository, ScalarObject } from '@things-factory/shell'\n\nimport { TwinEngine } from '../../engine/index.js'\nimport { assessSuite, SUITE_SPEC, type SuiteFacts } from '../../engine/integration-runner.js'\nimport { readSpecCoverage } from '../../engine/spec-coverage.js'\nimport { capabilitiesOf, getAdapter } from '../reference/reference-adapter.js'\nimport { TwinEvent } from '../twin-event/twin-event.js'\nimport { anyJournalRow, countUpTo } from '../twin-event/journal-count.js'\nimport { TwinInstance } from '../twin-instance/twin-instance.js'\nimport { TwinReference } from '../reference/twin-reference.js'\n\n/*\n * 도입 단계 — **「이 트윈은 어디까지 증명됐나」.**\n *\n * `twinIngestHealth` 와 묻는 것이 다르다: 그쪽은 「지금 현장과 맞춰지고 있나」(피드의 건강)이고,\n * 여기는 「구조·라이브·예측·폐루프 중 어디까지 **증거로** 섰나」다. 체크리스트가 아니라 판정이므로\n * 사람이 체크해서 초록으로 만들 수 없다.\n *\n * **접속 프로브는 여기서 돌리지 않는다.** 조회마다 고객 시스템을 두드리면 화면을 열 때마다 남의\n * 운영계에 부하가 간다. 그래서 `connectOk` 는 `null`(안 돌렸다)이고, 계획의 첫 칸이 접속 확인이 된다.\n */\n@Resolver()\nexport class TwinReadinessQuery {\n @Query(returns => ScalarObject, {\n nullable: true,\n description:\n 'Which adoption stage this twin has actually reached, judged from evidence rather than a checklist: structure, live, forecast, closed-loop. Each stage reports what blocks it and which signals could not be measured at all — an unmeasured signal never counts as achieved, so a half-run suite cannot claim green. Probes that do not apply to this twin (live probes on a simulation, mapping-warning probes on a template-built twin) come back as notApplicable with a reason, which is neither a pass nor a gap. `forbiddenClaims` lists the claims that must not be made yet (realtime, prediction, automatic control). The connection probe is not run here because a read query should not hit the source system on every page load, so it appears in `planned` as the next step to take. Null if the instance is not in the current domain.'\n })\n async twinAdoptionPath(@Arg('instanceId') instanceId: string, @Ctx() context: ResolverContext): Promise<any> {\n const domainId = context.state.domain.id\n if (!TwinEngine.owns(domainId, instanceId) && !(await TwinEngine.ownsRegistered(domainId, instanceId))) return null\n\n const inst = await getRepository(TwinInstance).findOne({ where: { domain: { id: domainId }, instanceId } })\n if (!inst) return null\n const ref = await getRepository(TwinReference)\n .findOne({ where: { domain: { id: domainId }, source: instanceId } })\n .catch(() => null)\n\n const mode = TwinEngine.modeOf(domainId, instanceId)\n const snapshot = TwinEngine.owns(domainId, instanceId) ? TwinEngine.snapshot(domainId, instanceId) : undefined\n const events = getRepository(TwinEvent)\n\n /*\n * 저널에서 센다 — **재시작에도 남는 자리**다. 인메모리 계기로 세면 재기동마다 0 이 되고, 그 0 이\n * 「세었는데 반출이 없었다」로 읽혀 라이브 단계를 거짓으로 막는다.\n *\n * `action` 승격 전에 기록된 행은 세어지지 않는다. 그래서 반출이 **한 건도 없고** 승격 이후 유입도\n * 없으면 `null`(모른다)로 낸다 — 옛 저널을 「반출 0건」으로 단정하지 않는다.\n */\n /*\n * **상한까지만 센다** (2026-08-22 실측). 예전에는 넷을 전부 세었고, 저널 358만 행인 트윈에서 한 번이\n * 5.32초라 이 화면 하나가 20초를 썼다. 판정에 쓰이는 것은 문턱(≥1)이므로 상한까지의 수로 충분하고,\n * 승격 여부는 **한 건만 찾으면** 답이 난다(수가 필요 없다).\n */\n const scope = { domain: { id: domainId }, instanceId }\n const journal = await countUpTo(events, scope)\n const removalCount = await countUpTo(events, { ...scope, action: 'DELETE' })\n const journalTotal = journal.count\n const removals = removalCount.count\n const anyPromoted =\n removals > 0 ||\n (await anyJournalRow(events, { ...scope, action: 'OBSERVE' })) ||\n (await anyJournalRow(events, { ...scope, action: 'ADD' }))\n\n const modelLocations = Array.isArray((inst.model as any)?.locations) ? (inst.model as any).locations.length : null\n\n const facts: SuiteFacts = {\n subject: mode === 'live' ? 'live' : mode === 'sim' ? 'sim' : 'unknown',\n fromReference: !!ref,\n adapterCapabilities: ref?.adapterType ? capabilitiesOf(getAdapter(ref.adapterType)) : [],\n connectOk: null, // 조회에서 남의 운영계를 두드리지 않는다\n /* 이 레퍼런스가 트윈을 세운 사이트 수 — 발견의 결과다(발견 자체를 다시 돌리지 않는다). */\n siteCount: ref ? ((ref.scopeSpec as any)?.produced?.length ?? null) : null,\n locationCount: snapshot?.locations?.length ?? modelLocations,\n itemCount: snapshot?.items?.length ?? null,\n lastWarningCount: ref?.lastWarningCount ?? null,\n journalTotal,\n /* 승격 이후 유입이 하나도 없으면 세지 못한 것이다 — 0 으로 단정하지 않는다. */\n removalsJournaled: anyPromoted ? removals : null,\n specCoverage: (() => {\n const c: any = snapshot ? readSpecCoverage(snapshot) : null\n if (!c?.operations?.length) return null\n const total = c.operations.length\n const declared = c.operations.filter((o: any) => o.duration === 'declared' || o.duration === 'measured').length\n return { declared, total }\n })(),\n forecastRan: null, // 예측 실행 이력을 남기는 자리가 아직 없다 — 모른다고 말한다\n feed: 'unknown'\n }\n\n const assessment = assessSuite(facts)\n return { instanceId, ...assessment, spec: SUITE_SPEC, facts }\n }\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"area-resolver.js","sourceRoot":"","sources":["../../../server/service/twin-space/area-resolver.ts"],"names":[],"mappings":";;;AA4BA,oCAmCC;AAGD,kDAQC;AA1ED;;;;;;;;;;;;;;;;GAgBG;AACH,iDAAqD;AACrD,qCAA4B;AAE5B,6EAA4H;AAC5H,wEAAgE;AAChE,mDAA2C;AAC3C,iDAAyC;AAEzC,qGAAqG;AACxF,QAAA,iBAAiB,GAAG,YAAY,CAAA;AAEtC,KAAK,UAAU,YAAY,CAChC,QAAgB,EAChB,GAAsB,EACtB,OAA+B,EAC/B,IAA4B;IAE5B,MAAM,MAAM,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;IAC5D,IAAI,CAAC,MAAM,CAAC,MAAM;QAAE,OAAO,EAAE,CAAA;IAE7B,4GAA4G;IAC5G,MAAM,IAAI,GAAG,MAAM,IAAA,qBAAa,EAAC,+BAAY,CAAC,CAAC,OAAO,CAAC;QACrD,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAS,EAAE,UAAU,EAAE,OAAO,CAAC,UAAU,EAAE;KAC3E,CAAC,CAAA;IACF,MAAM,OAAO,GAAG,IAAI,EAAE,OAAO,CAAA;IAC7B,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,IAAI,EAAE,CAAC,yBAAyB,OAAO,CAAC,UAAU,mDAAmD,CAAC,CAAA;QACtG,OAAO,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;IAClD,CAAC;IACD,MAAM,KAAK,GAAG,MAAM,IAAA,qBAAa,EAAC,yBAAS,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAS,EAAE,OAAO,EAAE,EAAE,CAAC,CAAA;IAC7G,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,IAAI,EAAE,CAAC,0BAA0B,OAAO,cAAc,OAAO,CAAC,UAAU,yBAAyB,CAAC,CAAA;QAClG,OAAO,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;IAClD,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,IAAA,qBAAa,EAAC,uBAAQ,CAAC,CAAC,IAAI,CAAC;QAC9C,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAS,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,KAAK,CAAC,EAAE,EAAS,EAAE,MAAM,EAAE,IAAA,YAAE,EAAC,MAAM,CAAC,EAAE;KAC/F,CAAC,CAAA;IACF,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,CAAA;IAElD,uGAAuG;IACvG,OAAO,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE;QACrB,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;QACzB,IAAI,CAAC,IAAI;YAAE,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAA;QACvC,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAA;IACrD,CAAC,CAAC,CAAA;AACJ,CAAC;AAED,gFAAgF;AAChF,SAAgB,mBAAmB,CAAC,IAA4B;IAC9D,IAAA,+CAAwB,EACtB;QACE,MAAM,EAAE,yBAAiB;QACzB,OAAO,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE,OAAO,EAAE,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,CAAC;KAChF,EACD,IAAI,CACL,CAAA;AACH,CAAC","sourcesContent":["/*\n * What an area id is — the host's answer for `external: 'space.area'`.\n *\n * The contract declares a location's parent as another location or, when no location has that id, an area of the\n * space (`axis-or-external`), and says the host resolves the external half. Nothing registered a resolver, so on\n * 2026-09-18 every location in the running twin showed its parent as \"no component can resolve this relation\" —\n * the areas were in this package's own table all along.\n *\n * The lookup is (domain, space, areaId), the table's own unique key: an `areaId` is unique inside a space, so a\n * tenant can hold the same id in two spaces. The space comes from the twin the relation belongs to, which is why\n * `resolve` is given the instance (external-resolver.ts `ExternalResolveContext`). Looking up by tenant alone\n * would answer another space's name as this location's parent.\n *\n * No `href`: the screen that opens an area belongs to the product app, and putting its route here would fix a\n * product screen's address in this package. With no href the screen shows the name and makes no link — that is\n * what the field is for (no dead links). A route is registered the day a screen needs it.\n */\nimport { getRepository } from '@things-factory/shell'\nimport { In } from 'typeorm'\n\nimport { registerExternalResolver, type ExternalRef, type ExternalResolveContext } from '../twin-model/external-resolver.js'\nimport { TwinInstance } from '../twin-instance/twin-instance.js'\nimport { TwinSpace } from './twin-space.js'\nimport { TwinArea } from './twin-area.js'\n\n/** The contract's word for this target. Must match `target.entity` or it attaches to no relation. */\nexport const SPACE_AREA_ENTITY = 'space.area'\n\nexport async function resolveAreas(\n domainId: string,\n ids: readonly string[],\n context: ExternalResolveContext,\n warn?: (msg: string) => void\n): Promise<ExternalRef[]> {\n const wanted = [...new Set(ids.map(String).filter(Boolean))]\n if (!wanted.length) return []\n\n /* Which space is this twin in? A twin with no space has no areas to point at — every id is then missing. */\n const inst = await getRepository(TwinInstance).findOne({\n where: { domain: { id: domainId } as any, instanceId: context.instanceId }\n })\n const spaceId = inst?.spaceId\n if (!spaceId) {\n warn?.(`[area-resolver] twin \"${context.instanceId}\" is in no space — its parent ids cannot be areas`)\n return wanted.map(id => ({ id, missing: true }))\n }\n const space = await getRepository(TwinSpace).findOne({ where: { domain: { id: domainId } as any, spaceId } })\n if (!space) {\n warn?.(`[area-resolver] space \"${spaceId}\" of twin \"${context.instanceId}\" is not in this tenant`)\n return wanted.map(id => ({ id, missing: true }))\n }\n\n const rows = await getRepository(TwinArea).find({\n where: { domain: { id: domainId } as any, space: { id: space.id } as any, areaId: In(wanted) }\n })\n const byId = new Map(rows.map(r => [r.areaId, r]))\n\n /* An id that is in no area of this space is said to be missing — it is not dropped from the answer. */\n return wanted.map(id => {\n const area = byId.get(id)\n if (!area) return { id, missing: true }\n return area.name ? { id, name: area.name } : { id }\n })\n}\n\n/** Registered at boot, once — the same shape as the reference link resolver. */\nexport function installAreaResolver(warn?: (msg: string) => void): void {\n registerExternalResolver(\n {\n entity: SPACE_AREA_ENTITY,\n resolve: (domainId, ids, context) => resolveAreas(domainId, ids, context, warn)\n },\n warn\n )\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../server/service/twin-space/index.ts"],"names":[],"mappings":";;;AAAA,mDAA2C;AAC3C,iFAAwE;AACxE,6DAAoD;AACpD,iDAAyC;AACzC,qEAA4D;AAE/C,QAAA,QAAQ,GAAG,CAAC,yBAAS,EAAE,sDAAuB,EAAE,kCAAa,EAAE,uBAAQ,CAAC,CAAA;AACxE,QAAA,SAAS,GAAG,CAAC,0CAAiB,CAAC,CAAA","sourcesContent":["import { TwinSpace } from './twin-space.js'\nimport { TwinSpaceRepresentation } from './twin-space-representation.js'\nimport { TwinSpaceArea } from './twin-space-area.js'\nimport { TwinArea } from './twin-area.js'\nimport { TwinSpaceResolver } from './twin-space-resolver.js'\n\nexport const entities = [TwinSpace, TwinSpaceRepresentation, TwinSpaceArea, TwinArea]\nexport const resolvers = [TwinSpaceResolver]\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"move-space.js","sourceRoot":"","sources":["../../../server/service/twin-space/move-space.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;;AAkDH,gDA2FC;AA2CD,oDAsDC;AA7LD,8BAA8B;AAC9B,SAAgB,kBAAkB,CAAC,KAAqB;IACtD,MAAM,EAAE,GAAG,CAAC,KAAK,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAA;IACzC,MAAM,IAAI,GAAG,CAAC,KAAK,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAA;IAE7C,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,CAAC;QACtB,OAAO;YACL,OAAO,EAAE,EAAE,IAAI,EAAE,gBAAgB,EAAE,OAAO,EAAE,6BAA6B,EAAE;YAC3E,QAAQ,EAAE,EAAE;SACb,CAAA;IACH,CAAC;IACD,IAAI,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,aAAa,EAAE,CAAC;QAChC,OAAO;YACL,OAAO,EAAE;gBACP,IAAI,EAAE,iBAAiB;gBACvB,MAAM,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE;gBACvB,OAAO,EAAE,UAAU,EAAE,mEAAmE;aACzF;YACD,QAAQ,EAAE,EAAE;SACb,CAAA;IACH,CAAC;IACD,IAAI,IAAI,IAAI,IAAI,KAAK,EAAE,EAAE,CAAC;QACxB,OAAO;YACL,OAAO,EAAE;gBACP,IAAI,EAAE,YAAY;gBAClB,MAAM,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE;gBACvB,OAAO,EAAE,SAAS,KAAK,CAAC,UAAU,0BAA0B,EAAE,GAAG;aAClE;YACD,QAAQ,EAAE,EAAE;SACb,CAAA;IACH,CAAC;IACD;6DACyD;IACzD,IAAI,KAAK,CAAC,OAAO,KAAK,OAAO,EAAE,CAAC;QAC9B,OAAO;YACL,OAAO,EAAE;gBACP,IAAI,EAAE,YAAY;gBAClB,MAAM,EAAE,EAAE,UAAU,EAAE,KAAK,CAAC,UAAU,EAAE;gBACxC,OAAO,EAAE,SAAS,KAAK,CAAC,UAAU,kDAAkD;aACrF;YACD,QAAQ,EAAE,EAAE;SACb,CAAA;IACH,CAAC;IAED,MAAM,QAAQ,GAAuB,EAAE,CAAA;IAEvC;iEAC6D;IAC7D,MAAM,IAAI,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAA;IAC/F,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,SAAS,IAAI,EAAE,CAAC,CAAA;IAC3C,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;IACtD,IAAI,QAAQ,CAAC,MAAM,EAAE,CAAC;QACpB,QAAQ,CAAC,IAAI,CAAC;YACZ,IAAI,EAAE,mBAAmB;YACzB,MAAM,EAAE,EAAE,KAAK,EAAE,QAAQ,CAAC,MAAM,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;YAC1E,OAAO,EAAE,GAAG,QAAQ,CAAC,MAAM,8FAA8F,QAAQ;iBAC9H,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;iBACX,IAAI,CAAC,IAAI,CAAC,EAAE;SAChB,CAAC,CAAA;IACJ,CAAC;IAED,4DAA4D;IAC5D,MAAM,MAAM,GAAG,CAAC,KAAK,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAA;IAChD,MAAM,IAAI,GAAG,CAAC,KAAK,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAA;IAC5C,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;QACpB,QAAQ,CAAC,IAAI,CAAC;YACZ,IAAI,EAAE,kBAAkB;YACxB,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,IAAI,GAAG,EAAE,EAAE,EAAE,IAAI,IAAI,GAAG,EAAE;YAChD,OAAO,EAAE,2BAA2B,MAAM,IAAI,OAAO,SAAS,IAAI,IAAI,OAAO,4DAA4D;SAC1I,CAAC,CAAA;IACJ,CAAC;IAED;mEAC+D;IAC/D,IAAI,CAAC,KAAK,CAAC,uBAAuB,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC;QAC7C,QAAQ,CAAC,IAAI,CAAC;YACZ,IAAI,EAAE,6BAA6B;YACnC,MAAM,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,uBAAiC,EAAE,OAAO,EAAE,IAAI,IAAI,GAAG,EAAE;YAChF,OAAO,EAAE,GAAG,KAAK,CAAC,uBAAuB,uCAAuC,IAAI,qEAAqE;SAC1J,CAAC,CAAA;IACJ,CAAC;IAED,8DAA8D;IAC9D,IAAI,KAAK,CAAC,OAAO,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;QACrC,QAAQ,CAAC,IAAI,CAAC;YACZ,IAAI,EAAE,SAAS;YACf,MAAM,EAAE,EAAE,UAAU,EAAE,KAAK,CAAC,UAAU,EAAE;YACxC,OAAO,EAAE,SAAS,KAAK,CAAC,UAAU,gEAAgE;SACnG,CAAC,CAAA;IACJ,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,CAAA;AACrB,CAAC;AA0CD,6BAA6B;AAC7B,SAAgB,oBAAoB,CAAC,KAAuB;IAC1D,MAAM,IAAI,GAAG,CAAC,KAAK,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAA;IAE7C,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,CAAC;QACtB,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,gBAAgB,EAAE,OAAO,EAAE,6BAA6B,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAA;IACtG,CAAC;IACD,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO;YACL,OAAO,EAAE;gBACP,IAAI,EAAE,UAAU;gBAChB,MAAM,EAAE,EAAE,UAAU,EAAE,KAAK,CAAC,UAAU,EAAE;gBACxC,OAAO,EAAE,SAAS,KAAK,CAAC,UAAU,0CAA0C;aAC7E;YACD,QAAQ,EAAE,EAAE;SACb,CAAA;IACH,CAAC;IACD,0DAA0D;IAC1D,IAAI,KAAK,CAAC,OAAO,KAAK,OAAO,EAAE,CAAC;QAC9B,OAAO;YACL,OAAO,EAAE;gBACP,IAAI,EAAE,YAAY;gBAClB,MAAM,EAAE,EAAE,UAAU,EAAE,KAAK,CAAC,UAAU,EAAE;gBACxC,OAAO,EAAE,SAAS,KAAK,CAAC,UAAU,0DAA0D;aAC7F;YACD,QAAQ,EAAE,EAAE;SACb,CAAA;IACH,CAAC;IAED,MAAM,QAAQ,GAAyB;QACrC;YACE,IAAI,EAAE,UAAU;YAChB,MAAM,EAAE,EAAE,UAAU,EAAE,KAAK,CAAC,UAAU,EAAE;YACxC,OAAO,EAAE,SAAS,KAAK,CAAC,UAAU,oFAAoF;SACvH;KACF,CAAA;IAED,IAAI,CAAC,KAAK,CAAC,uBAAuB,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC;QAC7C,QAAQ,CAAC,IAAI,CAAC;YACZ,IAAI,EAAE,6BAA6B;YACnC,MAAM,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,uBAAiC,EAAE,OAAO,EAAE,IAAI,EAAE;YACzE,OAAO,EAAE,GAAG,KAAK,CAAC,uBAAuB,uCAAuC,IAAI,qEAAqE;SAC1J,CAAC,CAAA;IACJ,CAAC;IAED,MAAM,EAAE,GAAG,CAAC,KAAK,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAA;IAC5C,IAAI,EAAE,EAAE,CAAC;QACP,QAAQ,CAAC,IAAI,CAAC;YACZ,IAAI,EAAE,eAAe;YACrB,MAAM,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE;YACxB,OAAO,EAAE,2BAA2B,EAAE,0EAA0E;SACjH,CAAC,CAAA;IACJ,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,CAAA;AACrB,CAAC","sourcesContent":["/*\n * 이미 있는 트윈을 다른 현장으로 옮긴다 — **판정만**. 순수.\n *\n * ── 왜 있나 (2026-08-13) ────────────────────────────────────────────────────\n * 트윈↔현장 연결은 **만들 때만** 정할 수 있었다(템플릿 위자드·import 의 `spaceId`). 잘못 넣었거나,\n * 나중에 \"이 창고는 사실 저 공장과 같은 부지다\" 를 알게 되면 지우고 다시 만드는 것이 유일한 길이었다 —\n * 다시 만들면 그 트윈의 저널(일어난 일)이 사라진다. 고칠 수 있는 실수를 데이터 손실로 갚게 하는 설계다.\n *\n * ── 옮기는 것이 무엇을 옮기나 (엔티티 키를 보고 정했다) ──────────────────────\n * 무엇이 트윈에 매여 있고 무엇이 공간에 매여 있는지가 답을 정한다:\n *\n * · `TwinEvent` `(domain, instanceId, …)` → **따라온다.** 저널을 다시 쓰지 않는다.\n * · `TwinLocation/Equipment/Operation` `(domain, instance, …)` → **따라온다.**\n * · `TwinArea` `(domain, space, areaId)` → **남는다.** 구역은 공간의 것이다.\n * · `TwinSpaceRepresentation`(지도·이미지·보드) → **남는다.** 표현도 공간의 것이다.\n *\n * 그래서 옮기기는 이력 이전이 아니라 **소속 갱신**이다(`instance.spaceId` + `model.spaceId`).\n * 대신 공간에 매인 것들과의 연결이 끊길 수 있고, 그것을 **알리지 않고 넘기지 않는 것**이 이 모듈의 일이다.\n *\n * ── 거절과 경고를 가른다 ────────────────────────────────────────────────────\n * 거절: 되돌릴 수 없거나 뜻이 성립하지 않는 것(없는 공간·같은 공간·벤치 사본).\n * 경고: 사용자가 알고 나면 정당할 수 있는 것(구역 소속이 끊긴다·시간대가 다르다·옛 표현이 남는다).\n * 경고를 거절로 올리면 정당한 이전을 막고, 거절을 경고로 낮추면 들어온 것이 없는 사고가 된다.\n */\n\n/** 옮길 수 없는 이유 — 언어 중립 코드(발견 오류·인제스트 거절과 같은 규약). */\nexport type MoveSpaceRefusalCode = 'twin-not-found' | 'space-not-found' | 'same-space' | 'bench-copy'\n\n/** 옮겨도 되지만 알아야 하는 것 — 같은 규약. */\nexport type MoveSpaceWarningCode = 'areas-left-behind' | 'timezone-differs' | 'representations-left-behind' | 'running'\n\nexport interface MoveSpaceNote<C extends string> {\n code: C\n params?: Record<string, string | number>\n /** 영어 canonical — 로그에 남고, 번역이 없으면 그대로 보인다. */\n message: string\n}\n\nexport type MoveSpaceRefusal = MoveSpaceNote<MoveSpaceRefusalCode>\nexport type MoveSpaceWarning = MoveSpaceNote<MoveSpaceWarningCode>\n\nexport interface MoveSpaceInput {\n /** 옮길 트윈. 없으면 거절한다. */\n instanceId?: string\n /** 지금 속한 공간(없을 수 있다 — 옛 트윈). */\n fromSpaceId?: string\n /** 옮겨 갈 공간. */\n toSpaceId: string\n /** 그 공간이 이 테넌트에 실제로 있나(호출측이 조회해 넘긴다). */\n toSpaceExists: boolean\n /** 운영 트윈인가 벤치 사본인가 — 사본은 원본의 공간을 따라야 하므로 옮기지 않는다. */\n purpose?: string\n /** 지금 실행 중인가 — 시간대 변화는 재기동 뒤에 커널에 실린다. */\n running?: boolean\n /** 두 공간의 시간대(IANA). 다르면 앞으로의 시각 해석이 달라진다. */\n fromTimezone?: string\n toTimezone?: string\n /** 이 트윈의 로케이션들이 소속으로 가리키는 구역 id 들(중복 포함 가능). */\n areaRefs?: readonly (string | undefined | null)[]\n /** 옮겨 갈 공간에 있는 구역 id 들. */\n toAreaIds?: readonly string[]\n /** 옛 공간의 표현 수 — 그 표현의 폴리곤이 이 트윈을 가리키고 있었을 수 있다. */\n fromRepresentationCount?: number\n}\n\nexport interface MoveSpaceJudgement {\n /** 있으면 옮기지 않는다. */\n refusal?: MoveSpaceRefusal\n /** 옮기되 함께 알린다. 비어 있으면 잃는 것이 없다. */\n warnings: MoveSpaceWarning[]\n}\n\n/** 옮겨도 되나 — 되면 무엇을 알려야 하나. */\nexport function judgeMoveTwinSpace(input: MoveSpaceInput): MoveSpaceJudgement {\n const to = (input.toSpaceId ?? '').trim()\n const from = (input.fromSpaceId ?? '').trim()\n\n if (!input.instanceId) {\n return {\n refusal: { code: 'twin-not-found', message: 'no such twin in this tenant' },\n warnings: []\n }\n }\n if (!to || !input.toSpaceExists) {\n return {\n refusal: {\n code: 'space-not-found',\n params: { spaceId: to },\n message: `space \"${to}\" not found — cannot move a twin into a space that does not exist`\n },\n warnings: []\n }\n }\n if (from && from === to) {\n return {\n refusal: {\n code: 'same-space',\n params: { spaceId: to },\n message: `twin \"${input.instanceId}\" is already in space \"${to}\"`\n },\n warnings: []\n }\n }\n /* 벤치 사본은 \"이 공장이 이만큼 커지면\" 을 재는 사본이라 원본의 현장에 매여 있다. 옮기면 그 측정이\n 무엇의 측정인지 말할 수 없게 된다 — 사본을 옮기는 대신 원본을 옮기고 사본을 다시 뜬다. */\n if (input.purpose === 'bench') {\n return {\n refusal: {\n code: 'bench-copy',\n params: { instanceId: input.instanceId },\n message: `twin \"${input.instanceId}\" is a bench copy — move its source twin instead`\n },\n warnings: []\n }\n }\n\n const warnings: MoveSpaceWarning[] = []\n\n /* 로케이션의 구역 소속 — 구역은 공간의 것이라 새 공간에 같은 id 가 없으면 소속이 끊긴다.\n 막지는 않는다(새 공간에서 구역을 다시 그리는 것이 정상 경로다). 다만 몇 개가 끊기는지 말한다. */\n const refs = [...new Set((input.areaRefs ?? []).filter((x): x is string => !!x && !!x.trim()))]\n const have = new Set(input.toAreaIds ?? [])\n const orphaned = refs.filter(r => !have.has(r)).sort()\n if (orphaned.length) {\n warnings.push({\n code: 'areas-left-behind',\n params: { count: orphaned.length, areas: orphaned.slice(0, 5).join(', ') },\n message: `${orphaned.length} area reference(s) do not exist in the target space — those locations lose their grouping: ${orphaned\n .slice(0, 5)\n .join(', ')}`\n })\n }\n\n /* 시간대 — 공간이 정하고 커널이 분 오프셋으로 받는다. 다르면 같은 저널이 다른 시각으로 읽힌다. */\n const tzFrom = (input.fromTimezone ?? '').trim()\n const tzTo = (input.toTimezone ?? '').trim()\n if (tzFrom !== tzTo) {\n warnings.push({\n code: 'timezone-differs',\n params: { from: tzFrom || '—', to: tzTo || '—' },\n message: `time zone changes from \"${tzFrom || 'unset'}\" to \"${tzTo || 'unset'}\" — shift boundaries and day buckets will read differently`\n })\n }\n\n /* 옛 공간의 표현 — 폴리곤 바인딩이 이 트윈의 로케이션·그룹을 가리키고 있었을 수 있다. 표현은\n 공간에 남으므로, 그 화면에서 이 트윈이 사라진다. 몇 개가 남는지 말해 두면 사람이 찾아갈 수 있다. */\n if ((input.fromRepresentationCount ?? 0) > 0) {\n warnings.push({\n code: 'representations-left-behind',\n params: { count: input.fromRepresentationCount as number, spaceId: from || '—' },\n message: `${input.fromRepresentationCount} representation(s) stay with space \"${from}\" — bindings that pointed at this twin will no longer resolve there`\n })\n }\n\n /* 실행 중 — 소속은 즉시 바뀌지만 시간대는 커널을 세울 때 실린다. 시간대가 같으면 말할 것이 없다. */\n if (input.running && tzFrom !== tzTo) {\n warnings.push({\n code: 'running',\n params: { instanceId: input.instanceId },\n message: `twin \"${input.instanceId}\" is running — the new time zone applies after it is restarted`\n })\n }\n\n return { warnings }\n}\n\n/*\n * ── 현장에서 떼기 (2026-08-13) ──────────────────────────────────────────────\n *\n * 더하기·옮기기만 있으면 잘못 넣은 것을 되돌릴 수 없다. 떼기는 \"어느 현장에도 속하지 않음\" 으로\n * 되돌리는 일이고, 데이터 모델이 그 상태를 이미 허용한다(`TwinInstance.spaceId` 는 선택 컬럼).\n *\n * 떼면 무엇이 달라지나 — 옮기기와 같은 규칙이지만 **갈 곳이 없다**는 점이 다르다:\n * · 저널·로케이션·설비는 그대로 트윈에 남는다(잃는 것 없음).\n * · 구역·표현은 옛 현장에 남는다 → 그 화면에서 이 트윈이 사라진다.\n * · **볼 무대가 없어진다** — 현장 현황(지도·보드)은 현장의 표현으로 그리므로, 뗀 트윈은 목록과\n * 조회 화면에서만 보인다. 이것을 말하지 않으면 사용자는 트윈이 고장 났다고 읽는다.\n * · 시간 기준(`utcOffsetMinutes`)은 **옛 현장의 것으로 남는다.** 지우면 알리지 않고 UTC 로 읽히므로\n * 그쪽이 더 위험하다 — 남기고 그 사실을 말한다.\n */\n\n/** 뗄 수 없는 이유 — 언어 중립 코드. */\nexport type DetachSpaceRefusalCode = 'twin-not-found' | 'no-space' | 'bench-copy'\n\n/** 떼도 되지만 알아야 하는 것. */\nexport type DetachSpaceWarningCode = 'no-stage' | 'representations-left-behind' | 'timebase-kept'\n\nexport type DetachSpaceRefusal = MoveSpaceNote<DetachSpaceRefusalCode>\nexport type DetachSpaceWarning = MoveSpaceNote<DetachSpaceWarningCode>\n\nexport interface DetachSpaceInput {\n instanceId?: string\n /** 지금 속한 공간 — 없으면 뗄 것이 없다. */\n fromSpaceId?: string\n purpose?: string\n /** 옛 공간의 표현 수. */\n fromRepresentationCount?: number\n /** 옛 공간의 시간대 — 있으면 그 기준이 model 에 남는다. */\n fromTimezone?: string\n}\n\nexport interface DetachSpaceJudgement {\n refusal?: DetachSpaceRefusal\n warnings: DetachSpaceWarning[]\n}\n\n/** 떼도 되나 — 되면 무엇을 알려야 하나. */\nexport function judgeDetachTwinSpace(input: DetachSpaceInput): DetachSpaceJudgement {\n const from = (input.fromSpaceId ?? '').trim()\n\n if (!input.instanceId) {\n return { refusal: { code: 'twin-not-found', message: 'no such twin in this tenant' }, warnings: [] }\n }\n if (!from) {\n return {\n refusal: {\n code: 'no-space',\n params: { instanceId: input.instanceId },\n message: `twin \"${input.instanceId}\" is not on any site — nothing to detach`\n },\n warnings: []\n }\n }\n /* 벤치 사본은 원본의 현장을 따라야 측정이 무엇의 측정인지 말할 수 있다(옮기기와 같은 이유). */\n if (input.purpose === 'bench') {\n return {\n refusal: {\n code: 'bench-copy',\n params: { instanceId: input.instanceId },\n message: `twin \"${input.instanceId}\" is a bench copy — it must stay on the site it measures`\n },\n warnings: []\n }\n }\n\n const warnings: DetachSpaceWarning[] = [\n {\n code: 'no-stage',\n params: { instanceId: input.instanceId },\n message: `twin \"${input.instanceId}\" will have no site to be drawn on — it stays visible in lists and inspection only`\n }\n ]\n\n if ((input.fromRepresentationCount ?? 0) > 0) {\n warnings.push({\n code: 'representations-left-behind',\n params: { count: input.fromRepresentationCount as number, spaceId: from },\n message: `${input.fromRepresentationCount} representation(s) stay with space \"${from}\" — bindings that pointed at this twin will no longer resolve there`\n })\n }\n\n const tz = (input.fromTimezone ?? '').trim()\n if (tz) {\n warnings.push({\n code: 'timebase-kept',\n params: { timezone: tz },\n message: `the time base stays as \"${tz}\" (the site it came from) — clearing it would silently read times as UTC`\n })\n }\n\n return { warnings }\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"representation-role.js","sourceRoot":"","sources":["../../../server/service/twin-space/representation-role.ts"],"names":[],"mappings":";;;AAAA;;;;;;;;;;;;GAYG;AACU,QAAA,oBAAoB,GAAG,CAAC,OAAO,EAAE,SAAS,CAAU,CAAA","sourcesContent":["/*\n * 표현이 무엇을 위한 것인가 — **닫힌 목록** (2026-08-27 · 사용자 지시).\n *\n * index 표현 목록에 나온다. 비어 있으면 이것이다(흔한 쪽을 기본으로 둔다)\n * derived 다른 표현에서 열린다(팝업·드릴 대상). 목록에서는 접어 세어 보인다 — 감추지 않는다\n *\n * 열어 두면 넣는 쪽마다 다른 이름을 쓰고, 그러면 화면이 어느 이름을 목록에 넣어야 하는지 알 수 없다.\n * 늘려야 하면 이 목록에 더한다.\n *\n * ── 왜 엔티티가 아니라 이 파일인가 ──────────────────────────────────────────\n * 엔티티에는 데코레이터가 있어서 테스트가 그 파일을 읽을 수 없다(런타임의 타입 제거가 데코레이터를\n * 파싱하지 못한다). 값으로 확인해야 하는 것은 데코레이터 없는 파일에 둔다.\n */\nexport const REPRESENTATION_ROLES = ['index', 'derived'] as const\nexport type RepresentationRole = (typeof REPRESENTATION_ROLES)[number]\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"space-integrity.js","sourceRoot":"","sources":["../../../server/service/twin-space/space-integrity.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * 공간 ↔ 트윈 ↔ 가시화 정합성 — **순수**. 세 축이 서로 어긋난 자리를 찾는다.\n *\n * ── 왜 있나 (2026-08-13) ────────────────────────────────────────────────────\n * 이 셋은 서로를 id 로만 가리킨다. 참조 무결성을 DB 가 지켜 주지 않는 지점이 많다:\n * 공간·구역은 공간에 매이고, 로케이션·설비는 트윈에 매이고, 폴리곤은 **양쪽을 가리킨다.**\n * 그래서 트윈을 옮기거나 떼거나(2026-08-13 추가) 원본을 다시 읽으면, 아무 오류 없이 **가리킬 것이\n * 없는 도형**과 **소속 없는 로케이션**이 남는다. 증상은 \"지도가 비었다\" 뿐이고 원인은 화면에 없다.\n *\n * 그 어긋남을 사람이 눈으로 맞추고 있었다(spaceId 를 목록에서 대조). 기계가 대신 본다.\n *\n * ── 무엇을 사실로 보나 ─────────────────────────────────────────────────────\n * 판정은 **조회 결과만** 받는다(DB 를 물지 않는다). 그래서 단위테스트로 전부 부를 수 있고, 호출측은\n * 사실을 모으는 일만 한다. 각 발견은 언어 중립 코드 + 파라미터이고, 화면이 사람 말을 만든다.\n *\n * ── 심각도를 가른다 ────────────────────────────────────────────────────────\n * `broken` 은 무언가 이미 보이지 않는 상태다(가리킬 대상이 없다). `warn` 은 아직 보이지만 뜻이\n * 흐려진 상태다(소속 없음·대표 없음). 섞으면 사람이 무엇을 먼저 볼지 정할 수 없다.\n */\n\nexport type SpaceIntegrityCode =\n /** 트윈이 없는 공간을 가리킨다 — 그 트윈은 무대가 사라졌다. */\n | 'twin-space-missing'\n /** 레지스트리와 model 의 공간이 다르다 — 어느 쪽이 사실인지 알 수 없다. */\n | 'twin-space-mismatch'\n /** 폴리곤이 이 공간에 없는 구역을 가리킨다. */\n | 'polygon-area-missing'\n /** 폴리곤이 이 공간에 사는 어느 트윈에도 없는 로케이션·설비를 가리킨다. */\n | 'polygon-target-missing'\n /** 로케이션이 이 공간에 없는 구역에 소속되어 있다. */\n | 'location-area-missing'\n /** 대표 표현이 이 공간의 표현이 아니다. */\n | 'primary-representation-missing'\n /** 보드 표현이 보드를 가리키지 않는다(또는 없는 보드를 가리킨다). */\n | 'board-representation-unbound'\n /** 표현이 하나도 없는 공간에 트윈이 산다 — 볼 화면이 없다. */\n | 'space-without-representation'\n /** 어느 공간에도 속하지 않은 트윈 — 뗀 결과일 수 있다(사실이면 정상). */\n | 'twin-without-space'\n /**\n * 이 트윈이 **담을 줄 모르는 어휘**를 받고 있다 — 리비전은 오르는데 상태가 채워지지 않는다.\n *\n * 커널은 모르는 `eventType` 을 버리고(전방 호환) 종류별로 센다(`state.unhandled`). 그 수가 0이\n * 아니면 둘 중 하나다: 커넥터가 엉뚱한 트윈에 붙었거나(예: `energy.*` 가 창고 트윈으로), 커널이\n * 낡아 새 어휘를 모른다. 둘 다 사람이 손봐야 하는 것이고, 알리지 않고 두면 「정상인데 빈」 트윈이 된다.\n */\n | 'twin-unhandled-vocabulary'\n\nexport type SpaceIntegritySeverity = 'broken' | 'warn'\n\nexport interface SpaceIntegrityFinding {\n code: SpaceIntegrityCode\n severity: SpaceIntegritySeverity\n /** 어디의 문제인가 — 화면이 그 자리로 데려갈 수 있게. */\n spaceId?: string\n instanceId?: string\n representationId?: string\n params?: Record<string, string | number>\n /** 영어 canonical — 로그·폴백. */\n message: string\n}\n\n/* ── 입력(조회 결과) ──────────────────────────────────────────────────────── */\n\nexport interface IntegritySpace {\n spaceId: string\n primaryRepresentationId?: string | null\n}\n\nexport interface IntegrityInstance {\n instanceId: string\n /** 레지스트리 컬럼. */\n spaceId?: string | null\n /** 저장된 model 의 공간 — 레지스트리와 같아야 한다. */\n modelSpaceId?: string | null\n purpose?: string | null\n /** 이 트윈의 로케이션 id 들. */\n locationIds?: readonly string[]\n /** 이 트윈의 설비 id 들. */\n equipmentIds?: readonly string[]\n /** 로케이션의 소속 구역 id 들(중복 가능). */\n areaRefs?: readonly (string | undefined | null)[]\n /**\n * 커널이 담을 줄 몰라 버린 사건들 — 실행 중인 트윈의 상태에서 온다(`state.unhandled`).\n *\n * 정지한 트윈에서는 알 수 없으므로 `undefined` 다 — **없는 것과 모르는 것을 구별한다**(빈 배열을\n * 넣으면 「받은 것이 없다」는 사실 주장이 되고, 그것은 우리가 확인한 바가 아니다).\n */\n unhandled?: readonly { eventType: string; count: number }[]\n}\n\nexport interface IntegrityRepresentation {\n id: string\n spaceId: string\n type: string\n /** 보드 표현이면 보드 id. */\n boardId?: string | null\n /** 폴리곤 바인딩들. */\n polygons?: readonly IntegrityPolygon[]\n}\n\nexport interface IntegrityPolygon {\n id?: string\n /** 논리 구역 바인딩(그룹). */\n groupId?: string | null\n /** 개체 바인딩 — 로케이션 또는 설비. */\n targetKind?: 'location' | 'equipment' | null\n targetId?: string | null\n}\n\nexport interface SpaceIntegrityInput {\n spaces: readonly IntegritySpace[]\n instances: readonly IntegrityInstance[]\n representations: readonly IntegrityRepresentation[]\n /** 공간별 구역 id 들. */\n areasBySpace: Readonly<Record<string, readonly string[]>>\n /** 존재하는 보드 id 들 — 보드 표현이 실제 보드를 가리키는지 본다. */\n boardIds?: readonly string[]\n}\n\n/** 세 축을 맞대어 어긋난 자리를 모두 낸다. 비어 있으면 정합하다. */\nexport function checkSpaceIntegrity(input: SpaceIntegrityInput): SpaceIntegrityFinding[] {\n const out: SpaceIntegrityFinding[] = []\n const spaceIds = new Set(input.spaces.map(s => s.spaceId))\n const areasOf = (spaceId: string) => new Set(input.areasBySpace[spaceId] ?? [])\n const repsOf = (spaceId: string) => input.representations.filter(r => r.spaceId === spaceId)\n const boards = new Set(input.boardIds ?? [])\n\n /* 벤치 사본은 측정용 사본이라 이 검사의 대상이 아니다 — 사본의 공간은 잠깐 살고 지워진다. */\n const instances = input.instances.filter(i => i.purpose !== 'bench')\n\n /* ── 트윈 → 공간 ─────────────────────────────────────────────────────── */\n for (const t of instances) {\n const sid = (t.spaceId ?? '').trim()\n const msid = (t.modelSpaceId ?? '').trim()\n\n if (!sid) {\n out.push({\n code: 'twin-without-space',\n severity: 'warn',\n instanceId: t.instanceId,\n message: `twin \"${t.instanceId}\" is on no site — it has no map or board to be drawn on`\n })\n } else if (!spaceIds.has(sid)) {\n out.push({\n code: 'twin-space-missing',\n severity: 'broken',\n instanceId: t.instanceId,\n spaceId: sid,\n message: `twin \"${t.instanceId}\" points at site \"${sid}\" which does not exist`\n })\n }\n\n /* 두 곳이 어긋나면 어느 쪽이 사실인지 알 수 없다 — 보드는 model 을, 목록은 컬럼을 읽는다. */\n if (sid !== msid) {\n out.push({\n code: 'twin-space-mismatch',\n severity: 'broken',\n instanceId: t.instanceId,\n spaceId: sid || undefined,\n params: { registry: sid || '—', model: msid || '—' },\n message: `twin \"${t.instanceId}\" registry site \"${sid || 'none'}\" differs from its model site \"${msid || 'none'}\"`\n })\n }\n\n /* 로케이션의 소속 구역은 **트윈이 속한 공간**의 것이어야 한다. */\n if (sid && spaceIds.has(sid)) {\n const have = areasOf(sid)\n const refs = [...new Set((t.areaRefs ?? []).filter((x): x is string => !!x && !!x.trim()))]\n const missing = refs.filter(r => !have.has(r)).sort()\n if (missing.length) {\n out.push({\n code: 'location-area-missing',\n severity: 'warn',\n instanceId: t.instanceId,\n spaceId: sid,\n params: { count: missing.length, areas: missing.slice(0, 5).join(', ') },\n message: `${missing.length} area(s) referenced by locations of \"${t.instanceId}\" do not exist in site \"${sid}\": ${missing\n .slice(0, 5)\n .join(', ')}`\n })\n }\n }\n\n /*\n * 어휘가 맞는가 — 저널이 들어오는데 상태가 채워지지 않는 경우를 잡는다.\n *\n * `undefined` 는 「모른다」다(정지한 트윈). 세지 않는다 — 확인하지 않은 것을 정합으로도, 결함으로도\n * 세지 않는 것이 이 하네스의 규율이다.\n */\n if (t.unhandled?.length) {\n const total = t.unhandled.reduce((n, u) => n + u.count, 0)\n const kinds = [...t.unhandled].sort((a, b) => b.count - a.count)\n out.push({\n code: 'twin-unhandled-vocabulary',\n severity: 'warn',\n instanceId: t.instanceId,\n spaceId: sid || undefined,\n params: { events: total, kinds: kinds.length, types: kinds.slice(0, 3).map(u => u.eventType).join(', ') },\n message: `twin \"${t.instanceId}\" received ${total} event(s) of ${kinds.length} type(s) its kernel does not handle: ${kinds\n .slice(0, 3)\n .map(u => u.eventType)\n .join(', ')}`\n })\n }\n }\n\n /* ── 공간 → 가시화 ───────────────────────────────────────────────────── */\n for (const s of input.spaces) {\n const reps = repsOf(s.spaceId)\n const livesHere = instances.filter(t => (t.spaceId ?? '') === s.spaceId)\n\n /* 트윈이 사는데 표현이 없으면 볼 화면이 없다. 트윈이 없는 빈 현장은 정상이므로 세지 않는다. */\n if (livesHere.length && !reps.length) {\n out.push({\n code: 'space-without-representation',\n severity: 'warn',\n spaceId: s.spaceId,\n params: { twins: livesHere.length },\n message: `site \"${s.spaceId}\" has ${livesHere.length} twin(s) but no representation — there is nothing to draw them on`\n })\n }\n\n const primary = (s.primaryRepresentationId ?? '').trim()\n if (primary && !reps.some(r => r.id === primary)) {\n out.push({\n code: 'primary-representation-missing',\n severity: 'broken',\n spaceId: s.spaceId,\n params: { representationId: primary },\n message: `site \"${s.spaceId}\" points at primary representation \"${primary}\" which is not one of its representations`\n })\n }\n }\n\n /* ── 가시화 → 공간·트윈 ─────────────────────────────────────────────── */\n for (const rep of input.representations) {\n const have = areasOf(rep.spaceId)\n /* 이 공간에 사는 트윈들의 개체 id — 폴리곤이 가리킬 수 있는 전부. */\n const here = instances.filter(t => (t.spaceId ?? '') === rep.spaceId)\n const locationIds = new Set(here.flatMap(t => [...(t.locationIds ?? [])]))\n const equipmentIds = new Set(here.flatMap(t => [...(t.equipmentIds ?? [])]))\n\n if (rep.type === 'board' && !(rep.boardId && boards.has(rep.boardId))) {\n out.push({\n code: 'board-representation-unbound',\n severity: 'broken',\n spaceId: rep.spaceId,\n representationId: rep.id,\n params: { boardId: rep.boardId ?? '—' },\n message: `board representation \"${rep.id}\" of site \"${rep.spaceId}\" does not point at an existing board (${rep.boardId ?? 'none'})`\n })\n }\n\n for (const p of rep.polygons ?? []) {\n const gid = (p.groupId ?? '').trim()\n if (gid && !have.has(gid)) {\n out.push({\n code: 'polygon-area-missing',\n severity: 'broken',\n spaceId: rep.spaceId,\n representationId: rep.id,\n params: { areaId: gid, polygonId: p.id ?? '—' },\n message: `a polygon of representation \"${rep.id}\" binds area \"${gid}\" which does not exist in site \"${rep.spaceId}\"`\n })\n }\n const tid = (p.targetId ?? '').trim()\n if (tid && p.targetKind) {\n const pool = p.targetKind === 'equipment' ? equipmentIds : locationIds\n if (!pool.has(tid)) {\n out.push({\n code: 'polygon-target-missing',\n severity: 'broken',\n spaceId: rep.spaceId,\n representationId: rep.id,\n params: { kind: p.targetKind, targetId: tid, polygonId: p.id ?? '—' },\n message: `a polygon of representation \"${rep.id}\" binds ${p.targetKind} \"${tid}\", which no twin on site \"${rep.spaceId}\" has`\n })\n }\n }\n }\n }\n\n return out\n}\n\n/** 심각한 것부터 — 화면이 정렬을 다시 정하지 않게 한 곳에서 정한다. */\nexport function sortFindings(findings: readonly SpaceIntegrityFinding[]): SpaceIntegrityFinding[] {\n const rank = (s: SpaceIntegritySeverity) => (s === 'broken' ? 0 : 1)\n return [...findings].sort(\n (a, b) => rank(a.severity) - rank(b.severity) || a.code.localeCompare(b.code) || (a.spaceId ?? '').localeCompare(b.spaceId ?? '')\n )\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"twin-area.js","sourceRoot":"","sources":["../../../server/service/twin-space/twin-area.ts"],"names":[],"mappings":";;;;AAAA,qCAAkI;AAClI,+CAAoD;AAEpD,iDAA4D;AAE5D,mDAA2C;AAE3C;;;;;GAKG;AAII,IAAM,QAAQ,GAAd,MAAM,QAAQ;CA8CpB,CAAA;AA9CY,4BAAQ;AAGV;IAFR,IAAA,gCAAsB,EAAC,MAAM,CAAC;IAC9B,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,iBAAE,CAAC;;oCACC;AAInB;IAFC,IAAA,mBAAS,EAAC,IAAI,CAAC,EAAE,CAAC,cAAM,CAAC;IACzB,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,cAAM,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,uBAAuB,EAAE,CAAC;sCACvE,cAAM;wCAAA;AAGf;IADC,IAAA,oBAAU,EAAC,CAAC,CAAW,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;;0CACrB;AAIjB;IAFC,IAAA,mBAAS,EAAC,IAAI,CAAC,EAAE,CAAC,yBAAS,CAAC;IAC5B,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,yBAAS,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,eAAe,EAAE,CAAC;sCACnE,yBAAS;uCAAA;AAGjB;IADC,IAAA,oBAAU,EAAC,CAAC,CAAW,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC;;4CAClB;AAInB;IAFC,IAAA,gBAAM,GAAE;IACR,IAAA,oBAAK,EAAC,EAAE,WAAW,EAAE,qFAAqF,EAAE,CAAC;;wCAChG;AAId;IAFC,IAAA,gBAAM,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAC1B,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,YAAY,EAAE,CAAC;;sCACxC;AAIb;IAFC,IAAA,gBAAM,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAC1B,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,+CAA+C,EAAE,CAAC;;sCAC3E;AAIb;IAFC,IAAA,gBAAM,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAC1B,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,2DAA2D,EAAE,CAAC;;0CACnF;AAIjB;IAFC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,aAAa,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAC/C,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,oBAAY,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,kFAAkF,EAAE,CAAC;;wCACrI;AAIZ;IAFC,IAAA,0BAAgB,GAAE;IAClB,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;sCACd,IAAI;2CAAA;AAIhB;IAFC,IAAA,0BAAgB,GAAE;IAClB,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;sCACd,IAAI;2CAAA;mBA7CL,QAAQ;IAHpB,IAAA,gBAAM,GAAE;IACR,IAAA,eAAK,EAAC,gBAAgB,EAAE,CAAC,CAAW,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;IACzF,IAAA,yBAAU,EAAC,EAAE,WAAW,EAAE,uHAAuH,EAAE,CAAC;GACxI,QAAQ,CA8CpB","sourcesContent":["import { CreateDateColumn, Entity, Index, Column, RelationId, ManyToOne, PrimaryGeneratedColumn, UpdateDateColumn } from 'typeorm'\nimport { ObjectType, Field, ID } from 'type-graphql'\n\nimport { Domain, ScalarObject } from '@things-factory/shell'\n\nimport { TwinSpace } from './twin-space.js'\n\n/*\n * TwinArea — 공간의 **논리적 구역(계층)**. 표현 무관(ISA-95 building→floor→zone).\n * area 단일화(space #2): deprecated `TwinSpace.content.areas`(blob) 를 정규화한 영구 자리.\n * 표현별 폴리곤(`TwinSpaceArea`)은 이 논리 구역을 `areaId` 로 참조한다(P2에서 binding.groupId→areaId 전환).\n * 안전 순서: P1=신설+인제스트 dual-write(content.areas 병행 유지) → P2 소비처 전환 → P3 blob 제거.\n */\n@Entity()\n@Index('ix_twin_area_0', (e: TwinArea) => [e.domain, e.space, e.areaId], { unique: true })\n@ObjectType({ description: 'A logical (representation-agnostic) area in a space hierarchy (building/floor/zone). Polygons reference it by areaId.' })\nexport class TwinArea {\n @PrimaryGeneratedColumn('uuid')\n @Field(type => ID)\n readonly id: string\n\n @ManyToOne(type => Domain)\n @Field(type => Domain, { nullable: true, description: 'Owning tenant domain.' })\n domain?: Domain\n\n @RelationId((e: TwinArea) => e.domain)\n domainId?: string\n\n @ManyToOne(type => TwinSpace)\n @Field(type => TwinSpace, { nullable: true, description: 'Owning space.' })\n space?: TwinSpace\n\n @RelationId((e: TwinArea) => e.space)\n spaceRowId?: string\n\n @Column()\n @Field({ description: 'Stable logical area id (unique within a space). Polygons reference this via areaId.' })\n areaId: string\n\n @Column({ nullable: true })\n @Field({ nullable: true, description: 'Area name.' })\n name?: string\n\n @Column({ nullable: true })\n @Field({ nullable: true, description: 'Region type (building/floor/zone/yard/dock…).' })\n type?: string\n\n @Column({ nullable: true })\n @Field({ nullable: true, description: 'Parent logical area id (hierarchy). Root areas have none.' })\n parentId?: string\n\n @Column({ type: 'simple-json', nullable: true })\n @Field(type => ScalarObject, { nullable: true, description: 'Layout footprint hint { x, y, w, h } in design coords (representation-agnostic).' })\n layout?: any\n\n @CreateDateColumn()\n @Field({ nullable: true })\n createdAt?: Date\n\n @UpdateDateColumn()\n @Field({ nullable: true })\n updatedAt?: Date\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"twin-space-area.js","sourceRoot":"","sources":["../../../server/service/twin-space/twin-space-area.ts"],"names":[],"mappings":"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","sourcesContent":["import { CreateDateColumn, Entity, Index, Column, RelationId, ManyToOne, PrimaryGeneratedColumn, UpdateDateColumn } from 'typeorm'\nimport { ObjectType, Field, ID } from 'type-graphql'\n\nimport { Domain, ScalarObject } from '@things-factory/shell'\n\nimport { TwinSpaceRepresentation } from './twin-space-representation.js'\n\n/*\n * TwinSpaceArea — map/image 표현 위의 폴리곤 구역(design/ui/space-composition.md).\n * geometry=폴리곤(map=위경도, image=px). drillTo=클릭 시 이동할 model/표현(폴리곤→보드 모니터/시뮬 뷰).\n * binding=트윈 엔티티/데이터 태그(라이브 상태 결합). model 표현은 씬 컴포넌트가 이 역할을 대신함.\n */\n@Entity()\n@Index('ix_twin_space_area_0', (e: TwinSpaceArea) => [e.domain, e.representation])\n@ObjectType({ description: 'A polygon region on a map/image representation, linked to a model (drill-down) and bound to a twin entity.' })\nexport class TwinSpaceArea {\n @PrimaryGeneratedColumn('uuid')\n @Field(type => ID)\n readonly id: string\n\n @ManyToOne(type => Domain)\n @Field(type => Domain, { nullable: true, description: 'Owning tenant domain.' })\n domain?: Domain\n\n @RelationId((e: TwinSpaceArea) => e.domain)\n domainId?: string\n\n @ManyToOne(type => TwinSpaceRepresentation)\n @Field(type => TwinSpaceRepresentation, { nullable: true, description: 'Owning representation.' })\n representation?: TwinSpaceRepresentation\n\n @RelationId((e: TwinSpaceArea) => e.representation)\n representationId?: string\n\n @Column({ nullable: true })\n @Field({ nullable: true, description: 'Area name.' })\n name?: string\n\n @Column({ nullable: true })\n @Field({ nullable: true, description: 'Region type (building/floor/zone/yard/dock…).' })\n type?: string\n\n @Column({ type: 'simple-json', nullable: true })\n @Field(type => ScalarObject, { nullable: true, description: 'Polygon geometry { kind:\"polygon\", points:[[x,y]…] } (map=lat/lon, image=px).' })\n geometry?: any\n\n @Column({ type: 'simple-json', nullable: true })\n @Field(type => ScalarObject, { nullable: true, description: 'Drill-down target { kind:\"board\"|\"representation\"|\"space\", id } — click navigates to a model monitor/sim view.' })\n drillTo?: any\n\n @Column({ type: 'simple-json', nullable: true })\n @Field(type => ScalarObject, { nullable: true, description: 'Twin binding { locationId?|entityId?|tag? } for live state.' })\n binding?: any\n\n @Column({ type: 'simple-json', nullable: true })\n @Field(type => ScalarObject, { nullable: true, description: 'Polygon decoration { stroke, fill, fillOpacity, strokeWidth } — line/fill color and opacity.' })\n style?: any\n\n @CreateDateColumn()\n @Field({ nullable: true })\n createdAt?: Date\n\n @UpdateDateColumn()\n @Field({ nullable: true })\n updatedAt?: Date\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"twin-space-representation.js","sourceRoot":"","sources":["../../../server/service/twin-space/twin-space-representation.ts"],"names":[],"mappings":"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","sourcesContent":["import { CreateDateColumn, Entity, Index, Column, RelationId, ManyToOne, PrimaryGeneratedColumn, UpdateDateColumn } from 'typeorm'\nimport { ObjectType, Field, ID, Int } from 'type-graphql'\n\nimport { Domain, ScalarObject } from '@things-factory/shell'\n\nimport { TwinSpace } from './twin-space.js'\n\n/*\n * TwinSpaceRepresentation — 공간을 보는 한 방식(map|image|model), 복수·1개 primary(공간구성 아키텍처, design/ui/space-composition.md).\n * config(simple-json): model={boardId}(board-service 참조) / image={attachmentId|boardId,width,height} / map={center,zoom,provider}.\n * 폴리곤 영역은 TwinSpaceArea(map/image), model 표현은 씬 컴포넌트가 대신.\n */\n@Entity()\n@Index('ix_twin_space_rep_0', (e: TwinSpaceRepresentation) => [e.domain, e.space])\n@ObjectType({ description: 'A way to view a Space (map | image | model). Multiple per space, one primary.' })\nexport class TwinSpaceRepresentation {\n @PrimaryGeneratedColumn('uuid')\n @Field(type => ID)\n readonly id: string\n\n @ManyToOne(type => Domain)\n @Field(type => Domain, { nullable: true, description: 'Owning tenant domain.' })\n domain?: Domain\n\n @RelationId((e: TwinSpaceRepresentation) => e.domain)\n domainId?: string\n\n @ManyToOne(type => TwinSpace)\n @Field(type => TwinSpace, { nullable: true, description: 'Owning space.' })\n space?: TwinSpace\n\n @RelationId((e: TwinSpaceRepresentation) => e.space)\n spaceId?: string\n\n @Column()\n @Field({ description: 'Representation type: map | image | model.' })\n type: string\n\n @Column({ nullable: true })\n @Field({ nullable: true, description: 'Representation name.' })\n name?: string\n\n @Column({ type: 'int', nullable: true })\n @Field(type => Int, { nullable: true, description: 'Display order.' })\n seq?: number\n\n @Column({ nullable: true, default: false })\n @Field({ nullable: true, description: 'Whether this is the primary representation.' })\n isPrimary?: boolean\n\n /*\n * ── 묶는 이름 · 목록에 나오는지 (2026-08-27 · 사용자 지시) ──────────────────\n *\n * 표현이 많아지면 목록만으로는 관리가 안 된다는 요구다.\n *\n * `group` 을 **자유 문자열**로 둔다. 묶는 축이 현장마다 다르다(건물별·용도별·층별). 고정 목록으로\n * 두면 현장마다 맞지 않는다. 별도 표로 올리지 않는 이유는 그룹에 붙을 속성이 아직 없다는 것이고,\n * 생기면 그때 올린다.\n *\n * **그룹 자체의 순서는 컬럼으로 두지 않는다.** 그 그룹에 속한 `seq` 의 최솟값이 그 순서다 —\n * 화면이 계산한다. 컬럼을 두면 그룹 이름을 바꿀 때 두 곳을 맞춰야 한다.\n */\n @Column({ nullable: true })\n @Field({\n nullable: true,\n description:\n 'Free-form group name for arranging a long representation list. Sites group differently (by building, by purpose, by floor), so this is not a fixed vocabulary. The order of the groups themselves is not stored: it is the smallest seq within each group, computed where the list is drawn.'\n })\n group?: string\n\n /*\n * 목록에 나올 것과 다른 표현에서 열리는 것을 가른다.\n *\n * `isPrimary` 에 얹지 않는다 — 그것은 「현장 현황에 나올 하나」를 정하는 다른 질문이다. 하나의 칸이\n * 두 질문에 답하면 한쪽을 고칠 때 다른 쪽이 오류 없이 바뀐다.\n *\n * **없으면 `index` 다.** 그 값이 흔한 쪽이라 비어 있는 것을 기본으로 읽는다. 대신 값이 있을 때는\n * 아는 값이어야 한다 — 모르는 값을 그냥 두면 화면이 그것을 어느 쪽으로도 그리지 못한다.\n */\n @Column({ nullable: true })\n @Field({\n nullable: true,\n description:\n 'What this representation is for: \"index\" (default when absent — it appears in the representation list) or \"derived\" (it is opened from another representation, such as a popup or drill target, and is folded out of the list rather than hidden). Kept separate from isPrimary, which answers a different question: which single representation stands for the site.'\n })\n role?: string\n\n @Column({ type: 'simple-json', nullable: true })\n @Field(type => ScalarObject, { nullable: true, description: 'Type config: model {boardId} / image {attachmentId|boardId,width,height} / map {center,zoom,provider}.' })\n config?: any\n\n @CreateDateColumn()\n @Field({ nullable: true })\n createdAt?: Date\n\n @UpdateDateColumn()\n @Field({ nullable: true })\n updatedAt?: Date\n}\n"]}
|