carto-md 2.0.9 → 2.1.0
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/CONTRIBUTING.md +19 -15
- package/README.md +192 -415
- package/docs/api/README.md +99 -0
- package/docs/api/did_we_discuss_this.md +34 -0
- package/docs/api/dismiss_suggestion.md +34 -0
- package/docs/api/explain_change_in_natural_language.md +33 -0
- package/docs/api/find_consumers_of_api.md +34 -0
- package/docs/api/get_action_patterns.md +32 -0
- package/docs/api/get_active_drift.md +32 -0
- package/docs/api/get_active_suggestions.md +25 -0
- package/docs/api/get_ai_cost_attribution.md +32 -0
- package/docs/api/get_arch_events.md +42 -0
- package/docs/api/get_architectural_drift.md +37 -0
- package/docs/api/get_architecture.md +25 -0
- package/docs/api/get_blast_radius.md +34 -0
- package/docs/api/get_canonical_pattern.md +39 -0
- package/docs/api/get_change_plan.md +34 -0
- package/docs/api/get_change_velocity.md +32 -0
- package/docs/api/get_churn_vs_blast_radius.md +32 -0
- package/docs/api/get_complexity_trend.md +39 -0
- package/docs/api/get_context.md +34 -0
- package/docs/api/get_conventions.md +32 -0
- package/docs/api/get_cross_domain.md +25 -0
- package/docs/api/get_cross_language_call_graph.md +25 -0
- package/docs/api/get_cross_repo_blast_radius.md +34 -0
- package/docs/api/get_cross_team_coupling.md +25 -0
- package/docs/api/get_data_flow.md +33 -0
- package/docs/api/get_dead_code_with_confidence.md +32 -0
- package/docs/api/get_decision_log.md +32 -0
- package/docs/api/get_dependency_surface.md +25 -0
- package/docs/api/get_domain.md +34 -0
- package/docs/api/get_domain_evolution.md +39 -0
- package/docs/api/get_domain_health.md +32 -0
- package/docs/api/get_domains_list.md +25 -0
- package/docs/api/get_drift_digest.md +32 -0
- package/docs/api/get_env_vars.md +32 -0
- package/docs/api/get_evolution_delta.md +36 -0
- package/docs/api/get_file_ownership.md +33 -0
- package/docs/api/get_file_summary.md +34 -0
- package/docs/api/get_high_impact_files.md +32 -0
- package/docs/api/get_hot_in_prod_no_tests.md +34 -0
- package/docs/api/get_hotspot_files.md +37 -0
- package/docs/api/get_iac_resources.md +25 -0
- package/docs/api/get_interface_contract.md +33 -0
- package/docs/api/get_intervention_history.md +32 -0
- package/docs/api/get_invariants.md +37 -0
- package/docs/api/get_llm_enrichment.md +33 -0
- package/docs/api/get_microservice_cut_points.md +32 -0
- package/docs/api/get_microservices_migration_cut_points.md +25 -0
- package/docs/api/get_minimal_context_for_intent.md +39 -0
- package/docs/api/get_models.md +32 -0
- package/docs/api/get_neighbors.md +39 -0
- package/docs/api/get_org_architecture.md +25 -0
- package/docs/api/get_org_domain_mapping.md +25 -0
- package/docs/api/get_pending_decisions.md +32 -0
- package/docs/api/get_predictive_risk.md +32 -0
- package/docs/api/get_progressive_disclosure_tree.md +25 -0
- package/docs/api/get_recent_decisions.md +37 -0
- package/docs/api/get_risk_weighted_blast_radius.md +32 -0
- package/docs/api/get_routes.md +25 -0
- package/docs/api/get_safety_checklist.md +33 -0
- package/docs/api/get_semantic_diff.md +34 -0
- package/docs/api/get_service_boundary_violations.md +25 -0
- package/docs/api/get_service_dependency_graph.md +25 -0
- package/docs/api/get_session_context.md +32 -0
- package/docs/api/get_similar_patterns.md +39 -0
- package/docs/api/get_stale_docs.md +25 -0
- package/docs/api/get_structure.md +25 -0
- package/docs/api/get_temporal_context.md +34 -0
- package/docs/api/get_test_coverage_map.md +25 -0
- package/docs/api/get_token_budget_report.md +36 -0
- package/docs/api/get_upgrade_risk.md +25 -0
- package/docs/api/get_working_memory.md +25 -0
- package/docs/api/ingest_otlp_traces.md +34 -0
- package/docs/api/scaffold_for_intent.md +34 -0
- package/docs/api/search_routes.md +34 -0
- package/docs/api/simulate_change_impact.md +37 -0
- package/docs/api/validate_change.md +39 -0
- package/docs/api/validate_diff.md +39 -0
- package/docs/concepts/anci.md +87 -0
- package/docs/concepts/blast-radius.md +66 -0
- package/docs/concepts/domains.md +91 -0
- package/docs/concepts/import-graph.md +102 -0
- package/docs/concepts/mcp-integration.md +148 -0
- package/docs/guides/adding-feature-safely.md +101 -0
- package/docs/guides/ci-integration.md +175 -0
- package/docs/guides/monorepo-setup.md +121 -0
- package/docs/guides/onboarding-new-engineer.md +121 -0
- package/docs/guides/pre-merge-review.md +139 -0
- package/docs/migration/v1-to-v2.md +110 -0
- package/docs/quickstart.md +95 -0
- package/docs/scale.md +2 -2
- package/docs/troubleshooting.md +180 -0
- package/package.json +10 -4
- package/scripts/gen-api-docs.js +170 -0
- package/src/acp/agent.js +83 -11
- package/src/acp/config.js +64 -0
- package/src/acp/persistence.js +146 -0
- package/src/acp/providers/anthropic.js +179 -27
- package/src/acp/providers/index.js +15 -2
- package/src/acp/providers/openai.js +164 -38
- package/src/acp/providers/sse.js +82 -0
- package/src/acp/safety.js +128 -0
- package/src/acp/session.js +73 -0
- package/src/adjacent/call-graph.js +170 -0
- package/src/adjacent/iac.js +167 -0
- package/src/adjacent/llm-enrich.js +35 -0
- package/src/adjacent/runtime.js +216 -0
- package/src/adjacent/semantic-diff.js +143 -0
- package/src/agents/scan-structure.js +1 -1
- package/src/ai/context-builder.js +215 -0
- package/src/ai/retrieval/lexical.js +122 -0
- package/src/ai/retrieval/rrf.js +121 -0
- package/src/ai/retrieval/semantic.js +35 -0
- package/src/ai/retrieval/structural.js +82 -0
- package/src/ai/tools.js +423 -0
- package/src/anci/emit.js +2 -2
- package/src/bitmap/index.js +1 -1
- package/src/bitmap/tools.js +2 -2
- package/src/brain/conventions/index.js +185 -0
- package/src/brain/index.js +31 -0
- package/src/brain/invariants/index.js +252 -0
- package/src/brain/procedural/index.js +181 -0
- package/src/brain/suggestions/index.js +153 -0
- package/src/brain/working/index.js +170 -0
- package/src/cli/check.js +47 -1
- package/src/cli/diff.js +83 -0
- package/src/cli/doctor.js +270 -0
- package/src/cli/explain.js +61 -0
- package/src/cli/index.js +101 -0
- package/src/cli/init.js +143 -5
- package/src/cli/org.js +172 -0
- package/src/cli/pr-impact.js +59 -2
- package/src/cli/serve.js +1 -1
- package/src/cli/status.js +211 -0
- package/src/cli/sync.js +2 -2
- package/src/cli/temporal.js +188 -0
- package/src/cli/validate.js +201 -0
- package/src/cli/watch.js +4 -4
- package/src/cli/why.js +101 -0
- package/src/extractors/frameworks.js +236 -0
- package/src/extractors/languages/dart.js +138 -0
- package/src/extractors/languages/go.js +11 -1
- package/src/extractors/languages/javascript.js +13 -3
- package/src/extractors/languages/kotlin.js +169 -0
- package/src/extractors/languages/php.js +195 -0
- package/src/extractors/languages/python.js +12 -1
- package/src/extractors/languages/swift.js +140 -0
- package/src/extractors/languages/typescript.js +15 -2
- package/src/extractors/plugin-api.js +102 -0
- package/src/mcp/files-without-tests.js +285 -0
- package/src/mcp/middleware/index.js +451 -0
- package/src/mcp/server.js +2292 -0
- package/src/mcp/validate.js +1 -1
- package/src/org/detect.js +262 -0
- package/src/org/queries.js +144 -0
- package/src/org/store.js +173 -0
- package/src/org/sync.js +106 -0
- package/src/predictive/cut-points.js +83 -0
- package/src/predictive/drift-digest.js +88 -0
- package/src/predictive/ownership.js +145 -0
- package/src/predictive/risk-score.js +121 -0
- package/src/predictive/validate-change.js +55 -0
- package/src/store/store-adapter.js +3 -3
- package/src/store/{sync-v2.js → sync.js} +53 -13
- package/src/temporal/backfill.js +211 -0
- package/src/temporal/delta.js +85 -0
- package/src/temporal/events.js +180 -0
- package/src/temporal/queries.js +358 -0
- package/src/temporal/snapshot.js +151 -0
- package/src/temporal/store.js +400 -0
- package/src/mcp/server-v2.js +0 -986
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
# Guide: CI integration
|
|
2
|
+
|
|
3
|
+
> Where carto fits into your CI pipeline, beyond the GitHub Action.
|
|
4
|
+
|
|
5
|
+
## The default — GitHub Action
|
|
6
|
+
|
|
7
|
+
[`docs/guides/pre-merge-review.md`](./pre-merge-review.md) covers the canonical case: drop the Action onto every PR, get sticky-comment impact reports automatically.
|
|
8
|
+
|
|
9
|
+
This guide is for the cases where the Action isn't the right fit: GitLab, Bitbucket, custom CI, pre-commit, monorepo-specific gates.
|
|
10
|
+
|
|
11
|
+
## GitLab CI
|
|
12
|
+
|
|
13
|
+
```yaml
|
|
14
|
+
# .gitlab-ci.yml
|
|
15
|
+
carto-impact:
|
|
16
|
+
stage: test
|
|
17
|
+
image: node:20
|
|
18
|
+
rules:
|
|
19
|
+
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
|
20
|
+
cache:
|
|
21
|
+
key: carto-${CI_COMMIT_REF_SLUG}
|
|
22
|
+
paths:
|
|
23
|
+
- .carto/
|
|
24
|
+
script:
|
|
25
|
+
- npm install -g carto-md
|
|
26
|
+
- test -d .carto || carto init
|
|
27
|
+
- carto sync
|
|
28
|
+
- carto pr-impact --base origin/$CI_MERGE_REQUEST_TARGET_BRANCH_NAME --head HEAD --format markdown > impact.md
|
|
29
|
+
- cat impact.md
|
|
30
|
+
artifacts:
|
|
31
|
+
paths: [impact.md]
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Posting to the merge-request as a comment requires `glab`:
|
|
35
|
+
|
|
36
|
+
```yaml
|
|
37
|
+
- glab mr note ${CI_MERGE_REQUEST_IID} -F impact.md
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Bitbucket Pipelines
|
|
41
|
+
|
|
42
|
+
```yaml
|
|
43
|
+
# bitbucket-pipelines.yml
|
|
44
|
+
pipelines:
|
|
45
|
+
pull-requests:
|
|
46
|
+
'**':
|
|
47
|
+
- step:
|
|
48
|
+
name: Carto Impact
|
|
49
|
+
image: node:20
|
|
50
|
+
script:
|
|
51
|
+
- npm install -g carto-md
|
|
52
|
+
- carto init || carto sync
|
|
53
|
+
- carto pr-impact --base $BITBUCKET_PR_DESTINATION_BRANCH --head HEAD --fail-on HIGH
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## CircleCI
|
|
57
|
+
|
|
58
|
+
```yaml
|
|
59
|
+
# .circleci/config.yml
|
|
60
|
+
version: 2.1
|
|
61
|
+
jobs:
|
|
62
|
+
carto-impact:
|
|
63
|
+
docker:
|
|
64
|
+
- image: cimg/node:20.10
|
|
65
|
+
steps:
|
|
66
|
+
- checkout
|
|
67
|
+
- restore_cache:
|
|
68
|
+
keys: [carto-{{ .Branch }}, carto-]
|
|
69
|
+
- run: npm install -g carto-md
|
|
70
|
+
- run: test -d .carto || carto init
|
|
71
|
+
- run: carto sync
|
|
72
|
+
- run: carto pr-impact --base origin/main --head HEAD --format markdown
|
|
73
|
+
- save_cache:
|
|
74
|
+
key: carto-{{ .Branch }}
|
|
75
|
+
paths: [.carto/]
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Custom CI / shell script
|
|
79
|
+
|
|
80
|
+
The whole thing is just three commands. Drop them into whatever runner you use:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
#!/usr/bin/env bash
|
|
84
|
+
set -euo pipefail
|
|
85
|
+
|
|
86
|
+
npm install -g carto-md
|
|
87
|
+
|
|
88
|
+
if [ ! -d .carto ]; then
|
|
89
|
+
carto init
|
|
90
|
+
else
|
|
91
|
+
carto sync
|
|
92
|
+
fi
|
|
93
|
+
|
|
94
|
+
carto pr-impact \
|
|
95
|
+
--base "${BASE_REF:-origin/main}" \
|
|
96
|
+
--head HEAD \
|
|
97
|
+
--format markdown \
|
|
98
|
+
--fail-on HIGH
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Exit codes:
|
|
102
|
+
|
|
103
|
+
- 0 — comment rendered, risk below threshold
|
|
104
|
+
- 1 — misuse / index missing / git failure
|
|
105
|
+
- 2 — `--fail-on` threshold tripped
|
|
106
|
+
|
|
107
|
+
## Pre-commit hook
|
|
108
|
+
|
|
109
|
+
For "fail fast" before pushing. Add to `.git/hooks/pre-commit`:
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
#!/bin/sh
|
|
113
|
+
git diff --cached | carto validate --fail-on HIGH
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Now a `git commit` that would produce a HIGH-risk change exits 2 and the commit is blocked. The dev sees the violation reasons in the same terminal.
|
|
117
|
+
|
|
118
|
+
Note: `carto init`'s installed pre-commit hook calls `carto sync`, not `carto validate`. If you want both, prepend the validate line:
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
#!/bin/sh
|
|
122
|
+
# Spec 22: validate the staged diff first
|
|
123
|
+
git diff --cached | carto validate --fail-on HIGH || exit 2
|
|
124
|
+
|
|
125
|
+
# carto-md: keep index fresh on git events
|
|
126
|
+
carto sync >/dev/null 2>&1 || true
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Caching tips
|
|
130
|
+
|
|
131
|
+
Re-running `carto init` from scratch is fast but not free (~10 seconds for a medium repo). On CI, cache `.carto/`:
|
|
132
|
+
|
|
133
|
+
```yaml
|
|
134
|
+
# GitHub Actions
|
|
135
|
+
- uses: actions/cache@v4
|
|
136
|
+
with:
|
|
137
|
+
path: .carto/
|
|
138
|
+
key: carto-${{ hashFiles('**/*.ts', '**/*.js', '**/*.py', '**/*.go') }}
|
|
139
|
+
restore-keys: carto-
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
The cache key hashes source files — any change invalidates the cache, but the source-file hash *captures* what changed, so reuse is high across PRs.
|
|
143
|
+
|
|
144
|
+
After cache restore, run `carto sync` (not `init`). Sync is incremental — mtime+size cached, only changed files re-parsed.
|
|
145
|
+
|
|
146
|
+
## Slack notifications (drift digest)
|
|
147
|
+
|
|
148
|
+
Not built in yet — but easy to wire from CI. Run `carto check --json` on a weekly cron, post the cross-domain section to Slack:
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
carto check --json | jq '.crossDomain | length' \
|
|
152
|
+
| xargs -I {} curl -X POST -H 'Content-Type: application/json' \
|
|
153
|
+
--data "{\"text\": \"This week: {} cross-domain edges in repo X\"}" \
|
|
154
|
+
$SLACK_WEBHOOK_URL
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## Don't gate everything
|
|
158
|
+
|
|
159
|
+
A few patterns we've learned not to recommend:
|
|
160
|
+
|
|
161
|
+
- **Gating *every* PR on `--fail-on LOW`** — too noisy. LOW is just "a file changed" — every PR trips it.
|
|
162
|
+
- **Running carto on `push` events** — wastes runner minutes; the impact report is only useful in PR context where there's a base branch to diff against.
|
|
163
|
+
- **Running on docs-only changes** — `path-filters` in your workflow to skip MD-only PRs saves minutes:
|
|
164
|
+
|
|
165
|
+
```yaml
|
|
166
|
+
on:
|
|
167
|
+
pull_request:
|
|
168
|
+
paths-ignore: ['**/*.md', 'docs/**']
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Related
|
|
172
|
+
|
|
173
|
+
- [`docs/guides/pre-merge-review.md`](./pre-merge-review.md) — the canonical GitHub Action setup
|
|
174
|
+
- [`docs/guides/monorepo-setup.md`](./monorepo-setup.md) — caching considerations for large repos
|
|
175
|
+
- [`docs/troubleshooting.md`](../troubleshooting.md) — what to do when CI fails
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# Guide: Monorepo setup
|
|
2
|
+
|
|
3
|
+
> The realities of indexing a 30K-file monorepo with carto. Knobs, gotchas, expected sizes.
|
|
4
|
+
|
|
5
|
+
## The default behavior
|
|
6
|
+
|
|
7
|
+
`carto init` at the monorepo root indexes *everything*. No file cap. SQLite handles the volume; the bitmap engine handles the queries.
|
|
8
|
+
|
|
9
|
+
Real numbers from the corpus runs (see [`docs/scale.md`](../scale.md)):
|
|
10
|
+
|
|
11
|
+
| Repo | Indexed files | First run | Re-sync (no changes) | DB size |
|
|
12
|
+
|------|--------------:|----------:|---------------------:|--------:|
|
|
13
|
+
| prisma | 961 | 1.0s | 350ms | 1.1 MB |
|
|
14
|
+
| zed | 1,752 | 2.9s | 468ms | 4.8 MB |
|
|
15
|
+
| supabase | 6,330 | 5.4s | 1.2s | 4.8 MB |
|
|
16
|
+
| vscode | 7,567 | 8.0s | 935ms | 14.3 MB |
|
|
17
|
+
|
|
18
|
+
For a 30–50K-file monorepo, expect ~30–50s first run, ~3–5s incremental. Beyond 100K files Carto prints an ETA and runs in 1–2 minutes.
|
|
19
|
+
|
|
20
|
+
## What gets excluded by default
|
|
21
|
+
|
|
22
|
+
`carto init` writes a `.cartoignore` if one doesn't exist. Defaults exclude:
|
|
23
|
+
|
|
24
|
+
- `node_modules/`, `vendor/`, `dist/`, `build/`, `target/`, `out/`
|
|
25
|
+
- `.git/`, `.svn/`, `.hg/`
|
|
26
|
+
- Test files matching common conventions:
|
|
27
|
+
- `*.test.*`, `*.spec.*`, `*.stories.*` (JS/TS)
|
|
28
|
+
- `test_*.py`, `*_test.py` (Python)
|
|
29
|
+
- `test_*`, `*_test.r` (R)
|
|
30
|
+
- Subdirs named `test/`, `tests/`, `__tests__/`, `spec/`
|
|
31
|
+
- Secrets / credentials: `.env*`, `*secret*`, `*credential*`, `*private_key*`, `*.pem`, `*.key`, SSH keys, AWS/GCP creds, kubeconfig, token files
|
|
32
|
+
- Binaries: images, media, archives
|
|
33
|
+
- Cache directories
|
|
34
|
+
|
|
35
|
+
If your monorepo has unusual layout (a separately-managed `vendor/` you do want indexed, e.g.), edit `.cartoignore` to allow it back in.
|
|
36
|
+
|
|
37
|
+
## Submodules
|
|
38
|
+
|
|
39
|
+
If `.gitmodules` is present, `carto init` warns:
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
[CARTO] Detected 3 git submodules. Add their paths to .cartoignore
|
|
43
|
+
if you don't want them indexed.
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Default behavior: submodule directories *are* descended into. If your submodules are external/vendored packages, you almost certainly want them excluded — add their paths to `.cartoignore`.
|
|
47
|
+
|
|
48
|
+
## Per-workspace domain hints
|
|
49
|
+
|
|
50
|
+
Monorepos with `packages/auth/`, `packages/payments/`, `packages/db/` produce good auto-detected domains because the path tokens line up with what the Leiden+CPM clusterer finds in the graph.
|
|
51
|
+
|
|
52
|
+
If you have a flatter layout (`apps/web/src/{auth,payments,db}/`), use `carto.config.json` to pin domains:
|
|
53
|
+
|
|
54
|
+
```json
|
|
55
|
+
{
|
|
56
|
+
"domains": {
|
|
57
|
+
"AUTH": {
|
|
58
|
+
"keywords": ["auth", "login", "session"],
|
|
59
|
+
"anchor": ["apps/web/src/auth/session.ts"]
|
|
60
|
+
},
|
|
61
|
+
"PAYMENTS": {
|
|
62
|
+
"keywords": ["payment", "billing", "checkout"],
|
|
63
|
+
"anchor": ["apps/web/src/payments/charge.ts"]
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
The `anchor` files force those paths into the named domain regardless of clustering. See [`domains.md`](../concepts/domains.md).
|
|
70
|
+
|
|
71
|
+
## TypeScript path aliases
|
|
72
|
+
|
|
73
|
+
Carto reads `tsconfig.json#paths` and `jsconfig.json#paths` for import resolution. In a monorepo with workspace references (e.g. `tsconfig.json#references`), each workspace's `tsconfig.json` is read independently. The aliases declared in `apps/web/tsconfig.json` apply when resolving imports *inside* `apps/web/`, etc.
|
|
74
|
+
|
|
75
|
+
If you use TypeScript project references with `"composite": true`, this just works. If you use a monorepo tool that bypasses tsconfig (some Nx setups), declare the equivalent paths in a top-level `tsconfig.json` for Carto's benefit even if the build doesn't use them.
|
|
76
|
+
|
|
77
|
+
## Cross-package imports
|
|
78
|
+
|
|
79
|
+
When `@company/auth` is published locally (npm workspaces, pnpm workspaces, yarn workspaces), imports of `@company/auth` resolve via the workspace symlink — which Carto follows. So `import { sessionFor } from '@company/auth'` from `apps/web/src/api/users.ts` correctly resolves to `packages/auth/src/index.ts`, and the edge ends up in the graph.
|
|
80
|
+
|
|
81
|
+
What this enables:
|
|
82
|
+
|
|
83
|
+
- `get_blast_radius('packages/auth/src/session.ts')` returns dependents across *every* workspace
|
|
84
|
+
- Cross-domain checks fire on workspace-to-workspace edges
|
|
85
|
+
- The `simulate_change_impact` MCP tool correctly unions blast radius across packages
|
|
86
|
+
|
|
87
|
+
## Excluding individual workspaces
|
|
88
|
+
|
|
89
|
+
`carto.config.json` can pin which directories to index:
|
|
90
|
+
|
|
91
|
+
```json
|
|
92
|
+
{
|
|
93
|
+
"include": ["apps/", "packages/"],
|
|
94
|
+
"exclude": ["packages/legacy-thing/"]
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
`include` is rare — `.cartoignore` is usually the right tool. `exclude` is the common case for "we don't index this old workspace anymore".
|
|
99
|
+
|
|
100
|
+
## Scoped indexing (>100K files)
|
|
101
|
+
|
|
102
|
+
For *very* large monorepos (Google-scale, ~1M files), the full index gets unwieldy. The roadmap has a `--scope=packages/changed/**` flag that only indexes affected workspaces; that hasn't shipped yet. If you hit this scale, file an issue — the gating decision is "real users at this scale" rather than premature.
|
|
103
|
+
|
|
104
|
+
In the meantime, the working knob is `.cartoignore`. Exclude packages you don't change, accept a partial graph, get a usable index.
|
|
105
|
+
|
|
106
|
+
## Performance expectations
|
|
107
|
+
|
|
108
|
+
| Files | First run | Re-sync | DB | Bitmap | RSS |
|
|
109
|
+
|------:|----------:|--------:|---:|-------:|----:|
|
|
110
|
+
| 1K | 1s | 350ms | 1 MB | 100 KB | 60 MB |
|
|
111
|
+
| 10K | 8s | 1s | 14 MB | 1.2 MB | 220 MB |
|
|
112
|
+
| 50K | 50s | 4s | 80 MB | 8 MB | 600 MB |
|
|
113
|
+
| 100K | ~100s | ~10s | 160 MB | 20 MB | 1.1 GB |
|
|
114
|
+
|
|
115
|
+
These are from the synthetic stress harness (`bench/scale-test/`). Real repos vary depending on edge density, but the shape is the same.
|
|
116
|
+
|
|
117
|
+
## Related
|
|
118
|
+
|
|
119
|
+
- [`docs/concepts/domains.md`](../concepts/domains.md) — adaptive gamma + custom hints
|
|
120
|
+
- [`docs/concepts/import-graph.md`](../concepts/import-graph.md) — alias resolution details
|
|
121
|
+
- [`docs/scale.md`](../scale.md) — full benchmark table
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# Guide: Onboarding a new engineer
|
|
2
|
+
|
|
3
|
+
> Day 1, hour 1, productive. Without 47 Slack DMs to teammates.
|
|
4
|
+
|
|
5
|
+
## The cold start
|
|
6
|
+
|
|
7
|
+
New engineer joins. The repo has 50K lines, three years of history, no architecture docs. The standard onboarding pattern is:
|
|
8
|
+
|
|
9
|
+
- Day 1–3: Set up tooling. Read README. Get the app running locally.
|
|
10
|
+
- Day 4–10: Get assigned a "starter ticket" — a tiny bug fix in a dark corner. Realize you have no idea where to begin.
|
|
11
|
+
- Day 11–20: Slack DMs. *"Where does session validation live?"* *"What does this file do?"* *"Is this safe to change?"*
|
|
12
|
+
- Day 21+: Maybe starting to feel productive.
|
|
13
|
+
|
|
14
|
+
That's 3 weeks × $5K/week = $15K of ramp time per hire. Most of it is the new engineer trying to build the mental model of the codebase that everyone else already has.
|
|
15
|
+
|
|
16
|
+
## What Carto does instead
|
|
17
|
+
|
|
18
|
+
`carto init` produces three things the new engineer can read on day 1:
|
|
19
|
+
|
|
20
|
+
1. **`AGENTS.md`** at the project root. Plain markdown. Architecture overview, domain list with file counts, top high-impact files. Skim in 5 minutes.
|
|
21
|
+
|
|
22
|
+
2. **`.carto/context/<DOMAIN>.md`** for each detected domain. Per-domain context: entry points, key files, common patterns. Read just the ones relevant to your starter ticket.
|
|
23
|
+
|
|
24
|
+
3. **A live MCP server** their AI tool (Cursor/Claude/Kiro/etc.) is already wired to. Every question the new engineer would have asked in Slack — "where does session validation live?", "what does this file do?", "what's the blast radius of this change?" — is one MCP call away.
|
|
25
|
+
|
|
26
|
+
## A literal day-1 walk-through
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
# new engineer just cloned the repo
|
|
30
|
+
git clone …
|
|
31
|
+
cd …
|
|
32
|
+
|
|
33
|
+
# carto is probably already installed; if not:
|
|
34
|
+
npm install -g carto-md
|
|
35
|
+
|
|
36
|
+
# first command they run:
|
|
37
|
+
carto init
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
The init banner gives the mirror moment:
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
┌─ Carto · indexed ─────────────────────────────────────────
|
|
44
|
+
│ 3,847 files · 7 domains · 142 routes · 8,201 import edges
|
|
45
|
+
│
|
|
46
|
+
│ Top domains:
|
|
47
|
+
│ CORE (1,940 files)
|
|
48
|
+
│ DATABASE (412 files)
|
|
49
|
+
│ AUTH (287 files)
|
|
50
|
+
│ PAYMENTS (235 files)
|
|
51
|
+
│
|
|
52
|
+
│ 💡 Highest-risk file: src/lib/db/client.ts
|
|
53
|
+
│ (94 files depend on it — try `carto why src/lib/db/client.ts`)
|
|
54
|
+
└───────────────────────────────────────────────────────────
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
They now know:
|
|
58
|
+
|
|
59
|
+
- This repo has ~4K source files (real size, not the inflated package.json claim)
|
|
60
|
+
- It's split into 7 domains they should learn one at a time
|
|
61
|
+
- The single most important file is `src/lib/db/client.ts`
|
|
62
|
+
|
|
63
|
+
Five minutes in, they've replaced 30 minutes of clicking around.
|
|
64
|
+
|
|
65
|
+
## What to ask first
|
|
66
|
+
|
|
67
|
+
Three questions every new engineer should ask their AI tool in the first hour:
|
|
68
|
+
|
|
69
|
+
1. *"Give me the architectural overview of this project."* → calls `get_architecture()`. 500-word summary.
|
|
70
|
+
|
|
71
|
+
2. *"What's in the AUTH domain?"* (or whichever they're working on) → calls `get_domain("AUTH")`. Routes, models, key files.
|
|
72
|
+
|
|
73
|
+
3. *"What does `src/lib/db/client.ts` do and what depends on it?"* → calls `get_file_summary()` + `get_blast_radius()`. Now they know the danger zone.
|
|
74
|
+
|
|
75
|
+
## When they pick up their first ticket
|
|
76
|
+
|
|
77
|
+
They start with:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
carto explain "fix the bug in user signup where email validation is skipped"
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
This calls `get_change_plan()` — same engine the AI uses. Output:
|
|
84
|
+
|
|
85
|
+
```
|
|
86
|
+
## Plan: fix bug in user signup where email validation is skipped
|
|
87
|
+
|
|
88
|
+
### Relevant routes
|
|
89
|
+
- POST /auth/signup src/auth/signup.ts:42
|
|
90
|
+
|
|
91
|
+
### Files to touch
|
|
92
|
+
- src/auth/signup.ts — the route handler (15 direct dependents)
|
|
93
|
+
- src/auth/validators.ts — email validation lives here
|
|
94
|
+
|
|
95
|
+
### Similar patterns
|
|
96
|
+
- src/auth/login.ts already validates email format using validateEmail()
|
|
97
|
+
- src/auth/reset-password.ts also uses validateEmail()
|
|
98
|
+
|
|
99
|
+
### Blast radius
|
|
100
|
+
- src/auth/signup.ts: 15 dependent files. Test coverage in
|
|
101
|
+
src/auth/__tests__/signup.test.ts — re-run after change.
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
A new engineer who's never opened `signup.ts` can read this, open the 3 files it names, find the bug, fix it correctly the first time. No Slack DM needed.
|
|
105
|
+
|
|
106
|
+
## When they break something
|
|
107
|
+
|
|
108
|
+
Even with Carto, mistakes happen. The two tools that help most:
|
|
109
|
+
|
|
110
|
+
- **`carto diff`** before committing. Shows the architectural impact of the local change — blast radius, cross-domain violations, files-without-tests. The new engineer self-corrects.
|
|
111
|
+
- **The GitHub Action** ([guide](./ci-integration.md)) catches what the new engineer didn't. The PR gets an impact comment; reviewers spot risky changes before merge.
|
|
112
|
+
|
|
113
|
+
## The team multiplier
|
|
114
|
+
|
|
115
|
+
Onboarding is the cost the *team* pays for a hire, not just the hire. Every Slack DM from a new engineer is an interruption to a senior. A 1-week ramp instead of a 3-week ramp doesn't just save the new engineer's time — it saves the senior's too.
|
|
116
|
+
|
|
117
|
+
## Related
|
|
118
|
+
|
|
119
|
+
- [`docs/quickstart.md`](../quickstart.md) — install + init
|
|
120
|
+
- [`docs/concepts/domains.md`](../concepts/domains.md) — how domains are named
|
|
121
|
+
- [`docs/guides/adding-feature-safely.md`](./adding-feature-safely.md) — the workflow for the second week onward
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# Guide: Pre-merge review
|
|
2
|
+
|
|
3
|
+
> Architecture review at PR time, automatically. The reviewer sees structural impact alongside the diff.
|
|
4
|
+
|
|
5
|
+
## What the GitHub Action does
|
|
6
|
+
|
|
7
|
+
On every pull request:
|
|
8
|
+
|
|
9
|
+
1. Checks out the PR head
|
|
10
|
+
2. Restores `.carto/` from `actions/cache` (or runs `carto init` cold)
|
|
11
|
+
3. Runs `carto pr-impact --base $BASE --head $HEAD --format markdown`
|
|
12
|
+
4. Posts the result as a sticky comment on the PR (one comment per PR, updated in place on every push)
|
|
13
|
+
|
|
14
|
+
The whole flow runs in 30–120 seconds on a warm cache, 1–3 minutes cold.
|
|
15
|
+
|
|
16
|
+
## Setup
|
|
17
|
+
|
|
18
|
+
In `.github/workflows/carto.yml`:
|
|
19
|
+
|
|
20
|
+
```yaml
|
|
21
|
+
name: Carto Impact Report
|
|
22
|
+
on:
|
|
23
|
+
pull_request:
|
|
24
|
+
branches: [main]
|
|
25
|
+
permissions:
|
|
26
|
+
contents: read
|
|
27
|
+
pull-requests: write
|
|
28
|
+
jobs:
|
|
29
|
+
carto:
|
|
30
|
+
runs-on: ubuntu-latest
|
|
31
|
+
steps:
|
|
32
|
+
- uses: actions/checkout@v4
|
|
33
|
+
with: { fetch-depth: 0 } # full history — pr-impact needs the base ref
|
|
34
|
+
- uses: theanshsonkar/carto@v2.0.9
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
That's the entire config. The action handles npm install, cache restore, sync, pr-impact, and the comment.
|
|
38
|
+
|
|
39
|
+
## What the comment looks like
|
|
40
|
+
|
|
41
|
+
```markdown
|
|
42
|
+
## 🗺️ Carto Impact Report
|
|
43
|
+
|
|
44
|
+
This PR touches **AUTH** and **DATABASE** domains.
|
|
45
|
+
|
|
46
|
+
| Metric | Value |
|
|
47
|
+
|--------|-------|
|
|
48
|
+
| Risk | 🔴 HIGH |
|
|
49
|
+
| Blast radius (union) | 47 files |
|
|
50
|
+
| Files changed | 6 |
|
|
51
|
+
| Cross-domain violations introduced | 2 |
|
|
52
|
+
| Files without tests in blast radius | 5 of 31 |
|
|
53
|
+
| High-impact file changed | src/auth/session.ts (8 direct dependents) |
|
|
54
|
+
|
|
55
|
+
<details>
|
|
56
|
+
<summary>Affected routes (4)</summary>
|
|
57
|
+
|
|
58
|
+
- POST /auth/login — risk: HIGH
|
|
59
|
+
- GET /auth/me — risk: HIGH
|
|
60
|
+
- POST /auth/register — risk: MEDIUM
|
|
61
|
+
- POST /api/users — risk: LOW
|
|
62
|
+
|
|
63
|
+
</details>
|
|
64
|
+
|
|
65
|
+
<details>
|
|
66
|
+
<summary>Cross-domain violations (2)</summary>
|
|
67
|
+
|
|
68
|
+
- auth/login.ts now imports from payments/billing.ts (AUTH→PAYMENTS)
|
|
69
|
+
- database/user-repo.ts now imports from auth/jwt.ts (DATABASE→AUTH)
|
|
70
|
+
|
|
71
|
+
</details>
|
|
72
|
+
|
|
73
|
+
<details>
|
|
74
|
+
<summary>Files without tests in blast radius (5)</summary>
|
|
75
|
+
|
|
76
|
+
- src/auth/middleware.ts
|
|
77
|
+
- src/auth/jwt-helpers.ts
|
|
78
|
+
- …
|
|
79
|
+
</details>
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## What a reviewer does with this
|
|
83
|
+
|
|
84
|
+
Look at the four signals in order:
|
|
85
|
+
|
|
86
|
+
1. **Risk badge.** HIGH / MEDIUM / LOW / SAFE. If it's SAFE or LOW, you can mostly skip the structural review and focus on the code itself. If it's HIGH, look more carefully.
|
|
87
|
+
|
|
88
|
+
2. **Cross-domain violations.** Each one is a new dependency between domains. Sometimes correct (a refactor moving shared logic), sometimes a smell (auth pulling from payments). Reviewer applies judgment.
|
|
89
|
+
|
|
90
|
+
3. **Files without tests.** Files in the blast radius that don't have a sibling test file. Lower confidence in the change because there's no automated check. Suggest the author add tests, or document why not.
|
|
91
|
+
|
|
92
|
+
4. **High-impact file changed.** Anything modifying a >20-dependent file deserves an extra read-through. Subtle changes to a widely-used utility have outsized blast.
|
|
93
|
+
|
|
94
|
+
## Failing the build on risk
|
|
95
|
+
|
|
96
|
+
For repos that want a harder gate, set `fail-on` in the workflow:
|
|
97
|
+
|
|
98
|
+
```yaml
|
|
99
|
+
- uses: theanshsonkar/carto@v2.0.9
|
|
100
|
+
with:
|
|
101
|
+
fail-on: HIGH
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Now the build fails when the risk is HIGH. PRs need to lower the risk (split, add tests, refactor) before they can merge.
|
|
105
|
+
|
|
106
|
+
Use sparingly. HIGH-risk changes are sometimes correct and *necessary* — the right reviewer call is "look more carefully", not "block automatically".
|
|
107
|
+
|
|
108
|
+
## Inputs reference
|
|
109
|
+
|
|
110
|
+
| Input | Default | What it does |
|
|
111
|
+
|---------------|-------------|--------------|
|
|
112
|
+
| `carto-version` | `latest` | Pin in production for reproducibility. |
|
|
113
|
+
| `base` | auto | Git ref the PR branched from. Auto-detected from `origin/$GITHUB_BASE_REF`. |
|
|
114
|
+
| `head` | auto | Git ref of the PR head. Auto-detected from `$GITHUB_SHA`. |
|
|
115
|
+
| `fail-on` | _(empty)_ | Fail when risk ≥ this severity. `HIGH`, `MEDIUM`, or `LOW`. |
|
|
116
|
+
| `comment-mode`| `sticky` | `sticky` updates existing comment, `new` posts a new one every push, `none` skips the comment (renders to stdout). |
|
|
117
|
+
| `node-version`| `20` | Node version on the runner. |
|
|
118
|
+
|
|
119
|
+
## Outputs
|
|
120
|
+
|
|
121
|
+
| Output | Description |
|
|
122
|
+
|--------------|-------------|
|
|
123
|
+
| `risk` | `SAFE` / `LOW` / `MEDIUM` / `HIGH` — gate downstream steps on it. |
|
|
124
|
+
| `comment-url`| URL of the posted comment. |
|
|
125
|
+
|
|
126
|
+
## Running it locally (mirror the CI)
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
carto pr-impact --base origin/main --head HEAD
|
|
130
|
+
carto pr-impact --base origin/main --head HEAD --format json
|
|
131
|
+
carto pr-impact --base origin/main --head HEAD --fail-on HIGH
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Same engine, same output. Useful for testing changes before pushing.
|
|
135
|
+
|
|
136
|
+
## Related
|
|
137
|
+
|
|
138
|
+
- [`docs/guides/ci-integration.md`](./ci-integration.md) — broader CI patterns
|
|
139
|
+
- [`docs/concepts/blast-radius.md`](../concepts/blast-radius.md) — the math behind the metric
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# Migration: V1 → V2
|
|
2
|
+
|
|
3
|
+
> Notes for anyone who installed `carto-md` pre-2.0.6.
|
|
4
|
+
|
|
5
|
+
## What V2 changed
|
|
6
|
+
|
|
7
|
+
V1 stored the index as JSON files at `.carto/cache/graph-cache.json` and `.carto/cache/hashes.json`. V2 stores it as SQLite at `.carto/carto.db` with a derived bitmap sidecar at `.carto/bitmap.bin`.
|
|
8
|
+
|
|
9
|
+
Why: SQLite handles 100K-file repos cleanly where the JSON approach started getting slow at ~10K files. The bitmap layer makes graph queries 100–10,000× faster than SQL at scale (see [`docs/scale.md`](../scale.md)).
|
|
10
|
+
|
|
11
|
+
V1 has been fully deleted from the tree as of carto-md@2.0.6.
|
|
12
|
+
|
|
13
|
+
## What you need to do
|
|
14
|
+
|
|
15
|
+
In most cases — nothing. `carto init` (or any `carto` command that touches the index) detects the old V1 cache files and migrates them transparently on first run.
|
|
16
|
+
|
|
17
|
+
Specifically, the migration:
|
|
18
|
+
|
|
19
|
+
1. Reads `.carto/cache/graph-cache.json` if present (V1 metadata)
|
|
20
|
+
2. Notices it's incompatible with the V2 schema
|
|
21
|
+
3. Runs a fresh `carto sync` to repopulate `.carto/carto.db` from source
|
|
22
|
+
4. Leaves the V1 files in place (they're harmless dead bytes)
|
|
23
|
+
|
|
24
|
+
The Spec 7 test suite explicitly covers this case: *"carto init migrates leftover V1 graph-cache.json cleanly (no errors)"*.
|
|
25
|
+
|
|
26
|
+
## Manual cleanup (optional)
|
|
27
|
+
|
|
28
|
+
After the first V2 sync succeeds, the V1 files are no longer read. Reclaim a bit of disk:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
rm -f .carto/cache/graph-cache.json
|
|
32
|
+
rm -f .carto/cache/hashes.json
|
|
33
|
+
rmdir .carto/cache # if empty
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Or just `carto remove && carto init` for a clean slate.
|
|
37
|
+
|
|
38
|
+
## MCP wiring changes
|
|
39
|
+
|
|
40
|
+
V1 exposed 12 MCP tools. V2 ships ~75, organized into 8 categories (core graph, episodic memory, temporal, brain, predictive, AI-native retrieval, adjacent, org-wide).
|
|
41
|
+
|
|
42
|
+
The highest-impact additions from V1:
|
|
43
|
+
|
|
44
|
+
- `get_architecture()` — the "use this first" tool
|
|
45
|
+
- `get_file_summary(file)` — surfaces what `carto why` shows
|
|
46
|
+
- `get_change_plan(intent)` — real graph traversal (V1 was keyword grep — Spec 2 rewrite)
|
|
47
|
+
- `get_similar_patterns(file)` — Jaccard-similarity over import sets
|
|
48
|
+
- `validate_diff(diff)` — sub-15ms pre-write governance, writes every call into the episodic log
|
|
49
|
+
- `did_we_discuss_this(topic)` — six-week recall over the decision log
|
|
50
|
+
- `get_predictive_risk(file?)` — P(file causes the next incident) score
|
|
51
|
+
- `get_minimal_context_for_intent(intent, budget)` — token-budgeted hybrid retrieval (structural + lexical + semantic with RRF fusion)
|
|
52
|
+
- `simulate_change_impact(files)` — bitmap-backed multi-file blast radius
|
|
53
|
+
|
|
54
|
+
Plus the temporal trio (`get_architectural_drift`, `get_domain_evolution`, `get_hotspot_files`), the brain stack (`get_invariants`, `get_conventions`, `get_action_patterns`, `scaffold_for_intent`), and the org/cross-repo set (`get_org_architecture`, `get_service_dependency_graph`, `find_consumers_of_api`).
|
|
55
|
+
|
|
56
|
+
Full reference: [`docs/api/`](../api/).
|
|
57
|
+
|
|
58
|
+
If your AI tool was configured against V1 and you're seeing tool-not-found errors, restart the tool to pick up the V2 server's new `tools/list` response. The wire protocol is the same.
|
|
59
|
+
|
|
60
|
+
## ACP agent
|
|
61
|
+
|
|
62
|
+
V1's ACP agent (in Zed / JetBrains / VS Code via `carto agent`) used its own in-memory index. V2's ACP agent shares the SQLite index with the MCP server (Spec 5). Re-running `carto init` in your project ensures both ACP and MCP see the same data.
|
|
63
|
+
|
|
64
|
+
## `.cartoignore` defaults
|
|
65
|
+
|
|
66
|
+
V2 expanded the default exclusion list from 12 patterns to 39 (Spec 8: SSH keys, AWS/GCP creds, `.netrc`, kubeconfig, etc.). If your project had a custom `.cartoignore`, it's preserved — Carto only writes a default when none exists. To pick up the new defaults, delete your `.cartoignore` and run `carto init` to regenerate.
|
|
67
|
+
|
|
68
|
+
## Git hooks
|
|
69
|
+
|
|
70
|
+
V1 didn't install git hooks. V2 (Spec 9) installs four:
|
|
71
|
+
|
|
72
|
+
- `pre-commit`
|
|
73
|
+
- `post-checkout`
|
|
74
|
+
- `post-merge`
|
|
75
|
+
- `post-rewrite`
|
|
76
|
+
|
|
77
|
+
Each runs `carto sync >/dev/null 2>&1 || true` — never blocks git, never errors loudly. If you already have hooks for other purposes, Carto appends to them non-destructively. Run `carto doctor` to confirm the hooks installed.
|
|
78
|
+
|
|
79
|
+
## Behavior changes worth flagging
|
|
80
|
+
|
|
81
|
+
| Behavior | V1 | V2 |
|
|
82
|
+
|----------|----|----|
|
|
83
|
+
| File-discovery cap | hard cap at ~50K files | uncapped |
|
|
84
|
+
| Index format | JSON | SQLite + bitmap |
|
|
85
|
+
| Re-parse on edit | only via `carto watch` | lazy at MCP query time + git hooks |
|
|
86
|
+
| `get_change_plan` | keyword grep | real graph traversal |
|
|
87
|
+
| Cross-domain detection | path-based | graph-clustered |
|
|
88
|
+
| ACP / MCP share index | no | yes |
|
|
89
|
+
| Read-only MCP DB | no | yes |
|
|
90
|
+
| Default `.cartoignore` | 12 patterns | 39 patterns |
|
|
91
|
+
|
|
92
|
+
If you depended on a V1-specific behavior that's no longer accurate, file an issue — we may have broken something we shouldn't have.
|
|
93
|
+
|
|
94
|
+
## Pinned-version recommendation
|
|
95
|
+
|
|
96
|
+
If you're upgrading in CI, pin a known-good Carto version:
|
|
97
|
+
|
|
98
|
+
```yaml
|
|
99
|
+
# .github/workflows/carto.yml
|
|
100
|
+
- uses: theanshsonkar/carto@v2.0.9
|
|
101
|
+
with:
|
|
102
|
+
carto-version: '2.0.9' # pin instead of `latest`
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
This way the action's output (and the PR-comment shape) stays stable across CI runs even when newer Carto versions ship.
|
|
106
|
+
|
|
107
|
+
## Related
|
|
108
|
+
|
|
109
|
+
- [`docs/troubleshooting.md`](../troubleshooting.md) — what to do when migration goes sideways
|
|
110
|
+
- [Spec 6](../../Progress/working.md) in `Progress/working.md` — the deletion that removed V1
|