Skip to content

feat: 술어 alias 시 원본 술어 기록·추적 — relation-aliases.md + provenance 역추적 (engine-free, read-only)#201

Merged
justinjoy merged 3 commits into
mainfrom
feat/provenance-alias-trace
Jul 2, 2026
Merged

feat: 술어 alias 시 원본 술어 기록·추적 — relation-aliases.md + provenance 역추적 (engine-free, read-only)#201
justinjoy merged 3 commits into
mainfrom
feat/provenance-alias-trace

Conversation

@justinjoy

Copy link
Copy Markdown
Contributor

무엇을

술어를 canonical로 alias할 때 문서의 원 술어(원본)가 무엇이었는지 기록·추적되게 합니다. 사람이 선언하는 policy/relation-aliases.md + factlog provenance의 역추적으로, canonical 조회 시 그 canonical을 이루는 모든 원 술어 행을 [surface: <원술어>] 라벨 + source + note와 함께 보여줍니다.

이슈 #188(술어 canonical-alias) 검토의 후속 — 술어 위치엔 compound term이 막혔고, alias 레이어의 하드 제약 #2("원 술어·provenance verbatim 저장 불변")를 만족하는 기록/추적 절반을 엔진 없이 먼저 구현합니다.

왜 엔진 없이 성립하나 (3-레이어 원본 보존)

  • Layer 1(원본 사실): 이미 candidates.csv에 원 술어+source가 verbatim 저장 — 무접촉.
  • Layer 2(매핑 결정): 이 PR이 추가하는 사람 선언 policy/relation-aliases.md(git-tracked·리뷰).
  • Layer 3(추적): 이 PR이 추가하는 provenance 역추적 — alias 테이블 + candidates.csv만으로 host-side 계산. canonical/3 엔진 파생 불필요.

동작 예

$ factlog provenance PMID:1 published_year 2005
  PMID:1 / 게재연도 / 2005  [surface: 게재연도]
    ← sources/a.md  [accepted, conf 0.98]   note: 2005년 게재
  PMID:1 / publication_year / 2005  [surface: publication_year]
    ← sources/b.md  [accepted, conf 0.95]   note: published 2005

커밋 (아토믹 3개)

  • feat(common): relation_aliases() parser + surface_variants() + collision guard
  • feat(provenance): trace canonical predicate back to surface variants
  • fix(common): harden relation_aliases — NFC-normalize tokens, require -> separator

설계 원칙 / 하드 불변식

테스트 / 무회귀

  • 유닛 362 passed(파서·surface_variants·collision·NFC·arrow·provenance-alias 커버), test_provenance.sh 19, golden 5/5 byte-identical.

리뷰 경위 (다단계 합의)

구현(아토믹) → 코드리뷰에서 🔴 CRITICAL NFC/NFD 불일치(macOS NFD 한글 alias 무증상 실패 — 정확히 타깃 use case)와 🟡 arrow 미검증 적발 → 구현자 수정 + 회귀 테스트 핀 고정 → **아키텍트+비평가 독립 검증 합의(CONCUR/CONCUR)**로 성립 확정.

알려진 비블로킹 후속

  • cli.py:1148-1160 동일 if/else grouping 분기 중복(behavior-neutral) — cosmetic dedup, 별도 정리.

비목표

엔진 canonical/3 파생·규칙, /factlog ask render의 canonical 병기(arity-3 query 표면 의존), 입력측 정규화, corroboration-join → 후속 슬라이스.

justinjoy added 3 commits July 1, 2026 23:12
…ion guard

Add relation_aliases(root) to parse policy/relation-aliases.md into a
{raw: canonical} dict, surface_variants(canonical, aliases) for reverse
lookup, and fail-loud collision detection (self-map, conflicting targets,
alias chains). Absent file returns {} — byte-identical for KBs without
the file. Mirrors sync_ignore_patterns() style and _assert_no_alias_collision
discipline.
When the RELATION term in `factlog provenance` is a declared canonical
(surface_variants is non-empty), expand the match to include rows stored
under any surface predicate, grouping them separately with a
[surface: <raw>] label.  When the term is itself a surface predicate,
emit a `canonical: <name>` context line.

Absent policy/relation-aliases.md -> zero aliases -> no expansion ->
output byte-identical to today (regression-guarded by two
TestProvenanceNoAliasFile tests and the full existing shell+golden suite).
@justinjoy justinjoy force-pushed the feat/provenance-alias-trace branch from c2baf75 to d5367b6 Compare July 2, 2026 02:28
@justinjoy justinjoy merged commit 9397625 into main Jul 2, 2026
3 checks passed
@justinjoy justinjoy deleted the feat/provenance-alias-trace branch July 2, 2026 02:29
justinjoy added a commit that referenced this pull request Jul 2, 2026
…ema_context

A relation query whose relation argument is a declared canonical name
(i.e. surface_variants(name, relation_aliases()) is non-empty) now
validates as engine-askable in classify_query, even though the stored
facts carry surface variants, not the canonical.

_relation_match_count is extended to count surface-variant rows when
the relation arg is a canonical name, so the validator returns QUERY_OK
(not QUERY_FACT_ABSENT) when matching rows exist under any alias.

schema_context() gains a "Canonical relation names (prefer these):"
section listing each canonical and its sorted variants; absent alias
file -> section is empty -> output is byte-identical to today.

No engine changes, no accepted.dl writes, no compile_facts changes.
Reuses existing relation_aliases()/surface_variants() (#201).
justinjoy added a commit that referenced this pull request Jul 2, 2026
…evaluate_relation

evaluate_relation now detects when the relation argument is a declared
canonical name (surface_variants non-empty) and matches fact rows whose
relation field equals the canonical OR is in the variant set.  This lets
a single canonical query (e.g. published_year) return all surface-variant
rows (게재연도, publication_year) with their real stored triples and real
provenance — no [no extraction backing] markers.

Pure query-layer change: no engine writes, no accepted.dl mutation, no
compile_facts changes.  relation_aliases/surface_variants are imported
from common (single source of truth, #201).  Absent alias file -> all
behavior byte-identical to before (opt-in no-op), pinned by a test.

Integration tests added to tests/test_ask_router.sh: canonical validate
routes engine with code=ok, evaluate returns both variant rows, render
shows real stored triples, no-alias-file behavior unchanged.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant