ckgraphify 0.1.2__tar.gz → 0.1.3__tar.gz

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 (43) hide show
  1. {ckgraphify-0.1.2 → ckgraphify-0.1.3}/PKG-INFO +1 -1
  2. {ckgraphify-0.1.2 → ckgraphify-0.1.3}/graphify/__main__.py +8 -0
  3. {ckgraphify-0.1.2 → ckgraphify-0.1.3}/graphify/graph_main_backend.py +1 -0
  4. {ckgraphify-0.1.2 → ckgraphify-0.1.3}/graphify/graph_main_frontend.py +1 -0
  5. {ckgraphify-0.1.2 → ckgraphify-0.1.3}/graphify/graph_main_merge.py +8 -11
  6. {ckgraphify-0.1.2 → ckgraphify-0.1.3}/graphify/graph_main_trace.py +16 -14
  7. {ckgraphify-0.1.2 → ckgraphify-0.1.3}/pyproject.toml +1 -1
  8. {ckgraphify-0.1.2 → ckgraphify-0.1.3}/skill/skill.md +46 -12
  9. {ckgraphify-0.1.2 → ckgraphify-0.1.3}/LICENSE +0 -0
  10. {ckgraphify-0.1.2 → ckgraphify-0.1.3}/MANIFEST.in +0 -0
  11. {ckgraphify-0.1.2 → ckgraphify-0.1.3}/README.md +0 -0
  12. {ckgraphify-0.1.2 → ckgraphify-0.1.3}/ckgraphify.egg-info/SOURCES.txt +0 -0
  13. {ckgraphify-0.1.2 → ckgraphify-0.1.3}/graphify/__init__.py +0 -0
  14. {ckgraphify-0.1.2 → ckgraphify-0.1.3}/graphify/analyze.py +0 -0
  15. {ckgraphify-0.1.2 → ckgraphify-0.1.3}/graphify/benchmark.py +0 -0
  16. {ckgraphify-0.1.2 → ckgraphify-0.1.3}/graphify/bridge_mtop.py +0 -0
  17. {ckgraphify-0.1.2 → ckgraphify-0.1.3}/graphify/build.py +0 -0
  18. {ckgraphify-0.1.2 → ckgraphify-0.1.3}/graphify/business_map.py +0 -0
  19. {ckgraphify-0.1.2 → ckgraphify-0.1.3}/graphify/cache.py +0 -0
  20. {ckgraphify-0.1.2 → ckgraphify-0.1.3}/graphify/callflow_html.py +0 -0
  21. {ckgraphify-0.1.2 → ckgraphify-0.1.3}/graphify/cluster.py +0 -0
  22. {ckgraphify-0.1.2 → ckgraphify-0.1.3}/graphify/dedup.py +0 -0
  23. {ckgraphify-0.1.2 → ckgraphify-0.1.3}/graphify/detect.py +0 -0
  24. {ckgraphify-0.1.2 → ckgraphify-0.1.3}/graphify/export.py +0 -0
  25. {ckgraphify-0.1.2 → ckgraphify-0.1.3}/graphify/extract.py +0 -0
  26. {ckgraphify-0.1.2 → ckgraphify-0.1.3}/graphify/global_graph.py +0 -0
  27. {ckgraphify-0.1.2 → ckgraphify-0.1.3}/graphify/google_workspace.py +0 -0
  28. {ckgraphify-0.1.2 → ckgraphify-0.1.3}/graphify/graph_main_html.py +0 -0
  29. {ckgraphify-0.1.2 → ckgraphify-0.1.3}/graphify/hooks.py +0 -0
  30. {ckgraphify-0.1.2 → ckgraphify-0.1.3}/graphify/ingest.py +0 -0
  31. {ckgraphify-0.1.2 → ckgraphify-0.1.3}/graphify/llm.py +0 -0
  32. {ckgraphify-0.1.2 → ckgraphify-0.1.3}/graphify/manifest.py +0 -0
  33. {ckgraphify-0.1.2 → ckgraphify-0.1.3}/graphify/report.py +0 -0
  34. {ckgraphify-0.1.2 → ckgraphify-0.1.3}/graphify/security.py +0 -0
  35. {ckgraphify-0.1.2 → ckgraphify-0.1.3}/graphify/serve.py +0 -0
  36. {ckgraphify-0.1.2 → ckgraphify-0.1.3}/graphify/transcribe.py +0 -0
  37. {ckgraphify-0.1.2 → ckgraphify-0.1.3}/graphify/tree_html.py +0 -0
  38. {ckgraphify-0.1.2 → ckgraphify-0.1.3}/graphify/validate.py +0 -0
  39. {ckgraphify-0.1.2 → ckgraphify-0.1.3}/graphify/watch.py +0 -0
  40. {ckgraphify-0.1.2 → ckgraphify-0.1.3}/graphify/wiki.py +0 -0
  41. {ckgraphify-0.1.2 → ckgraphify-0.1.3}/setup.cfg +0 -0
  42. {ckgraphify-0.1.2 → ckgraphify-0.1.3}/skill/__init__.py +0 -0
  43. {ckgraphify-0.1.2 → ckgraphify-0.1.3}/skill/skill-codex.md +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ckgraphify
