@operato/twin-kernel 0.8.2 → 0.8.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist-cjs/index.cjs +74 -15
  2. package/package.json +2 -2
@@ -63,7 +63,7 @@ __export(index_exports, {
63
63
  });
64
64
  module.exports = __toCommonJS(index_exports);
65
65
 
66
- // ../ops-contract/dist/capability.js
66
+ // node_modules/@operato/ops-contract/dist/capability.js
67
67
  var CAPABILITIES = {
68
68
  operable: {
69
69
  key: "operable",
@@ -198,7 +198,7 @@ function stateFieldsOf(caps) {
198
198
  return [...out];
199
199
  }
200
200
 
201
- // ../ops-contract/dist/contract.js
201
+ // node_modules/@operato/ops-contract/dist/contract.js
202
202
  var ORDER_TERMINAL_STATUS = ["completed", "cancelled"];
203
203
  function isOrderTerminal(o) {
204
204
  const status = String(o?.status ?? "").trim().toLowerCase();
@@ -218,6 +218,32 @@ function locationStatusOf(n) {
218
218
  const r = (n.occupancy ?? 0) / cap;
219
219
  return r >= 1 ? "full" : r >= LOCATION_SATURATION_NEAR ? "near-full" : "available";
220
220
  }
221
+ var DISPOSITION_DECISION = [
222
+ /** 원 규격으로 되돌린다 — 공정에 다시 들어가고, 산출물은 원 품목이다. */
223
+ "rework",
224
+ /**
225
+ * 쓸 수 있게 만들되 **원 규격은 아니다** — 공정에 다시 들어가지만 산출물이 원 품목이 아니다.
226
+ *
227
+ * `rework` 와 나눈 이유는 이름이 아니라 **효과**다. 되돌린 것과 고쳐 쓴 것은 산출물의 정체성이
228
+ * 다르고, 그것을 한 낱말로 묶으면 계보가 「원 품목을 만들었다」고 거짓을 말한다.
229
+ */
230
+ "repair",
231
+ /** 그대로 쓴다 — 공정도 정체성도 바뀌지 않는다. */
232
+ "use-as-is",
233
+ /**
234
+ * **등급을 내려 다른 품목으로 판다** — 공정에 다시 들어가지 않고, 그 자리에서 품목 정의가 바뀐다.
235
+ *
236
+ * 다른 넷과 축이 다르다. 폐기도 특채도 아니고 **자재의 품목 자체가 달라진다**(GTIN 이 바뀐다).
237
+ * 식품·철강·섬유에서 일상이다.
238
+ */
239
+ "regrade",
240
+ /** 재고에서 뺀다. */
241
+ "scrap",
242
+ /** 공급자에게 돌려보낸다 — 재고에서 빠지되 폐기와 다른 사실이다. */
243
+ "return-to-supplier",
244
+ /** 아직 정하지 않았다 — 묶어 두고 쓰지 않는다. */
245
+ "hold"
246
+ ];
221
247
  function testPassedAt(r, at) {
222
248
  if (r.result !== "pass")
223
249
  return false;
@@ -779,7 +805,7 @@ function gs1Namespaces(prefix) {
779
805
  return [`urn:epc:idpat:sgtin:${prefix}.`, `urn:epc:class:lgtin:${prefix}.`, `urn:epc:id:sgtin:${prefix}.`];
780
806
  }
781
807
 
782
- // ../ops-contract/dist/capacity.js
808
+ // node_modules/@operato/ops-contract/dist/capacity.js
783
809
  function isoDurationHours(iso2) {
784
810
  if (!iso2)
785
811
  return 0;
@@ -887,7 +913,7 @@ function analyzeCapacity(input) {
887
913
  };
888
914
  }
889
915
 
890
- // ../ops-contract/dist/wms-profile.js
916
+ // node_modules/@operato/ops-contract/dist/wms-profile.js
891
917
  var BIZSTEP = {
892
918
  receiving: "urn:epcglobal:cbv:bizstep:receiving",
893
919
  storing: "urn:epcglobal:cbv:bizstep:storing",
@@ -917,7 +943,7 @@ var WMS_TYPES = [
917
943
  { key: "packer", role: "equipment", label: "twin.type.packer", standardClass: { epcis: "object", isa95: "Equipment" }, identity: { scheme: "gs1:GIAI" }, capabilities: ["processable", "operable"] }
918
944
  ];
919
945
 
920
- // ../ops-contract/dist/yms-profile.js
946
+ // node_modules/@operato/ops-contract/dist/yms-profile.js
921
947
  var YARD_BIZSTEP = {
922
948
  arriving: "urn:epcglobal:cbv:bizstep:arriving",
923
949
  // 게이트-인
@@ -943,7 +969,7 @@ var YMS_TYPES = [
943
969
  { key: "hostler", role: "equipment", label: "twin.type.hostler", standardClass: { epcis: "object", iso55000: "Asset" }, identity: { scheme: "gs1:GIAI" }, capabilities: ["mobile", "operable"] }
944
970
  ];
945
971
 
946
- // ../ops-contract/dist/mes-profile.js
972
+ // node_modules/@operato/ops-contract/dist/mes-profile.js
947
973
  var MES_BIZSTEP = {
948
974
  receiving: "urn:epcglobal:cbv:bizstep:receiving",
949
975
  // 원자재 수령
@@ -981,7 +1007,7 @@ var MES_TYPES = [
981
1007
  { key: "assembler", role: "equipment", label: "twin.type.assembler", standardClass: { isa95: "Equipment", iso55000: "Asset" }, identity: { scheme: "gs1:GIAI" }, capabilities: ["processable", "operable"] }
982
1008
  ];
983
1009
 
984
- // ../ops-contract/dist/ems-profile.js
1010
+ // node_modules/@operato/ops-contract/dist/ems-profile.js
985
1011
  var EMS_LOCATION_TYPES = ["incoming", "feeder", "submeter-zone"];
986
1012
  var METER_DIRECTION = ["import", "export", "bidirectional"];
987
1013
  var EMS_PROPERTY = {
@@ -1302,7 +1328,7 @@ function isElectricalLocationType(type) {
1302
1328
  return EMS_LOCATION_TYPES.includes(type);
1303
1329
  }
1304
1330
 
1305
- // ../ops-contract/dist/domain-catalog.js
1331
+ // node_modules/@operato/ops-contract/dist/domain-catalog.js
1306
1332
  var locationKeys = (types) => types.filter((t) => t.role === "location").map((t) => t.key);
1307
1333
  var DOMAIN_CATALOG = {
1308
1334
  // label 은 언어 중립 i18n 키(twin.system.<code>) — 사람 언어는 표현계층이 렌더(L2).
@@ -1312,7 +1338,7 @@ var DOMAIN_CATALOG = {
1312
1338
  ems: { system: "ems", label: "twin.system.ems", types: EMS_TYPES, locationTypes: locationKeys(EMS_TYPES) }
1313
1339
  };
1314
1340
 
1315
- // ../ops-contract/dist/domain-definition.js
1341
+ // node_modules/@operato/ops-contract/dist/domain-definition.js
1316
1342
  var OP_PARAM = {
1317
1343
  /** 양품률(0..1, 무차원). 없으면 커널 기본값 — 기본값을 쓴 사실은 `specCoverage()` 가 밝힌다. */
1318
1344
  yield: "yield",
@@ -1321,7 +1347,7 @@ var OP_PARAM = {
1321
1347
  setupDuration: "setupDuration"
1322
1348
  };
1323
1349
 
1324
- // ../ops-contract/dist/energy-ingest.js
1350
+ // node_modules/@operato/ops-contract/dist/energy-ingest.js
1325
1351
  function resolveSubject(kind, localId, opts) {
1326
1352
  const declared = opts.identityOf?.(kind, localId);
1327
1353
  if (declared)
@@ -1332,7 +1358,7 @@ function periodFactId(tenantId, kind, subject, from, to) {
1332
1358
  return [tenantId, kind, subject, from, to].join("|");
1333
1359
  }
1334
1360
 
1335
- // ../ops-contract/dist/epcis.js
1361
+ // node_modules/@operato/ops-contract/dist/epcis.js
1336
1362
  var EPCIS_CONTEXT = "https://ref.gs1.org/standards/epcis/2.0.0/epcis-context.jsonld";
1337
1363
  var UTC_OFFSET = "+00:00";
1338
1364
  var DISP = {
@@ -1591,7 +1617,7 @@ function transformationEvent(p) {
1591
1617
  return e;
1592
1618
  }
1593
1619
 
1594
- // ../ops-contract/dist/iso-duration.js
1620
+ // node_modules/@operato/ops-contract/dist/iso-duration.js
1595
1621
  var RE = /^(-)?P(?:(\d+(?:\.\d+)?)W)?(?:(\d+(?:\.\d+)?)D)?(?:T(?:(\d+(?:\.\d+)?)H)?(?:(\d+(?:\.\d+)?)M)?(?:(\d+(?:\.\d+)?)S)?)?$/;
1596
1622
  function parseIsoDuration(text) {
1597
1623
  if (typeof text !== "string")
@@ -1617,7 +1643,7 @@ function parseIsoDuration(text) {
1617
1643
  return sign ? -ms2 : ms2;
1618
1644
  }
1619
1645
 
1620
- // ../ops-contract/dist/master-data.js
1646
+ // node_modules/@operato/ops-contract/dist/master-data.js
1621
1647
  function expiryFromAttributes(attrs) {
1622
1648
  return readEpochMs(attrs?.[ILMD_ATTR.expiry]);
1623
1649
  }
@@ -1634,7 +1660,7 @@ function readEpochMs(raw) {
1634
1660
  return Number.isNaN(at) ? void 0 : at;
1635
1661
  }
1636
1662
 
1637
- // ../ops-contract/dist/operational-ingest.js
1663
+ // node_modules/@operato/ops-contract/dist/operational-ingest.js
1638
1664
  var TASK_STATUS = ["created", "assigned", "in-progress", "completed"];
1639
1665
  var EQUIPMENT_STATUS = ["idle", "busy", "down"];
1640
1666
  var PERSON_STATUS = ["idle", "busy"];
@@ -1783,6 +1809,39 @@ var SPECS = {
1783
1809
  * `propertyMeasurements` 안쪽은 재검사하지 않는다 — 그 모양은 `PropertyMeasurement` 계약이고,
1784
1810
  * 여기서 두 번 지키면 두 벌이 된다(설비 `motion` 과 같은 규율).
1785
1811
  */
1812
+ /*
1813
+ * **부적합 처분** — 재고 판정을 받은 것을 어떻게 하기로 정했나.
1814
+ *
1815
+ * ── 이 통이 늦게 생긴 이유 (2026-08-30) ──────────────────────────────────
1816
+ * 사건 이름(`OP_EVENT.disposition`)과 모양(`DispositionFact`)을 먼저 만들고 **여기로 오는 길을
1817
+ * 내지 않았다.** 그래서 처분 사실을 보내면 어느 통도 아니어서 떨어진 목록에도 남지 않고 사라졌다.
1818
+ * MES 전문가가 소스를 읽다 찾았다.
1819
+ *
1820
+ * 이 파일의 위 주석이 말한 부류 그대로다 — `OP_EVENT.test` 와 `OP_EVENT.observation` 이 같은 일을
1821
+ * 겪었고 이번이 셋째다. **계약에 자리를 만드는 것과 그 자리로 가는 길을 내는 것은 다른 일이다.**
1822
+ *
1823
+ * ── 판정과 다른 사실이다 ─────────────────────────────────────────────────
1824
+ * 근거가 된 판정(`specId`)을 가리킬 수 있지만 **필수가 아니다** — 판정 없이 현장 재량으로 빼는 일이
1825
+ * 정상이다. 그래서 정체성은 처분 대상(`subjectId`)이다.
1826
+ */
1827
+ disposition: {
1828
+ eventType: OP_EVENT.disposition,
1829
+ identity: "subjectId",
1830
+ /* 무엇을 어떻게 하기로 했나 — 둘 중 하나가 없으면 그 결정은 아무 데도 붙지 못한다. */
1831
+ required: ["subjectId", "decision"],
1832
+ fields: {
1833
+ subjectId: "string",
1834
+ decision: "string",
1835
+ quantity: "number",
1836
+ uom: "string",
1837
+ specId: "string",
1838
+ decidedBy: "string",
1839
+ reason: "string",
1840
+ decidedAt: "string",
1841
+ recordTime: "string"
1842
+ },
1843
+ enums: { decision: DISPOSITION_DECISION }
1844
+ },
1786
1845
  test: {
1787
1846
  eventType: OP_EVENT.test,
1788
1847
  identity: "testableObjectId",
@@ -1842,7 +1901,7 @@ var SPECS = {
1842
1901
  }
1843
1902
  };
1844
1903
 
1845
- // ../ops-contract/dist/operations-capability.js
1904
+ // node_modules/@operato/ops-contract/dist/operations-capability.js
1846
1905
  function workingHoursBetween(calendar, fromMs, toMs, utcOffsetMinutes) {
1847
1906
  if (!(toMs > fromMs))
1848
1907
  return 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@operato/twin-kernel",
3
- "version": "0.8.2",
3
+ "version": "0.8.4",
4
4
  "type": "module",
5
5
  "description": "Twin Domain Kernel — framework-agnostic, zero-dep (domain + sim + 3-channel contract). WMS/YMS/MES, EPCIS 2.0 · ISA-95.",
6
6
  "publishConfig": {
@@ -28,6 +28,6 @@
28
28
  "test": "node --test test/*.test.ts"
29
29
  },
30
30
  "dependencies": {
31
- "@operato/ops-contract": "^0.1.0"
31
+ "@operato/ops-contract": "^0.4.0"
32
32
  }
33
33
  }