@jeongpd/korean-kinship 0.1.1 → 0.1.2

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/README.md CHANGED
@@ -165,8 +165,8 @@ Korean family-tree app, validated against actual usage. See
165
165
  - A dedicated sweep asserting no relation path ever resolves to an `undefined` or
166
166
  empty label, across every golden path plus a broad set of fallback-path
167
167
  combinations.
168
- - The compositional chon-cutoff rule independently re-verified against all 45
169
- spouse-containing golden entries.
168
+ - The compositional fallback's chon arithmetic (plain edge-sum, verified by hand
169
+ against a manual review) covering paths outside the golden table.
170
170
 
171
171
  CI (see badge above) runs this suite on every push, on Node 18 and 20 — the badge
172
172
  reflects the actual current state of `main`, not a claim in this README. Separately,
@@ -180,10 +180,13 @@ For the ~145 most common relationships, it is exactly a lookup table — that's
180
180
  and it's returned verbatim because it encodes real, occasionally non-obvious Korean
181
181
  usage conventions (for example: your sibling's spouse and your spouse's parents are
182
182
  conventionally given `chon: 0`, "just family," while your uncle's wife keeps your
183
- uncle's own `chon: 3` — these aren't derivable from one clean formula). For anything
184
- past that table, `resolve()` falls back to a compositional algorithm that computes
185
- 촌수 and blood/in-law class from the path directly, so arbitrarily deep or unusual
186
- relationship chains still get a sensible answer instead of an error.
183
+ uncle's own `chon: 3` — these aren't derivable from one clean formula, they're curated
184
+ per entry). For anything past that table, `resolve()` falls back to a compositional
185
+ algorithm that computes 촌수 as a plain edge sum and blood/in-law class from the path
186
+ directly it does not try to re-derive the golden table's "no number for close
187
+ in-laws" convention (an earlier version tried, and silently mis-scored real 4th-degree
188
+ relatives as chon 0), so arbitrarily deep or unusual relationship chains still get an
189
+ arithmetically correct answer instead of an error or a guessed zero.
187
190
 
188
191
  ## License
189
192
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jeongpd/korean-kinship",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Resolve any Korean family-relationship path to its correct kinship term, reverse term, and 촌수 (degree of kinship) — including in-laws and 사돈.",
5
5
  "type": "module",
6
6
  "main": "./src/index.js",
package/src/resolve.js CHANGED
@@ -24,9 +24,6 @@ function pickBySelfGender(record, selfGender) {
24
24
  export function walkPath(path) {
25
25
  let generationDelta = 0;
26
26
  let chonEdges = 0;
27
- let bloodChonSoFar = 0;
28
- let bloodChonAtFirstSpouse = null;
29
- let firstSpouseIndex = null;
30
27
  let relationClass = 'blood';
31
28
  let olderYounger = null;
32
29
  // Gender of the person the path lands on. Every primitive but `spouse` fixes it
@@ -34,7 +31,7 @@ export function walkPath(path) {
34
31
  // hops has no gendered person to anchor on).
35
32
  let terminalGender = null;
36
33
 
37
- for (const [index, id] of path.entries()) {
34
+ for (const id of path) {
38
35
  const rel = PRIMITIVES[id];
39
36
  generationDelta += rel.generationDelta;
40
37
  chonEdges += rel.edgeCost;
@@ -44,36 +41,29 @@ export function walkPath(path) {
44
41
  }
45
42
 
46
43
  if (rel.category === 'spouse') {
47
- if (firstSpouseIndex === null) {
48
- firstSpouseIndex = index;
49
- bloodChonAtFirstSpouse = bloodChonSoFar;
50
- }
51
44
  relationClass = 'inlaw';
52
45
  if (terminalGender !== null) {
53
46
  terminalGender = terminalGender === 'M' ? 'F' : 'M';
54
47
  }
55
48
  } else {
56
- bloodChonSoFar += rel.edgeCost;
57
49
  terminalGender = rel.gender;
58
50
  }
59
51
  }
60
52
 
61
- // In-law 촌수 is not the blood chon carried through. Korean puts no number on a
62
- // relation once the chain crosses into another family: any hop *after* the first
63
- // spouse hop (a second marriage link, or a blood hop taken from the spouse's own
64
- // family — 사돈 territory) reports chon 0, as does a spouse hop onto a close blood
65
- // relative (chon 2 at that point: self, child, sibling). Only a spouse hop onto a
66
- // distant blood relative with nothing after it keeps that relative's own chon
67
- // (큰아버지 3촌 큰어머니 3촌).
68
- const hopsAfterFirstSpouse = firstSpouseIndex === null
69
- ? 0
70
- : path.length - 1 - firstSpouseIndex;
71
-
72
- const chon = relationClass === 'inlaw'
73
- ? ((hopsAfterFirstSpouse > 0 || bloodChonAtFirstSpouse <= 2) ? 0 : bloodChonAtFirstSpouse)
74
- : chonEdges;
75
-
76
- return { generationDelta, relationClass, olderYounger, chon, terminalGender };
53
+ // 촌수 here is always the plain edge sum spouse hops cost nothing (부부는
54
+ // 무촌), so a spouse's blood relatives count from the spouse exactly as a
55
+ // careful speaker would by hand (배우자의 오빠의 딸의 = 0+2+1+1 = 4촌).
56
+ //
57
+ // The golden table (Tier 1) separately encodes a real but *uncomputable*
58
+ // convention: Korean omits the number entirely for a specific, curated set of
59
+ // close relations (며느리, 처남, 사돈 the golden entries with chon: 0). That
60
+ // convention does not generalize into a formula — an earlier version of this
61
+ // function tried to derive one ("zero any hop past the first spouse hop") and
62
+ // it silently mis-scored genuine 4th-degree relatives like the example above
63
+ // as chon 0. Since Tier 1 always resolves before walkPath() ever runs, this
64
+ // function doesn't need to reproduce that convention — it only has to be
65
+ // arithmetically correct for paths the golden table doesn't already cover.
66
+ return { generationDelta, relationClass, olderYounger, chon: chonEdges, terminalGender };
77
67
  }
78
68
 
79
69
  // The descriptor key deliberately omits 친가/외가/처가/시가 `side`. Detecting it