3
- Version: 0.1.2
3
+ Version: 0.1.3
4
4
  Summary: AI coding assistant skill for Claude Code and Codex - graph-main boundary graphs, multi-repo call chains, business-map concepts, and business search
5
5
  License-Expression: MIT
6
6
  Project-URL: Homepage, https://github.com/safishamsi/graphify
@@ -97,7 +97,15 @@ def _claude_plugin_root() -> Path | None:
97
97
  return Path(raw).expanduser().resolve() if raw else None
98
98
 
99
99
 
100
+ def _claude_project_dir() -> Path | None:
101
+ raw = os.environ.get("CLAUDE_PROJECT_DIR", "").strip()
102
+ return Path(raw).expanduser().resolve() if raw else None
103
+
104
+
100
105
  def _default_repos_root() -> Path:
106
+ project_dir = _claude_project_dir()
107
+ if project_dir is not None:
108
+ return project_dir / "repos"
101
109
  plugin_root = _claude_plugin_root()
102
110
  if plugin_root is not None:
103
111
  return plugin_root / "repos"
@@ -1385,6 +1385,7 @@ def build_graph_main_backend(*, repo_root: Path, out_path: Path) -> GraphMainBac
1385
1385
  "graph": {
1386
1386
  "kind": "graph-main-backend",
1387
1387
  "description": "Back-end focused graph (hsf/rest/mtop/dependency/metaq)",
1388
+ "repo_name": repo_root.name,
1388
1389
  "mode": mode,
1389
1390
  "sdk_detection": sdk,
1390
1391
  },
@@ -1178,6 +1178,7 @@ def build_graph_main_frontend(*, repo_root: Path, out_path: Path) -> GraphMainFr
1178
1178
  "graph": {
1179
1179
  "kind": "graph-main-frontend",
1180
1180
  "description": "Front-end graph (page/component/api)",
1181
+ "repo_name": repo_root.name,
1181
1182
  "mode": mode,
1182
1183
  "frontend_detection": detection,
1183
1184
  },
@@ -62,24 +62,21 @@ def _edge_key(edge: dict) -> tuple[str, str, str, str]:
62
62
  )
63
63
 
64
64
 
65
- def _copy_node(repo: str, repo_root: str, graph_path: Path, node: dict) -> dict:
65
+ def _copy_node(repo: str, node: dict) -> dict:
66
66
  out = dict(node)
67
67
  local_id = str(node.get("id", ""))
68
68
  out["id"] = _node_key(repo, local_id)
69
69
  out["local_id"] = local_id
70
70
  out["repo"] = repo
71
- out["repo_root"] = repo_root
72
- out["graph_main_path"] = str(graph_path)
73
71
  out.setdefault("main_kind", "unknown")
74
72
  return out
75
73
 
76
74
 
77
- def _copy_edge(repo: str, graph_path: Path, edge: dict) -> dict:
75
+ def _copy_edge(repo: str, edge: dict) -> dict:
78
76
  out = dict(edge)
79
77
  out["source"] = _node_key(repo, edge.get("source", ""))
80
78
  out["target"] = _node_key(repo, edge.get("target", ""))
81
79
  out["repo"] = repo
82
- out["graph_main_path"] = str(graph_path)
83
80
  out["edge_scope"] = "intra_repo"
84
81
  return out
85
82
 
@@ -94,7 +91,6 @@ def _shared_api_node(anchor: str, originals: list[dict]) -> dict:
94
91
  "local_id": str(n.get("local_id", "")),
95
92
  "source_file": str(n.get("source_file", "")),
96
93
  "source_location": str(n.get("source_location", "")),
97
- "graph_main_path": str(n.get("graph_main_path", "")),
98
94
  }
99
95
  for n in originals
100
96
  ]
@@ -192,6 +188,7 @@ def merge_graph_main_files(graph_paths: Iterable[Path], out_path: Path) -> Graph
192
188
  edges: list[dict] = []
193
189
  edge_seen: set[tuple[str, str, str, str]] = set()
194
190
  repos: list[dict] = []
191
+ repo_roots: dict[str, str] = {}
195
192
  id_to_node: dict[str, dict] = {}
196
193
  canonical_index: dict[str, list[str]] = defaultdict(list)
197
194
  kind_index: dict[str, dict[str, list[str]]] = defaultdict(lambda: defaultdict(list))
@@ -203,11 +200,10 @@ def merge_graph_main_files(graph_paths: Iterable[Path], out_path: Path) -> Graph
203
200
  raise FileNotFoundError(f"graph-main not found: {path}")
204
201
  data = _load_graph(path)
205
202
  repo = _repo_from_path(path)
206
- repo_root = str(data.get("graph", {}).get("repo_root", "")) or str(path.parent.parent)
203
+ repo_root_abs = path.parent.parent
204
+ repo_roots[repo] = f"repos/{repo}"
207
205
  repo_meta = {
208
206
  "repo": repo,
209
- "graph_path": str(path),
210
- "repo_root": repo_root,
211
207
  "kind": data.get("graph", {}).get("kind", ""),
212
208
  "mode": data.get("graph", {}).get("mode", ""),
213
209
  "nodes": len(data.get("nodes", [])),
@@ -216,7 +212,7 @@ def merge_graph_main_files(graph_paths: Iterable[Path], out_path: Path) -> Graph
216
212
  repos.append(repo_meta)
217
213
 
218
214
  for node in data.get("nodes", []):
219
- copied = _copy_node(repo, repo_root, path, node)
215
+ copied = _copy_node(repo, node)
220
216
  nid = str(copied.get("id", ""))
221
217
  nodes.append(copied)
222
218
  id_to_node[nid] = copied
@@ -230,7 +226,7 @@ def merge_graph_main_files(graph_paths: Iterable[Path], out_path: Path) -> Graph
230
226
  metaq_topic_index[topic_key].append(nid)
231
227
 
232
228
  for edge in data.get("links", []):
233
- copied = _copy_edge(repo, path, edge)
229
+ copied = _copy_edge(repo, edge)
234
230
  key = _edge_key(copied)
235
231
  if key in edge_seen:
236
232
  continue
@@ -433,6 +429,7 @@ def merge_graph_main_files(graph_paths: Iterable[Path], out_path: Path) -> Graph
433
429
  "description": "Merged graph-main boundary graph with cross-repo semantic resolution edges",
434
430
  "generated_at": report["generated_at"],
435
431
  "repo_count": len(repos),
432
+ "repo_roots": repo_roots,
436
433
  "repos": repos,
437
434
  },
438
435
  "nodes": nodes,
@@ -24,10 +24,11 @@ _TRACE_RELS = {
24
24
  }
25
25
 
26
26
 
27
- def _load_graph(path: Path) -> tuple[list[dict], list[dict]]:
27
+ def _load_graph(path: Path) -> tuple[list[dict], list[dict], dict[str, str]]:
28
28
  data = json.loads(path.read_text(encoding="utf-8"))
29
29
  links = data.get("links", data.get("edges", []))
30
- return list(data.get("nodes", [])), list(links)
30
+ repo_roots = data.get("graph", {}).get("repo_roots", {})
31
+ return list(data.get("nodes", [])), list(links), repo_roots
31
32
 
32
33
 
33
34
  def _norm(v: object) -> str:
@@ -96,8 +97,9 @@ def _source_ref(node: dict) -> str:
96
97
  return source_file or source_location or "-"
97
98
 
98
99
 
99
- def _append_source_summary(lines: list[str], ordered_node_ids: list[str], by_id: dict[str, dict]) -> None:
100
+ def _append_source_summary(lines: list[str], ordered_node_ids: list[str], by_id: dict[str, dict], repo_roots: dict[str, str] | None = None) -> None:
100
101
  lines.extend(["", "Sources:"])
102
+ rr = repo_roots or {}
101
103
  for node_id in ordered_node_ids:
102
104
  node = by_id[node_id]
103
105
  lines.append(f"- {_node_text(node)}")
@@ -108,16 +110,16 @@ def _append_source_summary(lines: list[str], ordered_node_ids: list[str], by_id:
108
110
  source_file = str(origin.get("source_file") or "")
109
111
  source_location = str(origin.get("source_location") or "")
110
112
  ref = f"{source_file}:{source_location}" if source_file and source_location else (source_file or source_location or "-")
111
- lines.append(f" origin: {repo} {ref}")
113
+ root = rr.get(repo, "")
114
+ full_ref = f"{root}/{ref}" if root else ref
115
+ lines.append(f" origin: {repo} {full_ref}")
112
116
  else:
113
- repo_root = str(node.get("repo_root") or "")
114
- graph_path = str(node.get("graph_main_path") or "")
115
- lines.append(f" repo: {node.get('repo', '')}")
116
- lines.append(f" file: {_source_ref(node)}")
117
- if repo_root:
118
- lines.append(f" repo_root: {repo_root}")
119
- if graph_path:
120
- lines.append(f" graph_main: {graph_path}")
117
+ repo = str(node.get("repo", ""))
118
+ root = rr.get(repo, "")
119
+ ref = _source_ref(node)
120
+ full_ref = f"{root}/{ref}" if root and ref != "-" else ref
121
+ lines.append(f" repo: {repo}")
122
+ lines.append(f" file: {full_ref}")
121
123
 
122
124
 
123
125
  def _matches(node: dict, query: str, *, kinds: set[str] | None = None) -> bool:
@@ -179,7 +181,7 @@ def trace_graph_main(
179
181
  prefer_repos: list[str] | tuple[str, ...] | set[str] | None = None,
180
182
  exclude_repos: list[str] | tuple[str, ...] | set[str] | None = None,
181
183
  ) -> str:
182
- nodes, links = _load_graph(graph_path)
184
+ nodes, links, repo_roots = _load_graph(graph_path)
183
185
  by_id = {str(n.get("id", "")): n for n in nodes}
184
186
  start = _pick_node(
185
187
  nodes,
@@ -318,5 +320,5 @@ def trace_graph_main(
318
320
  else:
319
321
  walk(start_id, 0, {start_id}, "")
320
322
  if include_sources:
321
- _append_source_summary(lines, ordered_node_ids, by_id)
323
+ _append_source_summary(lines, ordered_node_ids, by_id, repo_roots)
322
324
  return "\n".join(lines)
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "ckgraphify"
7
- version = "0.1.2"
7
+ version = "0.1.3"
8
8
  description = "AI coding assistant skill for Claude Code and Codex - graph-main boundary graphs, multi-repo call chains, business-map concepts, and business search"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -6,6 +6,18 @@ trigger: /ckgraphify
6
6
 
7
7
  # ckgraphify Skill
8
8
 
9
+ ## Prerequisites
10
+
11
+ Before running any `graphify` command, ensure the CLI is available. Run this check once per session:
12
+
13
+ ```bash
14
+ command -v graphify >/dev/null 2>&1 || python3 -m pip install ckgraphify 2>/dev/null || true
15
+ ```
16
+
17
+ If the install fails silently, tell the user to run `pip install ckgraphify` manually.
18
+
19
+ ---
20
+
9
21
  ckgraphify helps users ask business questions without knowing exact graph node names.
10
22
 
11
23
  The public API is `/ckgraphify ...`. Treat it as an assistant API: translate it into `graphify` CLI calls, graph inspection, focused code reading, or a learn candidate patch workflow as needed.
@@ -52,15 +64,27 @@ Show this API briefly.
52
64
  ## Execution Defaults
53
65
 
54
66
  - `--path` can point to a workspace, repos root, repo list, or a merged graph JSON. Resolve it before running CLI commands.
55
- - Claude Code plugin root:
56
- - Use `${CLAUDE_PLUGIN_ROOT}` as the ckgraphify workspace root.
57
- - Default repos root is `${CLAUDE_PLUGIN_ROOT}/repos`.
67
+ - Two root directories:
68
+ - `${CLAUDE_PLUGIN_ROOT}` installed plugin directory (graph data, map, evidence).
69
+ - `${CLAUDE_PROJECT_DIR}` — the project that installed the plugin (repos, pypi source, docs).
70
+ - Graph and business map (read/write):
58
71
  - Default business map is `${CLAUDE_PLUGIN_ROOT}/graphify-out/business-map.json`.
72
+ - Default evidence shadow table is `${CLAUDE_PLUGIN_ROOT}/graphify-out/business-map-evidence.json`.
59
73
  - Default merged graph is `${CLAUDE_PLUGIN_ROOT}/graphify-out/graph-hc.json`.
60
- - If `${CLAUDE_PLUGIN_ROOT}` is missing, report that the Claude plugin environment is not active instead of falling back to a relative kg-banks path.
61
- - Default map environment:
62
- - Use `--map`, then `${CLAUDE_PLUGIN_ROOT}/graphify-out/business-map.json`.
63
- - Default graph: use `--graph`, then a JSON passed via `--path`, then `${CLAUDE_PLUGIN_ROOT}/graphify-out/graph-hc.json`, then the graph bound in `business-map.json` (`graph.path`), then `${CLAUDE_PLUGIN_ROOT}/graphify-out/graph*.json`.
74
+ - Repos (code reading, main-graph generation):
75
+ - Default repos root is `${CLAUDE_PROJECT_DIR}/repos`.
76
+ - Each repo's graph-main output is `${CLAUDE_PROJECT_DIR}/repos/<repo>/graphify-out/graph-main.json`.
77
+ - Docs and policies (read-only, bundled with pypi source):
78
+ - `${CLAUDE_PROJECT_DIR}/ckgraphify/docs/business-map-policy.md`
79
+ - Sync: after writing to `${CLAUDE_PLUGIN_ROOT}/graphify-out/`, sync changes back to the project source:
80
+
81
+ ```bash
82
+ cp "${CLAUDE_PLUGIN_ROOT}/graphify-out/business-map.json" "${CLAUDE_PROJECT_DIR}/claude-plugin/graphify-out/business-map.json"
83
+ cp "${CLAUDE_PLUGIN_ROOT}/graphify-out/business-map-evidence.json" "${CLAUDE_PROJECT_DIR}/claude-plugin/graphify-out/business-map-evidence.json"
84
+ ```
85
+
86
+ - If `${CLAUDE_PLUGIN_ROOT}` is missing, report that the Claude plugin environment is not active.
87
+ - If `${CLAUDE_PROJECT_DIR}` is missing, report that repos and docs are not available for code reading.
64
88
  - Default depth: `10`.
65
89
  - Default answer: concise business result first, evidence second, gaps last.
66
90
  - If required inputs are missing and cannot be inferred from files, ask one short clarification.
@@ -76,8 +100,8 @@ graphify business-lint --map <map>
76
100
  graphify business-validate --map <map> --graph <graph>
77
101
  graphify business-trace --map <map> --graph <graph> --concept <concept> --scenario <scenario> --flow <flow> --max-depth <n> --sources
78
102
  graphify main-trace --graph <graph> --from <exact-node> --api <api> --max-depth <n> --sources --prefer-repo <repo> --exclude-repo <repo>
79
- graphify main-graph "${CLAUDE_PLUGIN_ROOT}/repos/<repo>" --out "${CLAUDE_PLUGIN_ROOT}/repos/<repo>/graphify-out/graph-main.json"
80
- graphify merge-main-graphs "${CLAUDE_PLUGIN_ROOT}/repos/<repo-a>/graphify-out/graph-main.json" "${CLAUDE_PLUGIN_ROOT}/repos/<repo-b>/graphify-out/graph-main.json" --out "${CLAUDE_PLUGIN_ROOT}/graphify-out/graph-hc.json"
103
+ graphify main-graph "${CLAUDE_PROJECT_DIR}/repos/<repo>" --out "${CLAUDE_PROJECT_DIR}/repos/<repo>/graphify-out/graph-main.json"
104
+ graphify merge-main-graphs "${CLAUDE_PROJECT_DIR}/repos/<repo-a>/graphify-out/graph-main.json" "${CLAUDE_PROJECT_DIR}/repos/<repo-b>/graphify-out/graph-main.json" --out "${CLAUDE_PLUGIN_ROOT}/graphify-out/graph-hc.json"
81
105
  ```
82
106
 
83
107
  ## Graph Scope
@@ -86,6 +110,15 @@ Treat the merged graph as business navigation, not as a complete execution trace
86
110
 
87
111
  Do not expect `graph-hc.json` or other merged graphs to describe every parameter, response field, extension point, or method-local branch. That level of detail would make the graph too large and noisy. When a question depends on field-level or parameter-level behavior, first use `main-trace` and source filepaths to land on the right code, then read the relevant implementation directly.
88
112
 
113
+ ### File path convention
114
+
115
+ Merged graphs store source paths as **relative paths** per repo. To resolve the full path for code reading:
116
+
117
+ - `graph.repo_roots` maps each repo name to its relative root, e.g. `{"p": "repos/p", "ele-newretail-drug": "repos/ele-newretail-drug"}`.
118
+ - Each node has `repo` (repo name) and `source_file` (relative to the repo root).
119
+ - Full path = `${CLAUDE_PROJECT_DIR}` + `/` + `repo_roots[node.repo]` + `/` + `node.source_file`.
120
+ - `main-trace --sources` already outputs resolved paths in `repos/<repo>/<file>` format.
121
+
89
122
  Missing field-level graph evidence is not automatically a graph defect. Classify it as one of:
90
123
 
91
124
  - graph navigation succeeded, code reading verified the detail;
@@ -113,15 +146,16 @@ Search discipline:
113
146
  For `/ckgraphify learn`:
114
147
 
115
148
  1. Require concept, scenario, repos, graph, map, and out.
116
- 2. Read `ckgraphify/docs/business-map-policy.md`; every map iteration must follow it or explicitly report the conflict.
149
+ 2. Read `${CLAUDE_PROJECT_DIR}/ckgraphify/docs/business-map-policy.md`; every map iteration must follow it or explicitly report the conflict.
117
150
  3. Read existing map scenarios, flows, gaps, accepted gaps, verification scopes, and `search_constraints`.
118
151
  4. Search graph nodes with aliases, keywords, page/API names, HSF names, and repo hints.
119
152
  5. Run `main-trace` on promising graph matches.
120
153
  6. Validate important links in code, especially when the answer depends on response fields, request parameters, extension points, or method-local branching.
121
- 7. For a simple branch, write a candidate patch to `--out` with scenario-level anchors, trace hints, verification scope, boundaries, and remaining gaps. Keep detailed source evidence in `graphify-out/business-map-evidence.json`, not in `business-map.json`.
154
+ 7. For a simple branch, write a candidate patch to `--out` with scenario-level anchors, trace hints, verification scope, boundaries, and remaining gaps. Keep detailed source evidence in `${CLAUDE_PLUGIN_ROOT}/graphify-out/business-map-evidence.json`, not in `business-map.json`.
122
155
  8. For a complex branch, write one scenario with `flows`; each flow may have `id`, `name`, `status`, `summary`, `verification_scope`, `anchors`, `trace_hints`, `gaps`, and `accepted_gaps`. Keep `business-map.json` compact; use the evidence shadow table for source proof.
123
156
  9. Do not split a user's named complex scenario into multiple top-level scenarios unless the user asks for that model.
124
157
  10. Run `business-lint` and `business-validate`; run `business-trace` if hints are usable.
158
+ 11. After writing to `${CLAUDE_PLUGIN_ROOT}/graphify-out/`, sync changes back to `${CLAUDE_PROJECT_DIR}/claude-plugin/graphify-out/`.
125
159
 
126
160
  ## Answer Contract
127
161
 
@@ -140,7 +174,7 @@ Keep graph-main schema details, dependency extraction rules, and low-level branc
140
174
  ## Guardrails
141
175
 
142
176
  - Do not write business semantics into `graph-main.json`.
143
- - Before changing `business-map.json`, read `ckgraphify/docs/business-map-policy.md`; follow it or state the conflict.
177
+ - Before changing `business-map.json`, read `${CLAUDE_PROJECT_DIR}/ckgraphify/docs/business-map-policy.md`; follow it or state the conflict.
144
178
  - Use `scenario.flows[]` for sub-links inside one complex business scene, such as landing page purchase/refund/benefit branches.
145
179
  - Keep `business-map.json` as a search/trace index. Do not add long `evidence` arrays there; put audit proof in `graphify-out/business-map-evidence.json`.
146
180
  - Use `gaps` for active unknowns and `accepted_gaps` for known boundaries with a stop rule.
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes