graphite-code 0.3.0__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.
- graphite_code-0.3.0/.gitignore +31 -0
- graphite_code-0.3.0/ARCHITECTURE.md +206 -0
- graphite_code-0.3.0/CHANGELOG.md +586 -0
- graphite_code-0.3.0/CONTRIBUTING.md +191 -0
- graphite_code-0.3.0/LICENSE +21 -0
- graphite_code-0.3.0/PKG-INFO +743 -0
- graphite_code-0.3.0/README.md +701 -0
- graphite_code-0.3.0/RELEASING.md +346 -0
- graphite_code-0.3.0/pyproject.toml +218 -0
- graphite_code-0.3.0/src/graphite/__init__.py +41 -0
- graphite_code-0.3.0/src/graphite/__main__.py +7 -0
- graphite_code-0.3.0/src/graphite/_cleanup_worker.py +525 -0
- graphite_code-0.3.0/src/graphite/activation.py +164 -0
- graphite_code-0.3.0/src/graphite/agent_hooks.py +577 -0
- graphite_code-0.3.0/src/graphite/agent_settings.py +226 -0
- graphite_code-0.3.0/src/graphite/analyze.py +146 -0
- graphite_code-0.3.0/src/graphite/answer_contract.py +420 -0
- graphite_code-0.3.0/src/graphite/bootstrap.py +210 -0
- graphite_code-0.3.0/src/graphite/buildlock.py +99 -0
- graphite_code-0.3.0/src/graphite/cache.py +131 -0
- graphite_code-0.3.0/src/graphite/channel.py +1325 -0
- graphite_code-0.3.0/src/graphite/cli.py +3053 -0
- graphite_code-0.3.0/src/graphite/cluster.py +111 -0
- graphite_code-0.3.0/src/graphite/config.py +209 -0
- graphite_code-0.3.0/src/graphite/context.py +355 -0
- graphite_code-0.3.0/src/graphite/daemon.py +745 -0
- graphite_code-0.3.0/src/graphite/daemon_health.py +733 -0
- graphite_code-0.3.0/src/graphite/debt.py +118 -0
- graphite_code-0.3.0/src/graphite/dependency_install.py +1597 -0
- graphite_code-0.3.0/src/graphite/detach.py +33 -0
- graphite_code-0.3.0/src/graphite/doctor.py +678 -0
- graphite_code-0.3.0/src/graphite/doctor_probes.py +2100 -0
- graphite_code-0.3.0/src/graphite/engine_identity.py +238 -0
- graphite_code-0.3.0/src/graphite/export/__init__.py +6 -0
- graphite_code-0.3.0/src/graphite/export/html.py +244 -0
- graphite_code-0.3.0/src/graphite/export/json.py +39 -0
- graphite_code-0.3.0/src/graphite/export/md.py +68 -0
- graphite_code-0.3.0/src/graphite/extract/__init__.py +4 -0
- graphite_code-0.3.0/src/graphite/extract/ast.py +1964 -0
- graphite_code-0.3.0/src/graphite/freshness.py +127 -0
- graphite_code-0.3.0/src/graphite/git.py +406 -0
- graphite_code-0.3.0/src/graphite/graph.py +117 -0
- graphite_code-0.3.0/src/graphite/graph_io.py +188 -0
- graphite_code-0.3.0/src/graphite/health.py +147 -0
- graphite_code-0.3.0/src/graphite/hook_entry.py +68 -0
- graphite_code-0.3.0/src/graphite/hookinstall.py +224 -0
- graphite_code-0.3.0/src/graphite/hookshim.py +86 -0
- graphite_code-0.3.0/src/graphite/incident_ledger.py +247 -0
- graphite_code-0.3.0/src/graphite/ingest.py +279 -0
- graphite_code-0.3.0/src/graphite/init.py +791 -0
- graphite_code-0.3.0/src/graphite/io.py +32 -0
- graphite_code-0.3.0/src/graphite/listing.py +51 -0
- graphite_code-0.3.0/src/graphite/llm.py +518 -0
- graphite_code-0.3.0/src/graphite/llm_probe.py +157 -0
- graphite_code-0.3.0/src/graphite/mcp.py +7 -0
- graphite_code-0.3.0/src/graphite/mcp_server.py +450 -0
- graphite_code-0.3.0/src/graphite/natural_query.py +252 -0
- graphite_code-0.3.0/src/graphite/overlays.py +713 -0
- graphite_code-0.3.0/src/graphite/probe_process.py +879 -0
- graphite_code-0.3.0/src/graphite/probe_workspace.py +728 -0
- graphite_code-0.3.0/src/graphite/process_contracts.py +22 -0
- graphite_code-0.3.0/src/graphite/provider_observer.py +397 -0
- graphite_code-0.3.0/src/graphite/query.py +646 -0
- graphite_code-0.3.0/src/graphite/query_plan.py +97 -0
- graphite_code-0.3.0/src/graphite/replacement_audit.py +291 -0
- graphite_code-0.3.0/src/graphite/resolve.py +660 -0
- graphite_code-0.3.0/src/graphite/review.py +782 -0
- graphite_code-0.3.0/src/graphite/routing/__init__.py +5 -0
- graphite_code-0.3.0/src/graphite/routing/approval.py +362 -0
- graphite_code-0.3.0/src/graphite/routing/classifier.py +169 -0
- graphite_code-0.3.0/src/graphite/routing/claude_executor.py +419 -0
- graphite_code-0.3.0/src/graphite/routing/claude_probe.py +102 -0
- graphite_code-0.3.0/src/graphite/routing/cli_identity.py +84 -0
- graphite_code-0.3.0/src/graphite/routing/codex_executor.py +383 -0
- graphite_code-0.3.0/src/graphite/routing/codex_probe.py +93 -0
- graphite_code-0.3.0/src/graphite/routing/context_builder.py +327 -0
- graphite_code-0.3.0/src/graphite/routing/contracts.py +802 -0
- graphite_code-0.3.0/src/graphite/routing/diff_policy.py +468 -0
- graphite_code-0.3.0/src/graphite/routing/edit_apply.py +166 -0
- graphite_code-0.3.0/src/graphite/routing/effort.py +43 -0
- graphite_code-0.3.0/src/graphite/routing/lifecycle.py +771 -0
- graphite_code-0.3.0/src/graphite/routing/lifecycle_operator.py +227 -0
- graphite_code-0.3.0/src/graphite/routing/lifecycle_service.py +555 -0
- graphite_code-0.3.0/src/graphite/routing/lifecycle_storage.py +977 -0
- graphite_code-0.3.0/src/graphite/routing/ollama_executor.py +341 -0
- graphite_code-0.3.0/src/graphite/routing/ollama_probe.py +72 -0
- graphite_code-0.3.0/src/graphite/routing/openrouter_executor.py +338 -0
- graphite_code-0.3.0/src/graphite/routing/openrouter_probe.py +188 -0
- graphite_code-0.3.0/src/graphite/routing/policy.py +815 -0
- graphite_code-0.3.0/src/graphite/routing/probe_runner.py +543 -0
- graphite_code-0.3.0/src/graphite/routing/process_runner.py +523 -0
- graphite_code-0.3.0/src/graphite/routing/profiles.py +554 -0
- graphite_code-0.3.0/src/graphite/routing/prompt.py +58 -0
- graphite_code-0.3.0/src/graphite/routing/registry.py +444 -0
- graphite_code-0.3.0/src/graphite/routing/route_pool.py +629 -0
- graphite_code-0.3.0/src/graphite/routing/route_pool_execution.py +275 -0
- graphite_code-0.3.0/src/graphite/routing/schema_validation.py +169 -0
- graphite_code-0.3.0/src/graphite/routing/service.py +1263 -0
- graphite_code-0.3.0/src/graphite/routing/settings.py +99 -0
- graphite_code-0.3.0/src/graphite/routing/shadow.py +201 -0
- graphite_code-0.3.0/src/graphite/routing/storage.py +4001 -0
- graphite_code-0.3.0/src/graphite/routing/telemetry.py +346 -0
- graphite_code-0.3.0/src/graphite/routing/worktree.py +259 -0
- graphite_code-0.3.0/src/graphite/routing/zai_edit.py +113 -0
- graphite_code-0.3.0/src/graphite/routing/zai_executor.py +191 -0
- graphite_code-0.3.0/src/graphite/routing/zai_probe.py +126 -0
- graphite_code-0.3.0/src/graphite/savings.py +84 -0
- graphite_code-0.3.0/src/graphite/ts_bridge.py +142 -0
- graphite_code-0.3.0/src/graphite/ts_resolver.mjs +314 -0
- graphite_code-0.3.0/src/graphite/typescript_activation.py +1586 -0
- graphite_code-0.3.0/src/graphite/usage_ledger.py +156 -0
- graphite_code-0.3.0/src/graphite/validation.py +148 -0
- graphite_code-0.3.0/src/graphite/watch.py +167 -0
- graphite_code-0.3.0/src/graphite/windows_job.py +368 -0
- graphite_code-0.3.0/src/graphite/windows_startup.py +144 -0
- graphite_code-0.3.0/src/graphite/windows_task.py +212 -0
- graphite_code-0.3.0/tests/conftest.py +146 -0
- graphite_code-0.3.0/tests/fake_clis/fake_cli.py +35 -0
- graphite_code-0.3.0/tests/fixtures/provider_lifecycle_schema_v1.sql +45 -0
- graphite_code-0.3.0/tests/fixtures/routing_schema_v2_ca77600.sql +167 -0
- graphite_code-0.3.0/tests/fixtures/routing_schema_v3_94eb333.sql +60 -0
- graphite_code-0.3.0/tests/fixtures/routing_schema_v4_lifecycle_migration.sql +72 -0
- graphite_code-0.3.0/tests/test_activation.py +164 -0
- graphite_code-0.3.0/tests/test_activation_backstop.py +150 -0
- graphite_code-0.3.0/tests/test_agent_hook_activation.py +54 -0
- graphite_code-0.3.0/tests/test_agent_hooks.py +699 -0
- graphite_code-0.3.0/tests/test_agent_settings.py +362 -0
- graphite_code-0.3.0/tests/test_answer_contract.py +487 -0
- graphite_code-0.3.0/tests/test_arrow_and_constructor_binding.py +172 -0
- graphite_code-0.3.0/tests/test_bootstrap.py +304 -0
- graphite_code-0.3.0/tests/test_build_detach.py +126 -0
- graphite_code-0.3.0/tests/test_buildlock.py +89 -0
- graphite_code-0.3.0/tests/test_cache_engine_identity.py +115 -0
- graphite_code-0.3.0/tests/test_cache_file_set.py +110 -0
- graphite_code-0.3.0/tests/test_cache_pruning.py +126 -0
- graphite_code-0.3.0/tests/test_call_graph.py +932 -0
- graphite_code-0.3.0/tests/test_channel_cli.py +95 -0
- graphite_code-0.3.0/tests/test_channel_core.py +334 -0
- graphite_code-0.3.0/tests/test_channel_lock.py +214 -0
- graphite_code-0.3.0/tests/test_channel_mcp.py +144 -0
- graphite_code-0.3.0/tests/test_channel_register.py +529 -0
- graphite_code-0.3.0/tests/test_channel_report.py +216 -0
- graphite_code-0.3.0/tests/test_channel_status.py +180 -0
- graphite_code-0.3.0/tests/test_class_field_arrow_binding.py +130 -0
- graphite_code-0.3.0/tests/test_cli_channel.py +110 -0
- graphite_code-0.3.0/tests/test_cli_version.py +283 -0
- graphite_code-0.3.0/tests/test_context.py +473 -0
- graphite_code-0.3.0/tests/test_cwd_relative_config.py +106 -0
- graphite_code-0.3.0/tests/test_daemon.py +444 -0
- graphite_code-0.3.0/tests/test_daemon_activation.py +148 -0
- graphite_code-0.3.0/tests/test_daemon_build_lock.py +83 -0
- graphite_code-0.3.0/tests/test_daemon_engine_staleness.py +129 -0
- graphite_code-0.3.0/tests/test_daemon_health.py +1040 -0
- graphite_code-0.3.0/tests/test_daemon_health_activation.py +74 -0
- graphite_code-0.3.0/tests/test_debt.py +149 -0
- graphite_code-0.3.0/tests/test_destructured_binding.py +183 -0
- graphite_code-0.3.0/tests/test_determinism.py +88 -0
- graphite_code-0.3.0/tests/test_doctor.py +4905 -0
- graphite_code-0.3.0/tests/test_doctor_agent_hooks.py +197 -0
- graphite_code-0.3.0/tests/test_doctor_hooks.py +78 -0
- graphite_code-0.3.0/tests/test_doctor_managed_docs.py +413 -0
- graphite_code-0.3.0/tests/test_documentation.py +1966 -0
- graphite_code-0.3.0/tests/test_edit_apply.py +54 -0
- graphite_code-0.3.0/tests/test_engine_identity.py +262 -0
- graphite_code-0.3.0/tests/test_external_calls.py +539 -0
- graphite_code-0.3.0/tests/test_git_security.py +929 -0
- graphite_code-0.3.0/tests/test_go_rust.py +270 -0
- graphite_code-0.3.0/tests/test_graph_io.py +213 -0
- graphite_code-0.3.0/tests/test_graph_provider_isolation.py +224 -0
- graphite_code-0.3.0/tests/test_hardening.py +1127 -0
- graphite_code-0.3.0/tests/test_health.py +793 -0
- graphite_code-0.3.0/tests/test_hook_entry.py +131 -0
- graphite_code-0.3.0/tests/test_hook_template.py +179 -0
- graphite_code-0.3.0/tests/test_hookinstall.py +173 -0
- graphite_code-0.3.0/tests/test_hookshim.py +193 -0
- graphite_code-0.3.0/tests/test_html_security.py +72 -0
- graphite_code-0.3.0/tests/test_incident_ledger.py +540 -0
- graphite_code-0.3.0/tests/test_init.py +512 -0
- graphite_code-0.3.0/tests/test_init_activation_doctrine.py +188 -0
- graphite_code-0.3.0/tests/test_init_hooks.py +111 -0
- graphite_code-0.3.0/tests/test_init_validation_exit.py +112 -0
- graphite_code-0.3.0/tests/test_lifecycle_operator.py +253 -0
- graphite_code-0.3.0/tests/test_listing.py +76 -0
- graphite_code-0.3.0/tests/test_listing_surfaces.py +207 -0
- graphite_code-0.3.0/tests/test_llm.py +445 -0
- graphite_code-0.3.0/tests/test_mcp.py +146 -0
- graphite_code-0.3.0/tests/test_monorepo.py +199 -0
- graphite_code-0.3.0/tests/test_natural_query.py +205 -0
- graphite_code-0.3.0/tests/test_overlays.py +610 -0
- graphite_code-0.3.0/tests/test_path_leak_fixture.py +57 -0
- graphite_code-0.3.0/tests/test_probe_diagnostics.py +141 -0
- graphite_code-0.3.0/tests/test_probe_workspace.py +432 -0
- graphite_code-0.3.0/tests/test_provider_claude_probe.py +165 -0
- graphite_code-0.3.0/tests/test_provider_codex_probe.py +116 -0
- graphite_code-0.3.0/tests/test_provider_lifecycle.py +659 -0
- graphite_code-0.3.0/tests/test_provider_lifecycle_service.py +455 -0
- graphite_code-0.3.0/tests/test_provider_lifecycle_storage.py +594 -0
- graphite_code-0.3.0/tests/test_provider_observer.py +371 -0
- graphite_code-0.3.0/tests/test_provider_ollama_probe.py +54 -0
- graphite_code-0.3.0/tests/test_provider_openrouter_probe.py +141 -0
- graphite_code-0.3.0/tests/test_provider_probe_runner.py +672 -0
- graphite_code-0.3.0/tests/test_public_surface.py +107 -0
- graphite_code-0.3.0/tests/test_published_schemas.py +190 -0
- graphite_code-0.3.0/tests/test_python_resolver.py +517 -0
- graphite_code-0.3.0/tests/test_query_plan.py +379 -0
- graphite_code-0.3.0/tests/test_reliability.py +153 -0
- graphite_code-0.3.0/tests/test_replacement_audit.py +173 -0
- graphite_code-0.3.0/tests/test_resolve.py +289 -0
- graphite_code-0.3.0/tests/test_review.py +1488 -0
- graphite_code-0.3.0/tests/test_route_pool.py +761 -0
- graphite_code-0.3.0/tests/test_routing_approval.py +310 -0
- graphite_code-0.3.0/tests/test_routing_benchmark.py +102 -0
- graphite_code-0.3.0/tests/test_routing_classifier.py +105 -0
- graphite_code-0.3.0/tests/test_routing_claude_executor.py +631 -0
- graphite_code-0.3.0/tests/test_routing_cli.py +435 -0
- graphite_code-0.3.0/tests/test_routing_cli_contracts.py +155 -0
- graphite_code-0.3.0/tests/test_routing_cli_recovery.py +283 -0
- graphite_code-0.3.0/tests/test_routing_codex_executor.py +702 -0
- graphite_code-0.3.0/tests/test_routing_context.py +123 -0
- graphite_code-0.3.0/tests/test_routing_contracts.py +246 -0
- graphite_code-0.3.0/tests/test_routing_diff_policy.py +246 -0
- graphite_code-0.3.0/tests/test_routing_executor.py +366 -0
- graphite_code-0.3.0/tests/test_routing_openrouter_executor.py +621 -0
- graphite_code-0.3.0/tests/test_routing_policy.py +742 -0
- graphite_code-0.3.0/tests/test_routing_process_runner.py +695 -0
- graphite_code-0.3.0/tests/test_routing_profiles.py +685 -0
- graphite_code-0.3.0/tests/test_routing_registry.py +327 -0
- graphite_code-0.3.0/tests/test_routing_schema_validation.py +180 -0
- graphite_code-0.3.0/tests/test_routing_security.py +125 -0
- graphite_code-0.3.0/tests/test_routing_service.py +469 -0
- graphite_code-0.3.0/tests/test_routing_shadow.py +157 -0
- graphite_code-0.3.0/tests/test_routing_storage.py +2408 -0
- graphite_code-0.3.0/tests/test_routing_telemetry.py +249 -0
- graphite_code-0.3.0/tests/test_routing_worktree.py +229 -0
- graphite_code-0.3.0/tests/test_routing_zai_executor.py +151 -0
- graphite_code-0.3.0/tests/test_routing_zai_probe.py +29 -0
- graphite_code-0.3.0/tests/test_savings.py +162 -0
- graphite_code-0.3.0/tests/test_search.py +192 -0
- graphite_code-0.3.0/tests/test_smoke.py +40 -0
- graphite_code-0.3.0/tests/test_typescript_activation.py +6525 -0
- graphite_code-0.3.0/tests/test_typescript_resolver.py +274 -0
- graphite_code-0.3.0/tests/test_usage_ledger.py +160 -0
- graphite_code-0.3.0/tests/test_verify_artifact.py +141 -0
- graphite_code-0.3.0/tests/test_watch.py +159 -0
- graphite_code-0.3.0/tests/test_windows_startup.py +69 -0
- graphite_code-0.3.0/tests/test_windows_task.py +108 -0
- graphite_code-0.3.0/tests/test_zai_edit.py +154 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Graphite artifacts (this tool graphs itself via the supervising daemon).
|
|
2
|
+
# No developer-machine paths here: hatchling ships .gitignore inside the sdist,
|
|
3
|
+
# so anything written in this file is published.
|
|
4
|
+
graph-out/
|
|
5
|
+
**/.cache/graphite/
|
|
6
|
+
**/.graphite/
|
|
7
|
+
.graphite-daemon/
|
|
8
|
+
|
|
9
|
+
# Python
|
|
10
|
+
__pycache__/
|
|
11
|
+
*.py[cod]
|
|
12
|
+
*.egg-info/
|
|
13
|
+
.pytest_cache/
|
|
14
|
+
.ruff_cache/
|
|
15
|
+
dist/
|
|
16
|
+
.venv/
|
|
17
|
+
.worktrees/
|
|
18
|
+
|
|
19
|
+
# Subagent-driven-development scratch (ledgers, briefs, review packages)
|
|
20
|
+
.superpowers/
|
|
21
|
+
.aramid/
|
|
22
|
+
.graphite*
|
|
23
|
+
.cache/
|
|
24
|
+
|
|
25
|
+
.githooks/
|
|
26
|
+
|
|
27
|
+
# Coverage data, written by `pytest --cov`. The report is a measurement, not an
|
|
28
|
+
# artifact: regenerate it rather than committing a snapshot that goes stale.
|
|
29
|
+
.coverage
|
|
30
|
+
coverage.xml
|
|
31
|
+
htmlcov/
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
# Graphite architecture
|
|
2
|
+
|
|
3
|
+
This guide describes the current internal architecture and the constraints contributors must preserve. Graphite targets Python 3.11+, runs locally, and does not require a model provider. Its core graph facts and ordering are reproducible when the Graphite version, Tree-sitter/parser packages, Node/TypeScript toolchain, configuration, and resolver mode/outcome are fixed; optional tool availability or version differences can change extraction or resolution across hosts. Repository data, external processes, generated artifacts, and model input/output are trust boundaries rather than trusted implementation details.
|
|
4
|
+
|
|
5
|
+
## System context
|
|
6
|
+
|
|
7
|
+
Graphite is a local Python application. The public CLI is `graphite`, or equivalently `python -m graphite`, with command handling in `src/graphite/cli.py`. The optional `graphite-mcp` entry point in `src/graphite/mcp_server.py` exposes selected operations through MCP. Both are adapters over the same core modules; they are not alternative graph implementations.
|
|
8
|
+
|
|
9
|
+
Every canonical build is local-first and inference-free. It scans a repository, extracts structural facts, constructs and analyzes a directed graph, validates the public bundle, and writes local artifacts. Canonical operations force a scrubbed configuration, do not read provider credentials, and have no model-provider dependency. `src/graphite/llm.py` is reserved for the separate explicit overlay pipeline.
|
|
10
|
+
|
|
11
|
+
## Processing pipeline
|
|
12
|
+
|
|
13
|
+
```text
|
|
14
|
+
repository input
|
|
15
|
+
-> collect and classify files
|
|
16
|
+
-> parse and extract symbols/imports/calls
|
|
17
|
+
-> resolve cross-file identities
|
|
18
|
+
-> construct and analyze the directed graph
|
|
19
|
+
-> validate the bundle and render artifacts
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
The implementation stages are:
|
|
23
|
+
|
|
24
|
+
1. **Collection — `ingest.py`, `config.py`, `git.py`.** Configuration establishes file-count and file-size limits and the cache and output locations. Ingestion normalizes project-relative paths, resolves candidates beneath the repository root, skips unsafe or ineligible files, and sorts accepted entries. Git-backed enumeration uses `GitRunner` with a trusted executable outside the repository, an argument vector, no shell, a filtered Git environment, a timeout, and a stdout cap. The filesystem fallback is also capped by configured file limits, but it does not provide every process control because no child process is involved.
|
|
25
|
+
2. **Extraction — `extract/ast.py`, `cache.py`, `ts_bridge.py`, `ts_resolver.mjs`.** Per-language Tree-sitter extractors handle JavaScript/TypeScript, Python, Go, and Rust, while unsupported or unavailable parsers degrade to a file-level record. Extraction emits symbols, imports, calls, and containment edges in deterministic order. The content-addressed cache avoids repeated AST work. TypeScript/JavaScript may additionally use the Node compiler bridge for compiler-backed module resolution; bridge failure falls back to heuristic resolution rather than making Node mandatory.
|
|
26
|
+
3. **Resolution — `resolve.py`.** `SourceIndex` builds the set of normalized, project-relative source identities, reads TypeScript aliases and workspace package entry points, prefers compiler-backed TypeScript results when available, and otherwise applies bounded heuristics. Global merge logic also resolves supported call identities and deterministically removes duplicates.
|
|
27
|
+
4. **Graph and analysis — `graph.py`, `cluster.py`, `analyze.py`, `query.py`.** `graph.py` constructs a NetworkX `DiGraph` after sorting nodes and edges and normalizing IDs. Analysis filters to project nodes where appropriate and returns bounded, ordered results. Community detection constructs a deterministic undirected view and uses the configured seed (42 by default). JSON conversion preserves the graph's deterministic insertion order.
|
|
28
|
+
5. **Validation and review — `validation.py`, `context.py`, `review.py`.** Bundle validation checks structural types, node and edge identity, referential integrity, metadata counts, and unsafe `source_file` paths. Review validates a supplied bundle before deriving graph impact evidence; its Git discovery also normalizes status records and rejects malformed or unsafe paths. By contrast, `cmd_query`, `cmd_impact`, `cmd_context`, and `GraphiteMCPServer._load` currently read JSON and call `graph_from_json` without `validate_graph_bundle` or a bounded-read helper. Those direct consumers therefore rely on callers to supply an already validated, reasonably sized artifact.
|
|
29
|
+
6. **Export — `export/json.py`, `export/md.py`, `export/html.py`, `io.py`.** Exporters consume only canonical graph, cluster, analysis, and manifest data. JSON serialization provides the data encoding; HTML separately JSON-encodes script data, escapes `<`, `>`, and `&`, HTML-escapes the title, and uses text DOM APIs for runtime labels. Text and JSON outputs use temporary files, `fsync`, and `os.replace` for atomic replacement of each file.
|
|
30
|
+
7. **Operations — `watch.py`, `daemon.py`, `daemon_health.py`, `bootstrap.py`, `init.py`, `windows_task.py`, `windows_startup.py`.** These modules watch for changes, maintain multi-project daemon status, evaluate health, generate integration instructions, and manage platform startup. Watch and daemon canonicalize inherited configuration; daemon child builds use fixed `--llm none` argv and a provider-scrubbed environment.
|
|
31
|
+
8. **Provider lifecycle — `routing/lifecycle.py`, `routing/lifecycle_storage.py`, `routing/lifecycle_service.py`, and `routing/lifecycle_operator.py`.** Runtime observations, compatibility decisions, lifecycle authority, and invalidations live in an isolated database. Operator reads use an existing-database, query-only connection and bounded public records. Policy and verification preparation create non-activating content-hashed candidates; neither surface invokes a provider.
|
|
32
|
+
9. **Optional overlays — `overlays.py` and `llm.py`.** Provider adapters may consume an already-built, fresh, validated graph only through `graphite overlay build`. The overlay manifest binds the canonical bundle fingerprint, exact lifecycle/model/routing identities, limits, creation time, outcome, and schema. Identity-derived contained paths, restrictive permissions, content-addressed payloads, and manifest-last atomic replacement isolate the output below `graph-out/overlays/`. Overlay staleness is independent of canonical freshness and cannot grant graph or routing authority.
|
|
33
|
+
|
|
34
|
+
## Module map
|
|
35
|
+
|
|
36
|
+
| Area | Primary modules | Responsibility | May depend on |
|
|
37
|
+
| --- | --- | --- | --- |
|
|
38
|
+
| Entry adapters | `cli.py`, `mcp.py`, `mcp_server.py`, `__main__.py` | Parse user/tool input, select operations, format responses | Core, validation, exporters, operations |
|
|
39
|
+
| Configuration and ingestion | `config.py`, `ingest.py`, `git.py` | Establish limits; discover, contain, classify, and hash repository files | Cache hashing and bounded process adapter |
|
|
40
|
+
| Extraction and resolution | `extract/ast.py`, `cache.py`, `resolve.py`, `ts_bridge.py`, `ts_resolver.mjs` | Parse language structures and resolve project identities | Ingestion contracts, configuration, optional Node/TypeScript process |
|
|
41
|
+
| Graph and analysis | `graph.py`, `cluster.py`, `analyze.py`, `query.py` | Build, cluster, analyze, and query the directed graph | NetworkX and deterministic extracted structures |
|
|
42
|
+
| Validation and evidence | `validation.py`, `context.py`, `review.py` | Validate bundles and derive review/context evidence | Graph structures; review may use the Git adapter |
|
|
43
|
+
| Export | `export/json.py`, `export/md.py`, `export/html.py`, `io.py` | Encode and atomically replace individual artifacts | Validated graph, analysis, clusters, manifest |
|
|
44
|
+
| Optional model overlays | `overlays.py`, `llm.py` | Validate identity and canonical freshness; produce fingerprint-bound, non-authoritative annotations outside canonical artifacts | Existing canonical graph, explicit provider configuration, network only when separately authorized |
|
|
45
|
+
| Operations and integration | `watch.py`, `daemon.py`, `daemon_health.py`, `bootstrap.py`, `init.py`, `windows_task.py`, `windows_startup.py` | Freshness, daemon health, generated instructions, and OS startup | Public core operations and explicit platform/process boundaries |
|
|
46
|
+
|
|
47
|
+
The intended dependency direction is observable in current imports but is not enforced by a dedicated architecture linter. CLI and MCP adapt inputs; portable core modules do not import those UI entry points. Export consumes canonical graph and analysis data; extraction does not depend on exporters. Canonical graph construction, validation, and read operations do not depend on model providers. Windows startup and task management remain outside the portable core. External execution crosses explicit subprocess boundaries; Git uses the hardened `GitRunner`, while the TypeScript and Windows adapters have their own, not necessarily identical, controls. Contributors must preserve these directions and add tests if a boundary becomes mechanically important.
|
|
48
|
+
|
|
49
|
+
## Trust boundaries
|
|
50
|
+
|
|
51
|
+
### Doctor and deep-probe boundary
|
|
52
|
+
|
|
53
|
+
Fast checks are read-only with respect to the selected repository. They inspect the supported Python runtime, bounded Git enumeration, graph validity, daemon health, and static configuration or package availability. Missing MCP, TypeScript, daemon registration, or model configuration is an optional state; optional states do not block core graph operation. Only a `blocked` aggregate crosses the command's non-zero exit boundary.
|
|
54
|
+
|
|
55
|
+
The deep deterministic pipeline creates a synthetic repository in an external private temporary workspace and never writes to the selected root or loads or executes its code. On Windows, the normal lease parent and workspace directories are created with a protected, inheritable current-user DACL; the inheritable ACE applies to their children. This is a creation-time security-descriptor guarantee, not a claim that the DACL is re-read during each phase.
|
|
56
|
+
|
|
57
|
+
Canonical containment, pinned directory handles, reparse state, directory identity, and path bindings are validated before and after each synchronous phase. Subprocesses cross a separate hostile boundary with bounded stdin/stdout/stderr, one shared deadline, disabled shell execution, and native process containment: Windows Job Objects or POSIX process groups contain descendants. Cleanup coordination reserves part of the same deadline, revalidates the lease before deletion, and gives one bounded cleanup worker sole ownership. A cleanup timeout blocks the result and prevents another core probe in the same interpreter/process from racing the live lease until cleanup completes. The coordinator is process-local and does not claim cross-process exclusion.
|
|
58
|
+
|
|
59
|
+
These controls do not provide an OS sandbox. The local user and same-user process namespace remain a best effort boundary: another malicious process with the same authority may still interfere, so uncertain workspace bindings are leaked rather than deleted by pathname.
|
|
60
|
+
|
|
61
|
+
The MCP probe starts an isolated interpreter from a guarded distribution-record import manifest. It rejects current-directory, user-site, and attacker-controlled selected-root shadows and validates expected Graphite and MCP module origins before protocol startup. The exact origin-verified trusted Graphite source may be inside the selected repository, but it is accepted only when its expected lexical, canonical, filesystem-identity, and module-origin checks all match. MCP dependency roots, distribution metadata, package origins, and alternate Graphite origins that overlap the selected root remain rejected. The TypeScript probe is static no-exec detection: it reads package metadata through externally resolved Node but does not load, execute, or transpile project-controlled JavaScript, so detection stays optional/unverified.
|
|
62
|
+
|
|
63
|
+
The LLM path is an explicit subprocess and model trust boundary. `--include-llm` sends synthetic content only through an isolated bounded worker: one constant request, a hard 64 KiB HTTP response cap, redirects disabled, no retries, sanitized category-only failure, and no response body in the doctor report. Configured output-token bounds are normalized to 1–4096 with a default of 512, while the doctor probe forces 16. There is no repository data or model context carried between roots or tenants, preventing repository/model cross-contamination in this probe. Provider output cannot affect deterministic graph facts, validation, authorization, or core readiness.
|
|
64
|
+
|
|
65
|
+
The daemon-status path preserves bounded parse, schema, and output contracts. Input is size-limited before strict UTF-8 JSON parsing; health classification accepts only expected structures; doctor output exposes fixed booleans and counts rather than raw status, errors, process output, or paths.
|
|
66
|
+
|
|
67
|
+
## Consent-gated TypeScript activation boundary
|
|
68
|
+
|
|
69
|
+
`typescript_activation.py` owns evidence detection, prompt eligibility, lifecycle orchestration, revalidation, typed sanitized outcomes, and the process-local canonical-root lock. `dependency_install.py` owns manager adapters, exact argv, executable and validator provenance, registry/configuration isolation, source-policy checks, and post-install project-local detection. `cli.py` may call the activation entry point only from the single onboarding helper used by top-level `cmd_init` and `cmd_bootstrap`; build, report, check, doctor, daemon, watch, and MCP have no installation authority.
|
|
70
|
+
|
|
71
|
+
The lifecycle order is part of the public contract. Existing init/bootstrap writes complete first, activation runs second, and the requested build/validation stages then continue. `installed`, `already_available`, `not_applicable`, `declined`, and `guidance_only` preserve normal success semantics. `validation_failed`, `installation_failed`, and `verification_failed` are fatal activation outcomes: the overall command returns 1 while completed onboarding files and any reviewable package-manager changes remain preserved. There is no automatic rollback because Graphite cannot safely distinguish its writes from concurrent user or manager writes.
|
|
72
|
+
|
|
73
|
+
Automatic mutation is available only after bounded contained evidence, one unambiguous supported root lockfile, compatible `package.json#packageManager`, safe manifest/lock sources, absent manager override files, a supported external manager version, interactive default-No consent, and successful exact-package validation. The automatic adapters are npm 8–11, pnpm 11, and Bun 1. Yarn remains `guidance_only`. The validator must be an absolute regular file outside the selected root, runs through trusted external Node with only `typescript`, and is revalidated before use. The package manager is likewise external and revalidated immediately before launch. On POSIX, manager resolution permits only a bounded external symlink-launcher route while argv retains the lexical manager name required by Corepack-style dispatch. Immutable provenance covers every root-to-leaf directory/component binding used by the launcher and its symlink targets, including component identity, ownership, mode, and symlink target text, and the complete route is revalidated before version and install launches. A bounded prefix captured during the pinned-file read classifies the final target: exact `#!/usr/bin/env node`, `#!/usr/bin/node`, or `#!/bin/node` scripts execute only as canonical trusted-Node plus lexical-launcher argv, while recognized ELF/Mach-O managers such as Bun execute directly; ambiguous or unsupported interpreters fail closed to guidance. Both Node and the complete launcher route are revalidated immediately before version and install, and child `PATH` is never used to select Node. Root- or current-user-owned sticky directories such as the canonical temporary directory are allowed only when sticky semantics and trusted child ownership prevent cross-user replacement; group/world-writable non-sticky ancestors fail closed. Cycles, dangling or excessive routes, selected-root crossings, unsafe ownership, and component, chain, interpreter, or target replacement also fail closed. Directory-component symlinks such as `/tmp`-style canonical redirects use the same provenance policy rather than a pathname exception. Validator and control-file symlink rules remain strict, as does Windows executable resolution. A same-UID process may still race the final path-based OS launch after revalidation; that existing local-user trust limitation is not presented as cross-process isolation.
|
|
74
|
+
|
|
75
|
+
The automatic process boundary uses fixed argv with `shell=False`, closed stdin, lifecycle/build scripts disabled, a minimal allowlisted environment, isolated manager configuration/home, the canonical `https://registry.npmjs.org/`, stripped ambient registry tokens, bounded output, native descendant containment, and one shared deadline across validation, install, verification, and cleanup. Private registries and mirrors deliberately remain outside this unattended trust boundary and use the fixed manual workflow under operator policy.
|
|
76
|
+
|
|
77
|
+
Manifest and lockfile identities and hashes are captured before mutation and rechecked. TypeScript activation results expose only fixed outcomes, reason codes, manager names, and relative changed control-file paths. That activation result boundary includes neither credentials, raw process output, registry responses, absolute host paths, nor repository source; it is not a claim about every unrelated Graphite command or artifact. The lock excludes concurrent activation only within the current process; other editors and package managers remain possible failure domains.
|
|
78
|
+
|
|
79
|
+
On POSIX, descriptor-relative cleanup can safely empty an isolated directory but cannot atomically unlink its open root by descriptor. The cleanup worker may therefore intentionally retain an empty temporary root for operating-system temporary-directory reclamation rather than race a same-user pathname replacement. Operators may remove a confirmed stale empty root under their normal temporary-directory policy, but Graphite will not delete it by an unsafe inspect-then-remove sequence.
|
|
80
|
+
|
|
81
|
+
These controls provide prevention, containment, detection, and recoverable evidence; they do not provide an OS sandbox and do not make Graphite unhackable. The local user, same-user process namespace, manager implementation, canonical registry, trusted Node/validator, and operating system remain explicit trust boundaries.
|
|
82
|
+
|
|
83
|
+
**Repository input.**
|
|
84
|
+
|
|
85
|
+
Treat paths, bytes, symlinks, encodings, file counts, and file sizes as hostile. Current ingestion resolves roots and candidates, requires candidates to remain below the root, rejects unsafe Git paths, skips unreadable/binary/oversized files, applies configured count bounds, and records normalized project-relative paths. Extraction reads bytes and degrades or reports parse/read errors. New readers must use the same containment model; never trust a repository string as an absolute destination or executable.
|
|
86
|
+
|
|
87
|
+
**Process boundary.**
|
|
88
|
+
|
|
89
|
+
Git, Node/TypeScript, and Windows task/startup integrations execute outside Python. `GitRunner` is the strongest current adapter: fixed executable discovery outside the repository, argv execution with `shell=False`, disabled stdin/stderr, filtered `GIT_*` environment, timeout, stdout cap, and typed sanitized failures. The TypeScript bridge uses argv, `subprocess.run`, captured output, a configured timeout, and a 500-character diagnostic cap, but it currently inherits the environment and does not impose an explicit output-byte cap. Windows adapters are platform-specific and must be reviewed on their own controls. Do not generalize Git's isolation guarantees to every subprocess.
|
|
90
|
+
|
|
91
|
+
**Artifact and browser boundary.**
|
|
92
|
+
|
|
93
|
+
Repository-controlled names and strings remain untrusted when rendered. The normal build validates the public graph and rejects absolute or parent-traversing node/edge `source_file` values before export. The direct query, impact, context, and MCP load paths do not currently validate or bound the JSON read, which is a known hardening gap; do not treat their present behavior as a trust guarantee. JSON must be serialized, HTML script data must receive script-context escaping, visible browser values must use HTML escaping or text DOM APIs, and public artifacts must not introduce absolute system paths. `io.py` atomically replaces each completed file. The report set is written as several files rather than one filesystem transaction, so readers must validate the bundle and consult manifest/freshness state instead of assuming a directory snapshot is complete.
|
|
94
|
+
|
|
95
|
+
**Model and network boundary.**
|
|
96
|
+
|
|
97
|
+
Model use is disabled by default and requires the explicit overlay command; no vendor is required by the core. Current adapters use request timeouts, cap prompt characters and output tokens, apply the hard 64 KiB bound to successful and HTTP-error response reads, and disable redirects. Failure persistence accepts only fixed categories and never raw provider diagnostics. Provider output is untrusted annotation text stored only in a non-authoritative overlay: it must not become graph facts, execute tools, approve validation, authorize release, or cross tenant/repository contexts. Prompts contain bounded graph metrics rather than repository source.
|
|
98
|
+
|
|
99
|
+
### Adaptive router authority and audit boundary
|
|
100
|
+
|
|
101
|
+
`routing.registry.BUNDLED_PROFILES` is the immutable authority allowlist; the bounded cached Ollama inventory establishes availability only. Inventory presence does not authorize a model. Unknown identifiers, aliases, missing profiles, stale inventories, and exact-digest mismatches fail closed. Lifecycle eligibility enforces the 30-day minimum retirement runway: a dated retirement must be strictly more than 30 days after the evaluation date. Capability and context requirements, data policy, risk, default-only effort support, and the configured request/repository budget are ranking hard gates before deterministic role and provider-reported usage class ranking. A recommendation does not prove quota remains: actual repository and machine quota reservation happens atomically during approval consumption. Usage class is coarse provider metadata, not a USD price or measured saving.
|
|
102
|
+
|
|
103
|
+
The active provisional pool comprises `kimi-k2.7-code:cloud` for primary coding at high usage, `minimax-m2.7:cloud` for coding and agentic work at medium usage, `nemotron-3-super:cloud` for reasoning and review at medium usage, and `minimax-m3:cloud` for long-context and agentic work at high usage. All four accept only `default` effort. Provisional profiles are ineligible for high-risk tasks, which produce a manual frontier handoff rather than weakening a gate.
|
|
104
|
+
|
|
105
|
+
The execution authority binds one signed, short-lived, single-use approval to the exact model and inventory digest, effort, graph/context manifest, input and output limits, and quota reservation. Runtime independently revalidates the signed digest before approval consumption and the provider process. There is no retry or arbitrary substitution. One automatic cross-provider advance is permitted only when the same immutable approved pool contains exactly two eligible candidates and the first fails as `capacity_unavailable` before output or side effects; the second consumes its own exact authority. Non-TTY input or output, JSON mode, CI, and `--yes` are incapable of granting execution authority.
|
|
106
|
+
|
|
107
|
+
Lifecycle transitions never grant graph authority. `discovered`, `compatible`, `verification_required`, `active`, `incompatible`, and `unavailable` are persisted separately from graph artifacts. Hash/patch changes require a standard probe, minor/capability changes require an expanded probe, and major changes remain incompatible pending a separately authorized policy promotion. A successful probe reaches only `verification_required`; exact bounded verification is still required before activation. Daemon observation is advisory for scheduling and health, while the lazy identity check immediately before approval consumption is authoritative. One corrupt or unavailable provider boundary fails closed without changing canonical graph behavior or another provider's independent boundary.
|
|
108
|
+
|
|
109
|
+
Provider text crosses only the interactive display boundary. The CLI escapes terminal controls and delimiter impersonation, frames every line, and keeps the text ephemeral. Persistence contains the validated receipt, hashes, bindings, and bounded audit metadata, never the displayed text. A new attempt is durably recorded as `pending`; successful receipt finalization transactionally creates the execution, receipt, evidence, budget link, and `completed` transition.
|
|
110
|
+
|
|
111
|
+
If that final transaction fails after the single provider call, the service attempts to stage the validated receipt and marks the attempt `persistence_failed`. The attempt is reconcilable only while that staged state remains intact and available. `graphite route recoverable <root> --limit 50 --json` exposes only a bounded, deterministically ordered page of validated attempt IDs/status; `next_cursor` can be supplied with `--after` when `has_more` is true. `graphite route reconcile <root> --attempt-id <id> --json` transactionally performs the missing finalization with a sanitized receipt and without a provider call or approval issue, consumption, or reuse. Expected recovery validation/storage failures cross a dedicated allowlisted CLI boundary: JSON mode emits only a stable error code object and text mode emits a fixed path-free code. Operators should preserve or back up routing state before repair. If storage is unavailable for normal finalization and fallback staging, or staged state is deleted, corrupted, or lost with the disk, reconciliation is unavailable.
|
|
112
|
+
|
|
113
|
+
The schema-v3 migration deliberately maps schema-v1 `pending` and `persistence_failed` attempts that lack token and request-hash bindings to `legacy_unrecoverable` with `legacy_attempt_bindings_missing`. It separately maps schema-v2 nonterminal attempts that have those bindings but predate durable inventory-digest binding to `legacy_unrecoverable` with `legacy_attempt_digest_missing`. Both classes are quarantined and never replayed. Legacy `completed` rows remain intentionally preserved as read-only history. They are not reclassified as recoverable and are not rewritten to manufacture stronger evidence than the earlier schema recorded. New attempts and staged receipts persist the lowercase 64-hex digest from the signed approval manifest; finalization and reconciliation require an exact match.
|
|
114
|
+
|
|
115
|
+
## Artifacts and state
|
|
116
|
+
|
|
117
|
+
A build produces `graph.json`, `graph.html`, and `GRAPH_REPORT.md` in the configurable output directory (`graph-out` by default), plus internal `.graphite_manifest.json`, `.graphite_graph.json`, `.graphite_clusters.json`, `.graphite_analysis.json`, and `.graphite_validation.json` there. The manifest records scanned project-relative file paths and hashes; `graphite check` compares it with a new scan to report added, changed, and removed files. Explicit model annotations live separately under `graph-out/overlays/<provider>/<identity-digest>/`; canonical readers never load that tree. Extraction cache entries live under the configured cache directory (`.cache/graphite` by default) and are keyed by version and content-derived hashes. The daemon writes atomic status JSON under its state directory. Initialization/bootstrap may generate or update platform instruction files such as `GRAPHITE.md` and supported assistant integration files.
|
|
118
|
+
|
|
119
|
+
Current code sorts collection, extraction merge, graph construction, community members, and most query/review outputs; validates the public bundle before the normal report path publishes it; rejects unsafe public `source_file` paths on that path; and atomically replaces individual files where `io.py` is used. Cache writes are deterministic JSON but are not routed through the atomic helper. Multi-file report publication is not transactional. Direct query, impact, context, and MCP consumers neither validate the bundle nor bound their JSON read today.
|
|
120
|
+
|
|
121
|
+
Contributor invariants are stricter: artifact identities and repository paths stay normalized and project-relative; output ordering is stable; externally consumed structures are schema/invariant validated before use; incomplete or invalid bundles are rejected rather than silently accepted; and files are atomically replaced wherever interruption could expose partial content. If a new artifact set requires all-or-nothing consistency, add generation IDs or a commit/manifest protocol instead of assuming per-file atomic writes provide it.
|
|
122
|
+
|
|
123
|
+
## Failure behavior
|
|
124
|
+
|
|
125
|
+
- Escaping, absolute, symlink-resolved-outside-root, malformed Git, unreadable, binary, and oversized repository inputs are rejected or skipped according to the ingestion contract. Enumeration failures that prevent a trustworthy scan raise `IngestError`; individual unreadable files may be skipped or represented as extraction errors.
|
|
126
|
+
- `validate_graph_bundle` returns structured errors for malformed bundles, and the normal report path uses `assert_valid_graph_bundle` so an invalid public bundle fails before public exporters run. The standalone validate command exits non-zero on invalid JSON or failed validation. The query, impact, context, and MCP direct-load paths do not invoke validation or bound the read; callers are responsible for validating and constraining artifacts before those paths consume them until that gap is closed.
|
|
127
|
+
- Git failures use typed, sanitized exceptions with fixed messages. Other subprocess adapters currently return bounded diagnostic reasons or platform-specific errors; they do not all share Git's typed exception hierarchy, environment isolation, or output cap.
|
|
128
|
+
- Atomic replacement prevents a partially written individual artifact from being accepted at its final path. It does not make the entire report directory transactional; consumers must reject invalid bundles and use freshness/manifest evidence to detect stale or mixed state.
|
|
129
|
+
- Provider absence, drift, incompatibility, credential failure, or overlay failure cannot block or alter canonical graph construction, validation, reads, or export. Model output never supplies graph, validation, routing, or release authority.
|
|
130
|
+
- Overlay success publishes a content-addressed payload before atomically replacing its manifest. Failure preserves the last valid manifest and payload and writes only a separate sanitized category marker. Canonical graph or identity drift marks an overlay stale without making the graph stale.
|
|
131
|
+
|
|
132
|
+
## Extension points and invariants
|
|
133
|
+
|
|
134
|
+
**Languages.** Extend classification in `ingest.py`, add the Tree-sitter extractor and resolver behavior, and add fixtures/tests for symbols, imports, calls, malformed input, path containment, cross-file identity, and deterministic output. A language implementation must degrade safely when its parser or optional compiler is unavailable.
|
|
135
|
+
|
|
136
|
+
**Exporters.** Consume validated structures, encode for the exact destination context, write through atomic helpers, and exclude absolute paths, environment metadata, credentials, and other host-identifying state. Add hostile-string and interrupted-write tests.
|
|
137
|
+
|
|
138
|
+
**Query and analysis.** Preserve deterministic tie-breaking and ordering, bound result sizes and graph traversal, filter project nodes where the operation promises project-only evidence, and keep machine-readable JSON contracts stable.
|
|
139
|
+
|
|
140
|
+
**Model adapters.** Implement the provider protocol outside graph construction. Require explicit configuration, deadlines, bounded input/output, sanitized failures, and deterministic fakes in tests. Treat responses as untrusted annotations and never allow a model provider to change graph facts or validation results.
|
|
141
|
+
|
|
142
|
+
**Process adapters.** Use argv rather than shell interpolation, define time and output/resource bounds, return typed or safely structured failures, sanitize diagnostics, and isolate platform-specific behavior from the portable core. Environment inheritance must be a deliberate, documented choice.
|
|
143
|
+
|
|
144
|
+
Across all extensions, preserve these invariants:
|
|
145
|
+
|
|
146
|
+
- The core works with zero LLM or network access.
|
|
147
|
+
- Identical repository input and deterministic-core configuration produce the same graph facts and ordering only under a fixed Graphite version, Tree-sitter/parser package set, Node/TypeScript toolchain, and resolver mode/outcome. Parser availability changes whether structural or generic extraction runs, while `typescript_resolver=auto` may select compiler-backed resolution on one host and heuristics on another. Use heuristic or disabled TypeScript resolution when the compiler toolchain and cross-host resolver outcome cannot be controlled. Timestamps, random host state, and concurrency completion order must not otherwise affect core facts. Optional probabilistic model annotations are outside this guarantee and must never alter graph facts.
|
|
148
|
+
- Repository identities and public source paths are normalized and project-relative.
|
|
149
|
+
- Artifacts and logs contain no secrets, absolute system paths, or unnecessary environment metadata.
|
|
150
|
+
- Contributor target invariant (not universal current behavior): validate and size-bound untrusted structures before consumption; model text is never validation evidence.
|
|
151
|
+
- Public schemas and CLI behavior remain compatible unless an explicit, tested migration is provided.
|
|
152
|
+
# Adaptive routing trust boundary
|
|
153
|
+
|
|
154
|
+
The development router is an approval-gated change broker for two authenticated
|
|
155
|
+
subscription CLIs: Claude Code and Codex. Ollama is excluded from governed
|
|
156
|
+
development execution; OpenRouter remains reserved for in-application inference.
|
|
157
|
+
Trust zones are the source repository and validated graph, detached task worktrees,
|
|
158
|
+
the provider CLI process and its existing credential home, repository-local audit
|
|
159
|
+
storage, and machine-local signing state. Graphite neither reads API keys nor copies
|
|
160
|
+
subscription credentials into prompts, telemetry, child arguments, or storage.
|
|
161
|
+
|
|
162
|
+
The authority sequence is capability verification -> deterministic recommendation
|
|
163
|
+
-> detached worktree -> canonical prompt and manifest -> default-No single-use
|
|
164
|
+
approval -> CLI identity recheck -> one bounded process -> diff inspection ->
|
|
165
|
+
credential-free validation -> human accept/reject -> optional explicit cleanup.
|
|
166
|
+
Each transition binds the repository commit, capability snapshot, requested and
|
|
167
|
+
effective model, effort, executable hash/version, adapter protocol, permission
|
|
168
|
+
mode, prompt hash, token reservation, and timeout. No later stage can widen an
|
|
169
|
+
earlier permission. Worktree, approval, attempt, validation, and review identities
|
|
170
|
+
are immutable database evidence.
|
|
171
|
+
|
|
172
|
+
Capability verification reports actual input and output usage. The profile boundary
|
|
173
|
+
validates both values against the approved limits before constructing and saving
|
|
174
|
+
active authority. Invalid, missing, or over-budget usage cannot produce a persisted
|
|
175
|
+
snapshot; acceptance tooling uses the ordered verify-and-save operation rather than
|
|
176
|
+
an independently ordered persistence step.
|
|
177
|
+
|
|
178
|
+
Claude capability verification uses the CLI's vendor-documented `--json-schema`
|
|
179
|
+
contract with `--max-turns 1`. The terminal structured object must equal the fixed
|
|
180
|
+
verification payload, every assistant event must retain the expected model identity,
|
|
181
|
+
and usage must pass the approved bounds. Free text, missing or additional fields,
|
|
182
|
+
schema drift, and multi-turn completion fail closed. This constrained mode is not
|
|
183
|
+
used for ordinary development execution.
|
|
184
|
+
|
|
185
|
+
Provider output and edits are untrusted. The diff boundary rejects filesystem
|
|
186
|
+
indirection, repository nesting, submodule changes, case collisions, scope or size
|
|
187
|
+
violations, and source/diff drift. High-risk tasks require a separately approved
|
|
188
|
+
read-only review by the other provider. Acceptance produces only a detached commit;
|
|
189
|
+
it never merges. Retry, arbitrary provider switching, session reuse, cleanup, and
|
|
190
|
+
merge are never automatic. The only fallback is the pre-authorized, one-step,
|
|
191
|
+
capacity-only route-pool transition described above.
|
|
192
|
+
|
|
193
|
+
Telemetry has a closed typed schema and excludes source, prompt/response text, diff
|
|
194
|
+
contents, paths, secrets, and raw diagnostics. Subscription cost remains `unknown`.
|
|
195
|
+
Recency weighting and Wilson confidence penalties can propose a signed policy
|
|
196
|
+
candidate. Candidate creation grants no authority. Interactive promotion cannot
|
|
197
|
+
alter provider allowlists, permission ceilings, risk ceilings, or autonomy; rollback
|
|
198
|
+
appends an activation event and retains all prior evidence.
|
|
199
|
+
|
|
200
|
+
Schema v5 is a forward cutover. Before changing a v4 routing database, Graphite
|
|
201
|
+
creates a private `events-schema-v4.sqlite3` backup and SHA-256 marker, validates
|
|
202
|
+
schema, integrity, and foreign keys, then adds lifecycle bindings without inventing
|
|
203
|
+
authority for historical rows. Rollback requires stopped writers, verified backup
|
|
204
|
+
restore, and the matching v4 code; v5 is not edited into v4. A partial schema,
|
|
205
|
+
missing marker, lock, or failed integrity check leaves routing stopped for verified
|
|
206
|
+
restore or a tested forward fix.
|