diff --git a/CHANGELOG.md b/CHANGELOG.md index 58de882..3a2bc9e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,24 @@ For the full audit trail, see `git log`. --- +## 2026-06-04 + +- **`kosmos/2.1` — `kosmos/2.0` 미뤄둔 4개 layer 전부 LANDED 기록 (minor · grammar 무변경)** — + `spec/kosmos.md` §8에 `kosmos/2.1` 항목 추가 + `SPEC VERSION` 헤더/README 뱃지를 + `2.0`→`2.1`로 lockstep 갱신. `kosmos/2.0` 항목이 "2.x minors로 deferred"라 적어둔 + ① `.limen` packed-shard 바이너리 포맷(`spec/limen.md` + `impl/limen.hexa` 코덱, 14/14 self-test) + ② merkle 트리 구성(`spec/limen.md` §3) ③ HF-dataset export(`tool/corpus_to_hf.hexa` + `docs/hf_export.md`) + ④ LSP/tree-sitter `@corpus` 인식 — 네 가지가 모두 구현 완료된 상태를 §8에 정직하게 기록. + 문법(§1–§6)은 byte-동일 — 2.0 파일 = 2.1 파일. +- **deprecated `.py` LSP `@corpus` 동기화 — byte-parity 복원.** canonical `lsp/kosmos_lsp.hexa`는 + kosmos/2.0 `@corpus` 최상위 entry를 인식하는데 deprecated `lsp/kosmos_lsp.py`(라이브 에디터 stdio + 서버)는 인식하지 못해 유효한 `@corpus` 파일을 "must contain exactly one @anchor entry"로 **오탐**하고 + 진단 문자열 5개가 drift된 상태였음. `.py`의 `validate()`/`hover()`를 `.hexa`에 맞춰 `@corpus` + top-level + nested member + corpus meta field + corpus hover까지 미러 → `lsp/PARITY_VERIFY.md` + **26/26 파일 byte-equal**(stdout+exit) 복원, `@corpus` example exit 0 확인. +- **stale `.kanchors` 참조 1건 수정.** `.kanchors`→`.limen` rename(#14)이 놓친 canonical + `lsp/kosmos_lsp.hexa` `member` hover 문자열을 `*.limen`으로 교정 (repo 전체 `kanchors` 잔존 0). + ## 2026-05-31 - **`.limen` reference codec landed** (`impl/limen.hexa`) — the pure-hexa pack/unpack diff --git a/README.md b/README.md index dba7c79..972864f 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@
-
+
@@ -135,8 +135,9 @@ interactive stdio JSON-RPC server still runs `lsp/kosmos_lsp.py`
(**DEPRECATED**, retained only because hexa 0.1.0-dispatch has no incremental
raw N-byte stdin read for LSP Content-Length framing on a live editor pipe —
see the `.hexa` header). The hexa `validate()` / `hover()` are byte-parity
-with the `.py` over 22 corpus files + 45 hover lines
-(`lsp/PARITY_VERIFY.log`).
+with the `.py` over 26 files (11 anchors + 11 fixtures + 4 examples,
+incl. the kosmos/2.0 `@corpus` example) + 45 hover lines
+(`lsp/PARITY_VERIFY.md`). Both recognise the `@corpus` top-level entry.
Verified against all clean anchors (0 errors) and broken fixtures
(`lsp/test_fixtures/`). A Claude Code plugin can wire it via `.lsp.json`:
diff --git a/lsp/PARITY_VERIFY.md b/lsp/PARITY_VERIFY.md
index c0407b5..d2ac1ed 100644
--- a/lsp/PARITY_VERIFY.md
+++ b/lsp/PARITY_VERIFY.md
@@ -1,13 +1,17 @@
================================================================================
kosmos LSP — hexa-native port PARITY VERIFICATION (G2)
================================================================================
- reference : lsp/kosmos_lsp.py (Python 3.9.6, DEPRECATED — kept for live LSP)
+ reference : lsp/kosmos_lsp.py (Python 3.x, DEPRECATED — kept for live LSP)
port : lsp/kosmos_lsp.hexa (hexa 0.1.0-dispatch — canonical --check)
- date (UTC): 2026-05-25T18:25:08Z
- git rev : 1690345 (branch migrate/anima-kosmos-assets-2026-05-25)
+ date (UTC): 2026-06-04 (re-verified after kosmos/2.0 @corpus parity sync)
+ git rev : lane/kosmos-finalize (off origin/main b329901)
method : for every file, compare `python3 lsp/kosmos_lsp.py --check F`
against `hexa run --no-sentinel lsp/kosmos_lsp.hexa --check F`
on BOTH stdout (verbatim diagnostic lines) AND exit code.
+ note : 2026-06-04 — the canonical .hexa learned the kosmos/2.0 @corpus
+ top-level entry (§5.6); the DEPRECATED .py is now synced to it so
+ both accept a @corpus file and emit identical "top-level entry
+ (@anchor or @corpus)" diagnostics. 26/26 files byte-equal.
================================================================================
── FALSIFIER 1 — clean anchors must yield 0 error (exit 0) ─────────────────────
@@ -24,17 +28,29 @@ PASS anchors/anima/knuth_095_unity.kosmos (exit=0, 0 diag)
PASS anchors/anima/knuth_100_big_bang.kosmos (exit=0, 0 diag)
── FALSIFIER 2 — deliberately broken anchors must flag + exit 1 ────────────────
-PASS broken_two_anchor.kosmos (exit=1) → "exactly one @anchor per file"
+PASS broken_two_anchor.kosmos (exit=1) → "exactly one top-level entry per file (@anchor XOR @corpus, kosmos/2.0)"
PASS broken_missing_coord.kosmos (exit=0) → hint "missing ... coord" (sev2 = no exit-fail, matches .py)
PASS broken_indent_malformed.kosmos (exit=1) → malformed @anchor + bad indent + 2 hints
-PASS broken_payload_col0.kosmos (exit=1) → "only @anchor is a column-0 entry" + no-anchor
-PASS broken_bom_crlf.kosmos (exit=1) → BOM + bad indent + malformed @payload + no-anchor
+PASS broken_payload_col0.kosmos (exit=1) → "only @anchor / @corpus are column-0 entries" + no-top-entry
+PASS broken_bom_crlf.kosmos (exit=1) → BOM + bad indent + malformed @payload + no-top-entry
(note: CRLF does NOT raise the LF diag under --check — Python text-mode
universal-newlines normalize CRLF→LF before validate(); the hexa port
replicates this in k_normalize_newlines() so --check stays byte-parity.)
── FALSIFIER 3 — diagnostic PARITY (identical stdout + exit, .py == .hexa) ──────
- 16/16 corpus files (11 clean + 5 broken) : stdout verbatim-equal AND exit-equal.
+ 16/16 fixture files (11 clean + 5 broken) : stdout verbatim-equal AND exit-equal.
+
+── FALSIFIER 4 — kosmos/2.0 @corpus top-level entry accepted by BOTH ───────────
+PASS examples/01_text_only.kosmos (exit=0) @anchor (1.x) — unchanged
+PASS examples/02_multimodal.kosmos (exit=0) @anchor (1.x) — unchanged
+PASS examples/03_anima_knuth_077_mandala… (exit=0) @anchor (1.x) — unchanged
+PASS examples/04_corpus_clm_byte.kosmos (exit=0) @corpus (2.0) — nested @anchor
+ members + member=ref shards
+ accepted; pre-sync the .py
+ false-rejected this file
+ ("must contain exactly one
+ @anchor entry"), now fixed.
+ 4/4 example files : stdout verbatim-equal AND exit-equal (.py == .hexa).
── EXTRA edge-case fixtures (regex-port faithfulness, not coincidental exit) ────
PASS edge_heredoc_edges.kosmos (exit=0) heredoc body skipped (inner @anchor not counted);
@@ -50,9 +66,11 @@ PASS edge_payload_malformed.kosmos (exit=1) `@payload := ...` (no modality) +
45/45 lines of knuth_077_mandala.kosmos : hover string verbatim-equal.
================================================================================
- RESULT: 22/22 --check files + 6/6 edge files + 45/45 hover lines → ALL PASS
- validate(text) + hover(line) + --check FILE are byte-parity with the
- reference .py. exit codes identical (error→1, hint-only/clean→0).
+ RESULT: 26/26 --check files (11 anchors + 11 fixtures + 4 examples,
+ incl. the kosmos/2.0 @corpus example) + 45/45 hover lines → ALL PASS
+ validate(text) + hover(line) + --check FILE are byte-parity between
+ the canonical .hexa and the deprecated .py. exit codes identical
+ (error→1, hint-only/clean→0).
SCOPE : stdio JSON-RPC server NOT ported — hexa 0.1.0-dispatch has no
incremental raw N-byte stdin read for Content-Length framing on a
live (never-EOF) editor pipe. See kosmos_lsp.hexa header HONEST TODO.
@@ -62,8 +80,8 @@ PASS edge_payload_malformed.kosmos (exit=1) `@payload := ...` (no modality) +
================================================================================
── reproduce ───────────────────────────────────────────────────────────────────
- for f in anchors/anima/*.kosmos lsp/test_fixtures/*.kosmos; do
+ for f in anchors/anima/*.kosmos lsp/test_fixtures/*.kosmos examples/*.kosmos; do
py=$(python3 lsp/kosmos_lsp.py --check "$f" 2>&1); pr=$?
- hx=$(/Users/ghost/.hx/bin/hexa run --no-sentinel lsp/kosmos_lsp.hexa --check "$f" 2>&1); hr=$?
+ hx=$(hexa run --no-sentinel lsp/kosmos_lsp.hexa --check "$f" 2>&1); hr=$?
[ "$py" = "$hx" ] && [ "$pr" = "$hr" ] && echo "PASS $f" || echo "FAIL $f"
done
diff --git a/lsp/kosmos_lsp.hexa b/lsp/kosmos_lsp.hexa
index df8d1ba..6403f7f 100644
--- a/lsp/kosmos_lsp.hexa
+++ b/lsp/kosmos_lsp.hexa
@@ -576,7 +576,7 @@ fn k_hover(line: string) -> string {
}
if k_starts_with(s, "anchor_level") { return "**anchor_level** — member granularity: sample | topic | 2tier (default 2tier)" }
if k_starts_with(s, "lane_mix") { return "**lane_mix** — per-lane mixing fractions, Σ = 1.0 (e.g. \"web=0.8, register=0.2\")" }
- if k_starts_with(s, "member") { return "**member** — a packed anchor-pack shard: `member = ref \"*.kanchors\" sha256=… frac=…`" }
+ if k_starts_with(s, "member") { return "**member** — a packed anchor-pack shard: `member = ref \"*.limen\" sha256=… frac=…`" }
if k_starts_with(s, "closed_corpus"){ return "**closed_corpus** — corpus integrity (Σ frac = 1.0 ∧ ∀ member sha256 verified)" }
if k_starts_with(s, "coord") { return "**coord** — anchor placement (float vector, dim ≥ 1)" }
if k_starts_with(s, "lane") { return "**lane** — partition / lane id (quoted string)" }
diff --git a/lsp/kosmos_lsp.py b/lsp/kosmos_lsp.py
index 0daafb7..a2e1a81 100755
--- a/lsp/kosmos_lsp.py
+++ b/lsp/kosmos_lsp.py
@@ -1,10 +1,20 @@
#!/usr/bin/env python3
-# kosmos-lsp — canonical LSP server for the .kosmos manifest grammar.
+# kosmos-lsp — LSP server for the .kosmos manifest grammar (DEPRECATED).
+#
+# The CANONICAL linter is the hexa-native lsp/kosmos_lsp.hexa (project.tape
+# @D k_hexa_native). This .py is retained ONLY as the live-editor stdio
+# JSON-RPC server, because hexa 0.1.0-dispatch has no incremental raw N-byte
+# stdin read for LSP Content-Length framing on a never-EOF editor pipe. The
+# `--check` (CI) path routes to the .hexa via bin/kosmos-lsp; this file backs
+# only interactive sessions. validate()/hover() are kept byte-parity with the
+# canonical .hexa (see lsp/PARITY_VERIFY.md).
+#
# Stdio JSON-RPC, zero deps (Python 3.8+). Spec-grounded diagnostics +
# hover from spec/kosmos.md. .kosmos is a superset of tape v1.2 adding
-# exactly two entry types: @anchor (exactly one per file, at top) and
-# @payload (2-space body). Required placement triple: coord/lane/radius.
-# Conservative — missing optional structure is a hint (sev 2).
+# three entry types (kosmos/2.0): @anchor / @corpus (exactly one top-level
+# entry per file, at column 0) and @payload (2-space body). Required
+# placement triple: coord/lane/radius. Conservative — missing optional
+# structure is a hint (sev 2).
#
# kosmos-lsp # speak LSP on stdin/stdout
# kosmos-lsp --check FILE # one-shot lint (exit 1 on any error)
@@ -14,6 +24,13 @@
ANCHOR = re.compile(
r'^@anchor\s+\S+\s*:=\s*".*?"\s*::\s*\S+\s*(?:\[[^\]\n]*\])?\s*$')
+# @corpus has the same header shape as @anchor (kosmos/2.0 §5.6); the kind
+# token \S+ accepts kosmos-corpus. ANCHOR_BODY matches a nested @anchor
+# member's header at any indent (validated against the column-0-stripped form).
+CORPUS = re.compile(
+ r'^@corpus\s+\S+\s*:=\s*".*?"\s*::\s*\S+\s*(?:\[[^\]\n]*\])?\s*$')
+ANCHOR_BODY = re.compile(
+ r'^@anchor\s+\S+\s*:=\s*".*?"\s*::\s*\S+\s*(?:\[[^\]\n]*\])?\s*$')
PAYLOAD = re.compile(r"^@payload\s+\S+\s*:=")
KV = re.compile(r"^\S+\s*=")
EDGES = ("<-", "->", "=>", "==", "~>", "|>", "!!",
@@ -35,7 +52,8 @@ def validate(text):
if "\r" in text:
out.append(diag(0, 0, 1, "byte-canonical: LF line endings only"))
lines = text.split("\n")
- anchors, anchor_ln = 0, -1
+ anchors, corpora, anchor_ln = 0, 0, -1
+ corpus_mode = False # True once a @corpus top-level entry is seen
seen = set()
heredoc = None
for i, raw in enumerate(lines):
@@ -48,23 +66,60 @@ def validate(text):
if t == "" or t.startswith("#"):
continue
indent = len(s) - len(s.lstrip(" "))
- if s.startswith("@anchor"):
- anchors += 1
- anchor_ln = i
- if indent:
+ if indent == 0:
+ # column-0 = the single top-level entry: @anchor XOR @corpus
+ if t.startswith("@anchor"):
+ anchors += 1
+ anchor_ln = i
+ if not ANCHOR.match(s):
+ out.append(diag(i, 0, len(s),
+ 'malformed @anchor — expected `@anchor