codec-cortex 0.3.2__py3-none-any.whl
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.
- codec_cortex-0.3.2.dist-info/METADATA +183 -0
- codec_cortex-0.3.2.dist-info/RECORD +81 -0
- codec_cortex-0.3.2.dist-info/WHEEL +5 -0
- codec_cortex-0.3.2.dist-info/entry_points.txt +2 -0
- codec_cortex-0.3.2.dist-info/licenses/LICENSE +21 -0
- codec_cortex-0.3.2.dist-info/scm_file_list.json +124 -0
- codec_cortex-0.3.2.dist-info/scm_version.json +8 -0
- codec_cortex-0.3.2.dist-info/top_level.txt +1 -0
- cortex/__init__.py +22 -0
- cortex/__main__.py +7 -0
- cortex/_version.py +24 -0
- cortex/cli/__init__.py +5 -0
- cortex/cli/commands/__init__.py +150 -0
- cortex/cli/commands/add.py +89 -0
- cortex/cli/commands/compile.py +31 -0
- cortex/cli/commands/delete.py +44 -0
- cortex/cli/commands/diagram.py +130 -0
- cortex/cli/commands/diff.py +135 -0
- cortex/cli/commands/doctor.py +74 -0
- cortex/cli/commands/format.py +29 -0
- cortex/cli/commands/get.py +45 -0
- cortex/cli/commands/glossary.py +98 -0
- cortex/cli/commands/list.py +44 -0
- cortex/cli/commands/micro.py +79 -0
- cortex/cli/commands/move.py +45 -0
- cortex/cli/commands/new.py +80 -0
- cortex/cli/commands/recover.py +90 -0
- cortex/cli/commands/render.py +93 -0
- cortex/cli/commands/update.py +81 -0
- cortex/cli/commands/v2_canonicalize.py +162 -0
- cortex/cli/commands/v2_compare.py +74 -0
- cortex/cli/commands/v2_convert.py +183 -0
- cortex/cli/commands/v2_explain_loss.py +97 -0
- cortex/cli/commands/v2_inspect.py +113 -0
- cortex/cli/commands/v2_roundtrip.py +104 -0
- cortex/cli/commands/v2_roundtrip_bidir.py +128 -0
- cortex/cli/commands/v2_verify_view.py +65 -0
- cortex/cli/commands/verify.py +119 -0
- cortex/cli/main.py +636 -0
- cortex/core/__init__.py +85 -0
- cortex/core/ast.py +313 -0
- cortex/core/compare.py +180 -0
- cortex/core/document_kind.py +525 -0
- cortex/core/errors.py +399 -0
- cortex/core/lexer.py +267 -0
- cortex/core/parser.py +671 -0
- cortex/core/validator.py +268 -0
- cortex/core/writer.py +249 -0
- cortex/crud/__init__.py +17 -0
- cortex/crud/mutations.py +342 -0
- cortex/crud/selectors.py +95 -0
- cortex/crud/transactions.py +213 -0
- cortex/glossary/__init__.py +21 -0
- cortex/glossary/contracts.py +37 -0
- cortex/glossary/minimal.py +94 -0
- cortex/glossary/model.py +77 -0
- cortex/glossary/resolver.py +96 -0
- cortex/hcortex/__init__.py +35 -0
- cortex/hcortex/edit_parser.py +489 -0
- cortex/hcortex/edit_renderer.py +158 -0
- cortex/hcortex/markdown_model.py +81 -0
- cortex/hcortex/profiles.py +166 -0
- cortex/hcortex/read_renderer.py +342 -0
- cortex/hcortex/recovery.py +782 -0
- cortex/py.typed +0 -0
- cortex/templates/__init__.py +8 -0
- cortex/templates/brain.py +118 -0
- cortex/templates/minimal_glossary.py +42 -0
- cortex/templates/package.py +91 -0
- cortex/templates/skill.py +91 -0
- cortex/v2/__init__.py +30 -0
- cortex/v2/diagnostics.py +57 -0
- cortex/v2/encoder.py +1106 -0
- cortex/v2/equivalence.py +323 -0
- cortex/v2/hcortex_parser.py +615 -0
- cortex/v2/hcortex_renderer.py +450 -0
- cortex/v2/ir.py +223 -0
- cortex/v2/parser.py +655 -0
- cortex/v2/view.py +425 -0
- cortex/v2/view_renderer.py +474 -0
- cortex/v2/writer.py +301 -0
cortex/py.typed
ADDED
|
File without changes
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"""Template factories for new ``.cortex`` documents."""
|
|
2
|
+
|
|
3
|
+
from .minimal_glossary import build_minimal_glossary
|
|
4
|
+
from .brain import build_brain
|
|
5
|
+
from .skill import build_skill
|
|
6
|
+
from .package import build_package
|
|
7
|
+
|
|
8
|
+
__all__ = ["build_minimal_glossary", "build_brain", "build_skill", "build_package"]
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"""``brain.cortex`` template factory.
|
|
2
|
+
|
|
3
|
+
Builds a Nivel 2 operative brain with:
|
|
4
|
+
- $0: minimal local glossary (autocontención)
|
|
5
|
+
- $1: IDENTITY (IDN:agent, IDN:human, DOM:workspace)
|
|
6
|
+
- $2: ACTIVE WORK (FCS:primary, OBJ:main, WRK:state, STP:next)
|
|
7
|
+
- $3: GOVERNANCE (CNST:self_contained)
|
|
8
|
+
|
|
9
|
+
Mirrors Section 18.2 of SKILL.md.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
from ..core.ast import CortexDocument, Section
|
|
16
|
+
from ..core.parser import build_entry_from_value
|
|
17
|
+
from ..glossary.minimal import brain_sigils
|
|
18
|
+
from .minimal_glossary import build_minimal_glossary
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def build_brain(
|
|
22
|
+
name: str = "project-brain",
|
|
23
|
+
domain: str = "active work",
|
|
24
|
+
owner: str = "agent",
|
|
25
|
+
language: str = "en",
|
|
26
|
+
template: str = "standard",
|
|
27
|
+
with_diagrams: bool = False,
|
|
28
|
+
) -> CortexDocument:
|
|
29
|
+
"""Return a fresh ``brain.cortex`` :class:`CortexDocument`."""
|
|
30
|
+
|
|
31
|
+
doc = CortexDocument()
|
|
32
|
+
doc.meta = {
|
|
33
|
+
"path": "<template:brain>",
|
|
34
|
+
"format": ".cortex",
|
|
35
|
+
"version": "1.0.0",
|
|
36
|
+
"hash": "",
|
|
37
|
+
}
|
|
38
|
+
doc.glossary = build_minimal_glossary(brain_sigils())
|
|
39
|
+
|
|
40
|
+
# $0 section (will be serialised from the glossary at write-time)
|
|
41
|
+
sec0 = Section(id="$0", title="MINIMAL LOCAL GLOSSARY")
|
|
42
|
+
doc.sections.append(sec0)
|
|
43
|
+
|
|
44
|
+
# $1 IDENTITY
|
|
45
|
+
sec1 = Section(id="$1", title="IDENTITY")
|
|
46
|
+
sec1.entries.append(build_entry_from_value(
|
|
47
|
+
"$1", "IDN", "agent", "attrs",
|
|
48
|
+
{"name": name, "role": "operator"},
|
|
49
|
+
))
|
|
50
|
+
sec1.entries.append(build_entry_from_value(
|
|
51
|
+
"$1", "IDN", "human", "attrs",
|
|
52
|
+
{"name": "human", "role": "architect"},
|
|
53
|
+
))
|
|
54
|
+
sec1.entries.append(build_entry_from_value(
|
|
55
|
+
"$1", "DOM", "workspace", "attrs",
|
|
56
|
+
{"area": domain, "protocol": "CODEC-CORTEX", "artifact": "brain.cortex"},
|
|
57
|
+
))
|
|
58
|
+
doc.sections.append(sec1)
|
|
59
|
+
|
|
60
|
+
# $2 ACTIVE WORK
|
|
61
|
+
sec2 = Section(id="$2", title="ACTIVE WORK")
|
|
62
|
+
sec2.entries.append(build_entry_from_value(
|
|
63
|
+
"$2", "FCS", "primary", "attrs",
|
|
64
|
+
{
|
|
65
|
+
"what": "current focus",
|
|
66
|
+
"priority": "high",
|
|
67
|
+
"status": "current",
|
|
68
|
+
"survive": "min",
|
|
69
|
+
},
|
|
70
|
+
))
|
|
71
|
+
sec2.entries.append(build_entry_from_value(
|
|
72
|
+
"$2", "OBJ", "main", "attrs",
|
|
73
|
+
{
|
|
74
|
+
"goal": "current objective",
|
|
75
|
+
"status": "current",
|
|
76
|
+
"success": "verifiable criterion",
|
|
77
|
+
"survive": "min",
|
|
78
|
+
},
|
|
79
|
+
))
|
|
80
|
+
sec2.entries.append(build_entry_from_value(
|
|
81
|
+
"$2", "WRK", "state", "attrs",
|
|
82
|
+
{
|
|
83
|
+
"phase": "active",
|
|
84
|
+
"current": "work state",
|
|
85
|
+
"blocked": False,
|
|
86
|
+
"survive": "work",
|
|
87
|
+
},
|
|
88
|
+
))
|
|
89
|
+
sec2.entries.append(build_entry_from_value(
|
|
90
|
+
"$2", "STP", "next", "attrs",
|
|
91
|
+
{
|
|
92
|
+
"action": "next action",
|
|
93
|
+
"reason": "why",
|
|
94
|
+
"owner": owner,
|
|
95
|
+
"status": "current",
|
|
96
|
+
"survive": "min",
|
|
97
|
+
},
|
|
98
|
+
))
|
|
99
|
+
if with_diagrams:
|
|
100
|
+
sec2.entries.append(build_entry_from_value(
|
|
101
|
+
"$2", "DIAG", "flow", "bloque",
|
|
102
|
+
"@startuml\nA --> B\n@enduml",
|
|
103
|
+
))
|
|
104
|
+
doc.sections.append(sec2)
|
|
105
|
+
|
|
106
|
+
# $3 GOVERNANCE
|
|
107
|
+
sec3 = Section(id="$3", title="GOVERNANCE")
|
|
108
|
+
sec3.entries.append(build_entry_from_value(
|
|
109
|
+
"$3", "CNST", "self_contained", "attrs",
|
|
110
|
+
{
|
|
111
|
+
"rule": "This brain.cortex carries its own minimal $0 and does not require external glossary to begin safe interpretation.",
|
|
112
|
+
"severity": "blocking",
|
|
113
|
+
"survive": "min",
|
|
114
|
+
},
|
|
115
|
+
))
|
|
116
|
+
doc.sections.append(sec3)
|
|
117
|
+
|
|
118
|
+
return doc
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""Minimal-glossary factory — produces a fully-seeded :class:`Glossary`.
|
|
2
|
+
|
|
3
|
+
The minimal glossary always includes the canonical expansion types
|
|
4
|
+
(attrs, attrs-pos, cuerpo, bloque, relación) and the canonical
|
|
5
|
+
micro-tokens (Section 4.1.1 of SKILL.md). Sigils are added by the
|
|
6
|
+
template factories (brain / skill / package / generic).
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
from typing import List
|
|
12
|
+
|
|
13
|
+
from ..core.ast import AttrsPosContract, Glossary, SigilDef, TypeDef, MicroDef
|
|
14
|
+
from ..core.errors import CANONICAL_MICRO
|
|
15
|
+
from ..glossary.contracts import DEFAULT_CONTRACTS
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def build_minimal_glossary(sigils: List[SigilDef]) -> Glossary:
|
|
19
|
+
"""Build a glossary from a list of sigils + canonical types/micro."""
|
|
20
|
+
|
|
21
|
+
g = Glossary()
|
|
22
|
+
# Canonical expansion types
|
|
23
|
+
for name, desc in [
|
|
24
|
+
("attrs", "key:value pairs"),
|
|
25
|
+
("attrs-pos", "positional with explicit contract"),
|
|
26
|
+
("cuerpo", "free text body"),
|
|
27
|
+
("bloque", "verbatim multiline block"),
|
|
28
|
+
("relación", "causal A -> B form"),
|
|
29
|
+
]:
|
|
30
|
+
g.add_type(TypeDef(name=name, description=desc))
|
|
31
|
+
# Canonical micro-tokens
|
|
32
|
+
for tok, val in CANONICAL_MICRO.items():
|
|
33
|
+
g.add_micro(MicroDef(token=tok, value=val))
|
|
34
|
+
# Sigils provided by the caller
|
|
35
|
+
for sd in sigils:
|
|
36
|
+
g.add_sigil(sd)
|
|
37
|
+
# Default contracts for attrs-pos sigils in the sigil set
|
|
38
|
+
sigil_names = {sd.sigil for sd in sigils}
|
|
39
|
+
for sig, fields in DEFAULT_CONTRACTS.items():
|
|
40
|
+
if sig in sigil_names:
|
|
41
|
+
g.add_contract(AttrsPosContract(sigil=sig, fields=list(fields)))
|
|
42
|
+
return g
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"""Nivel 3 ``package.cortex`` template factory.
|
|
2
|
+
|
|
3
|
+
Builds a transportable context package with:
|
|
4
|
+
- $0: minimal local glossary
|
|
5
|
+
- $1: PACKAGE IDENTITY (IDN:package, DOM:scope)
|
|
6
|
+
- $2: CONTENT (KNW:topic, REF:source)
|
|
7
|
+
- $3: LIMITS (LIM:package_lifecycle, CLAIM:self_contained)
|
|
8
|
+
|
|
9
|
+
Mirrors Section 18.3 of SKILL.md.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
from ..core.ast import CortexDocument, Section
|
|
15
|
+
from ..core.parser import build_entry_from_value
|
|
16
|
+
from ..glossary.minimal import package_sigils
|
|
17
|
+
from .minimal_glossary import build_minimal_glossary
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def build_package(
|
|
21
|
+
name: str = "context_package",
|
|
22
|
+
version: str = "0.1.0",
|
|
23
|
+
domain: str = "specific domain",
|
|
24
|
+
owner: str = "source",
|
|
25
|
+
language: str = "en",
|
|
26
|
+
template: str = "standard",
|
|
27
|
+
with_diagrams: bool = False,
|
|
28
|
+
) -> CortexDocument:
|
|
29
|
+
doc = CortexDocument()
|
|
30
|
+
doc.meta = {
|
|
31
|
+
"path": "<template:package>",
|
|
32
|
+
"format": ".cortex",
|
|
33
|
+
"version": version,
|
|
34
|
+
"hash": "",
|
|
35
|
+
}
|
|
36
|
+
doc.glossary = build_minimal_glossary(package_sigils())
|
|
37
|
+
|
|
38
|
+
sec0 = Section(id="$0", title="MINIMAL LOCAL GLOSSARY")
|
|
39
|
+
doc.sections.append(sec0)
|
|
40
|
+
|
|
41
|
+
sec1 = Section(id="$1", title="PACKAGE IDENTITY")
|
|
42
|
+
sec1.entries.append(build_entry_from_value(
|
|
43
|
+
"$1", "IDN", "package", "attrs",
|
|
44
|
+
{"name": name, "version": version, "status": "current"},
|
|
45
|
+
))
|
|
46
|
+
sec1.entries.append(build_entry_from_value(
|
|
47
|
+
"$1", "DOM", "scope", "attrs",
|
|
48
|
+
{"area": domain, "owner": owner, "purpose": "context injection"},
|
|
49
|
+
))
|
|
50
|
+
doc.sections.append(sec1)
|
|
51
|
+
|
|
52
|
+
sec2 = Section(id="$2", title="CONTENT")
|
|
53
|
+
sec2.entries.append(build_entry_from_value(
|
|
54
|
+
"$2", "KNW", "topic", "attrs",
|
|
55
|
+
{
|
|
56
|
+
"topic": "domain concept",
|
|
57
|
+
"content": "compressed knowledge",
|
|
58
|
+
"status": "current",
|
|
59
|
+
},
|
|
60
|
+
))
|
|
61
|
+
sec2.entries.append(build_entry_from_value(
|
|
62
|
+
"$2", "REF", "source", "attrs",
|
|
63
|
+
{"PATH": "source.md", "purpose": "traceability"},
|
|
64
|
+
))
|
|
65
|
+
if with_diagrams:
|
|
66
|
+
sec2.entries.append(build_entry_from_value(
|
|
67
|
+
"$2", "DIAG", "overview", "bloque",
|
|
68
|
+
"@startuml\n[A]-->[B]\n@enduml",
|
|
69
|
+
))
|
|
70
|
+
doc.sections.append(sec2)
|
|
71
|
+
|
|
72
|
+
sec3 = Section(id="$3", title="LIMITS")
|
|
73
|
+
sec3.entries.append(build_entry_from_value(
|
|
74
|
+
"$3", "LIM", "package_lifecycle", "attrs",
|
|
75
|
+
{
|
|
76
|
+
"limit": "package does not mature by itself until formally absorbed by Level 2",
|
|
77
|
+
"scope": "level_3",
|
|
78
|
+
"status": "current",
|
|
79
|
+
},
|
|
80
|
+
))
|
|
81
|
+
sec3.entries.append(build_entry_from_value(
|
|
82
|
+
"$3", "CLAIM", "self_contained", "attrs",
|
|
83
|
+
{
|
|
84
|
+
"statement": "This package includes its own minimal $0 for safe initial interpretation.",
|
|
85
|
+
"evidence": "$0 section present",
|
|
86
|
+
"status": "current",
|
|
87
|
+
},
|
|
88
|
+
))
|
|
89
|
+
doc.sections.append(sec3)
|
|
90
|
+
|
|
91
|
+
return doc
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"""``SKILL.cortex`` template factory.
|
|
2
|
+
|
|
3
|
+
Builds a Nivel 1 (mind) skill document with:
|
|
4
|
+
- $0: UNIVERSAL GLOSSARY
|
|
5
|
+
- $1: IDENTITY (IDN:skill, DOM:protocol)
|
|
6
|
+
- $2: AXIOMS (AXM:level_separation, AXM:self_contained)
|
|
7
|
+
|
|
8
|
+
Mirrors Section 18.1 of SKILL.md.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
from ..core.ast import CortexDocument, Section
|
|
14
|
+
from ..core.parser import build_entry_from_value
|
|
15
|
+
from ..glossary.minimal import skill_sigils
|
|
16
|
+
from .minimal_glossary import build_minimal_glossary
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def build_skill(
|
|
20
|
+
name: str = "codec-cortex",
|
|
21
|
+
version: str = "1.0.0",
|
|
22
|
+
domain: str = "LLM/SLM contextual memory",
|
|
23
|
+
owner: str = "agent",
|
|
24
|
+
language: str = "en",
|
|
25
|
+
template: str = "standard",
|
|
26
|
+
with_diagrams: bool = False,
|
|
27
|
+
) -> CortexDocument:
|
|
28
|
+
doc = CortexDocument()
|
|
29
|
+
doc.meta = {
|
|
30
|
+
"path": "<template:skill>",
|
|
31
|
+
"format": ".cortex",
|
|
32
|
+
"version": version,
|
|
33
|
+
"hash": "",
|
|
34
|
+
}
|
|
35
|
+
doc.glossary = build_minimal_glossary(skill_sigils())
|
|
36
|
+
|
|
37
|
+
sec0 = Section(id="$0", title="UNIVERSAL GLOSSARY")
|
|
38
|
+
doc.sections.append(sec0)
|
|
39
|
+
|
|
40
|
+
sec1 = Section(id="$1", title="IDENTITY")
|
|
41
|
+
sec1.entries.append(build_entry_from_value(
|
|
42
|
+
"$1", "IDN", "skill", "attrs",
|
|
43
|
+
{
|
|
44
|
+
"name": name,
|
|
45
|
+
"version": version,
|
|
46
|
+
"status": "specification",
|
|
47
|
+
"nature": "cognitive_memory_protocol",
|
|
48
|
+
},
|
|
49
|
+
))
|
|
50
|
+
sec1.entries.append(build_entry_from_value(
|
|
51
|
+
"$1", "DOM", "protocol", "attrs",
|
|
52
|
+
{
|
|
53
|
+
"area": domain,
|
|
54
|
+
"format": ".cortex",
|
|
55
|
+
"memory_output": "HCORTEX",
|
|
56
|
+
"conversational_output": "CORTEX-OUT",
|
|
57
|
+
},
|
|
58
|
+
))
|
|
59
|
+
doc.sections.append(sec1)
|
|
60
|
+
|
|
61
|
+
sec2 = Section(id="$2", title="AXIOMS")
|
|
62
|
+
sec2.entries.append(build_entry_from_value(
|
|
63
|
+
"$2", "AXM", "level_separation", "cuerpo",
|
|
64
|
+
"SKILL.cortex governs behavior and contracts. It never stores live working state.",
|
|
65
|
+
))
|
|
66
|
+
sec2.entries.append(build_entry_from_value(
|
|
67
|
+
"$2", "AXM", "self_contained", "cuerpo",
|
|
68
|
+
"Every .cortex artifact must include a minimal $0 local glossary for safe interpretation.",
|
|
69
|
+
))
|
|
70
|
+
doc.sections.append(sec2)
|
|
71
|
+
|
|
72
|
+
sec3 = Section(id="$3", title="CONSTRAINTS")
|
|
73
|
+
sec3.entries.append(build_entry_from_value(
|
|
74
|
+
"$3", "CNST", "no_live_state_in_skill", "attrs",
|
|
75
|
+
{
|
|
76
|
+
"rule": "SKILL.cortex MUST NOT contain FCS/OBJ/WRK/STP/NXT as live state.",
|
|
77
|
+
"severity": "blocking",
|
|
78
|
+
"survive": "min",
|
|
79
|
+
},
|
|
80
|
+
))
|
|
81
|
+
doc.sections.append(sec3)
|
|
82
|
+
|
|
83
|
+
if with_diagrams:
|
|
84
|
+
sec6 = Section(id="$6", title="DIAGRAMS")
|
|
85
|
+
sec6.entries.append(build_entry_from_value(
|
|
86
|
+
"$6", "DIAG", "architecture", "bloque",
|
|
87
|
+
"@startuml\n[A]-->[B]\n@enduml",
|
|
88
|
+
))
|
|
89
|
+
doc.sections.append(sec6)
|
|
90
|
+
|
|
91
|
+
return doc
|
cortex/v2/__init__.py
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
r"""CODEC-CORTEX v2 — High-fidelity CORTEX <-> HCORTEX translation.
|
|
2
|
+
|
|
3
|
+
v2.2.1: HCORTEX is reversible by definition when VIEW coverage is valid.
|
|
4
|
+
HCORTEX-R eliminated as separate concept.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from .parser import parse_cortex_v2, CortexV2Document
|
|
8
|
+
from .writer import write_cortex_v2
|
|
9
|
+
from .ir import SkillIR, IREntry, IRBlock, IRWarning, cortex_to_ir, ir_to_cortex
|
|
10
|
+
from .hcortex_renderer import render_hcortex_v2
|
|
11
|
+
from .view import (
|
|
12
|
+
ViewDirective, ViewKind, ReverseStrategy, ViewDiagnostic,
|
|
13
|
+
parse_view_entry, parse_view_entries_from_doc,
|
|
14
|
+
resolve_target, calculate_view_coverage,
|
|
15
|
+
VALID_KINDS, VALID_REVERSES, KIND_REVERSE_COMPAT,
|
|
16
|
+
)
|
|
17
|
+
from .view_renderer import render_hcortex, render_hcortex_r, has_view_errors
|
|
18
|
+
|
|
19
|
+
__all__ = [
|
|
20
|
+
"parse_cortex_v2", "write_cortex_v2", "CortexV2Document",
|
|
21
|
+
"SkillIR", "IREntry", "IRBlock", "IRWarning",
|
|
22
|
+
"cortex_to_ir", "ir_to_cortex",
|
|
23
|
+
"render_hcortex_v2",
|
|
24
|
+
# VIEW
|
|
25
|
+
"ViewDirective", "ViewKind", "ReverseStrategy", "ViewDiagnostic",
|
|
26
|
+
"parse_view_entry", "parse_view_entries_from_doc",
|
|
27
|
+
"resolve_target", "calculate_view_coverage",
|
|
28
|
+
"VALID_KINDS", "VALID_REVERSES", "KIND_REVERSE_COMPAT",
|
|
29
|
+
"render_hcortex", "render_hcortex_r", "has_view_errors",
|
|
30
|
+
]
|
cortex/v2/diagnostics.py
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"""Diagnostics for v2.3.0 — formal error taxonomy.
|
|
2
|
+
|
|
3
|
+
11 error codes + 1 warning per spec section 5.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
from dataclasses import dataclass
|
|
9
|
+
from typing import List, Optional
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
# ---------------------------------------------------------------------------
|
|
13
|
+
# Diagnostic dataclass
|
|
14
|
+
# ---------------------------------------------------------------------------
|
|
15
|
+
|
|
16
|
+
@dataclass
|
|
17
|
+
class Diagnostic:
|
|
18
|
+
code: str
|
|
19
|
+
message: str
|
|
20
|
+
severity: str = "error" # error | warning | info
|
|
21
|
+
location: Optional[str] = None # e.g. "VIEW:foo", "$0/IDN:project"
|
|
22
|
+
|
|
23
|
+
def to_dict(self) -> dict:
|
|
24
|
+
return {
|
|
25
|
+
"code": self.code,
|
|
26
|
+
"message": self.message,
|
|
27
|
+
"severity": self.severity,
|
|
28
|
+
"location": self.location,
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
# ---------------------------------------------------------------------------
|
|
33
|
+
# Formal error codes (v2.3.0 spec section 5)
|
|
34
|
+
# ---------------------------------------------------------------------------
|
|
35
|
+
|
|
36
|
+
ERROR_CODES = {
|
|
37
|
+
# HCORTEX-level
|
|
38
|
+
"E_HCORTEX_HEADER_INVALID": "Header ausente o inválido",
|
|
39
|
+
"E_HCORTEX_NOT_REVERSIBLE": "Declara o requiere reversión pero no cumple",
|
|
40
|
+
"E_VIEW_MISSING": "Bloque semántico sin VIEW",
|
|
41
|
+
"E_VIEW_TARGET_UNRESOLVED": "Target no resoluble",
|
|
42
|
+
"E_VIEW_REVERSE_UNSUPPORTED": "Estrategia inversa no soportada",
|
|
43
|
+
"E_VIEW_HASH_MISMATCH": "Hash no coincide",
|
|
44
|
+
"E_HUMAN_BLOCK_UNDECLARED": "Prosa humana no marcada",
|
|
45
|
+
"E_TABLE_SCHEMA_MISMATCH": "Tabla no coincide con fields declarados",
|
|
46
|
+
"E_BLOCK_NOT_PRESERVED": "Bloque verbatim alterado",
|
|
47
|
+
"E_AST_EQUIVALENCE_FAIL": "No se conserva equivalencia AST",
|
|
48
|
+
"W_HCORTEX_DISPLAY_ONLY": "Markdown legible, pero no HCORTEX canónico",
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def has_errors(diags: List[Diagnostic]) -> bool:
|
|
53
|
+
return any(d.severity == "error" for d in diags)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def has_view_errors(diags: List[Diagnostic]) -> bool:
|
|
57
|
+
return any(d.code.startswith("E_VIEW_") and d.severity == "error" for d in diags)
|