This document details the architectural topology, component boundaries, execution flows, and engineering decisions behind GravityGuard.
Documentation automation lives in engine/gravityguard_engine/doc_automation.py. PreToolUse records CHANGELOG and, for rule/configuration changes, KNOWLEDGE obligations. Stop refreshes the architecture inventory and, on retry four, injects fallback entries before resolving completed obligations. Projects without a custom generator use a built-in source/LOC/test inventory in their existing architecture document; only the managed block is replaced (maximum 200 lines). Manual content and newline style are preserved by the generic updater.
GravityGuard operates as a dual-layer system combining a native IDE extension with an ultra-lightweight execution guard engine:
flowchart TD
subgraph Host IDE ["Antigravity IDE / VS Code"]
direction TB
subgraph UI ["User Interface Layer (TypeScript)"]
SB["Status Bar Item<br/><code>$(sparkle) Prompt Geliştir</code>"]
WV["GravityGuard Webview<br/><code>Live Monitor Panel</code>"]
KB["Keybinding Dispatcher<br/><code>Ctrl+Alt+E</code>"]
end
subgraph CoreExt ["Extension Core (src/extension.ts)"]
Intent["Local Intent Classifier<br/>(src/intent.ts, <1ms)"]
RouterClient["Local AI Client<br/>(OpenAI-compatible /v1)"]
LogWatcher["Live Log Watcher<br/>(fs.watch + Heartbeat)"]
ClipSync["Clipboard & Editor<br/>Synchronizer"]
end
end
subgraph GuardEngine ["Deterministic Guard Engine (Python)"]
direction TB
CLI["gravity-validator.py<br/>(CLI & Tool Hook Runner)"]
Rules["Rule Evaluator Matrix<br/>- SRP Boundary<br/>- Layer Matrix<br/>- Size & Complexity"]
LogFile[("srp_guardian_live.json<br/>(Shared State Log)")]
end
subgraph LLM ["Local AI Layer (optional)"]
NineRouter["OpenAI-compatible gateway<br/><code>http://127.0.0.1:20128</code>"]
Models["Models (gravityguard.models):<br/>- ag/gemini-3.8-flash-low<br/>- ag/gemini-3.7-flash-medium<br/>- all — or Ollama / LM Studio / llama.cpp"]
end
%% Interactions
SB -->|Triggers| KB
KB -->|Input Prompt| Intent
Intent -->|mode directive only| RouterClient
RouterClient -->|POST /v1/chat/completions| NineRouter
NineRouter -->|Inference| Models
NineRouter -->|Enhanced Spec| RouterClient
RouterClient -->|Auto-Copy| ClipSync
Intent -.->|gateway down| ClipSync
CLI -->|Execute Rules| Rules
Rules -->|Write Verdict| LogFile
LogFile -->|File Event & Poll| LogWatcher
LogWatcher -->|Render HTML & Stats| WV
src/extension.ts:- Acts as the primary lifecycle manager for the VS Code extension host.
- Registers the Status Bar Item (
vscode.window.createStatusBarItem) with priority 100 on the right side of the status bar. - Registers the
antigravity-guardian-viewwebview provider within the dedicated Activity Bar container. - Exposes interactive commands:
antigravityBridge.enhancePrompt: Main prompt enhancement workflow.antigravityBridge.refreshLogs: Force-refreshes the log stream.antigravityBridge.clearLogs: Purges the local audit log.antigravityBridge.ping: Diagnostic healthcheck.
The Prompt Enhancer talks to any OpenAI-compatible local gateway — 9Router, Ollama, LM Studio, llama.cpp — and degrades to a deterministic offline brief when none of them answers.
Stage 1 — Local intent classification (src/intent.ts, no network, <1ms)
classifyIntent()scores weighted Turkish and English signals and returns{ mode, confidence, score, runnerUpScore, signals, source }.- Three modes, three directives, and only the selected directive is sent:
consult(İSTİŞARE),implement(UYGULAMA),audit(DENETİM / REFACTOR). The other two never reach the model, so the prompt cannot drift back into "classify the user's intent" and the model cannot silently pick a different mode. - The user overrides the classifier with a
#denetle:/#danış:/#kodla:prefix (source: 'override'). A classifier the user cannot contradict is one the user stops trusting. - Classification moved out of the model because a directive the model is asked to honour is not a decision the repository can test. ROADMAP 2.2 recorded this gap; the classifier plus
tests/intent.test.mjscloses it.
Stage 2 — Gateway cascade (optional)
- Transport: Node.js native
http.requestagainstgravityguard.routerHost/routerPort, path/v1/chat/completions,"stream": false. - Model cascade (
gravityguard.models, envROUTER_MODELS):ag/gemini-3.8-flash-low→ag/gemini-3.7-flash-medium→all. Any OpenAI-compatible model id is valid, so the extension is not coupled to one gateway's naming scheme. - Two failure classes, two behaviours. A model-level failure (HTTP error, empty content, timeout) falls through to the next model. A connection-level failure (
ECONNREFUSED,ENOTFOUND,EHOSTUNREACH, …) means no model behind that host can answer, so the remaining candidates are skipped instead of each burning a full timeout. - Per-model timeout:
gravityguard.routerTimeoutMs, default 12,000 ms.
Stage 3 — Offline composer (always available)
- When no model answers,
buildOfflinePrompt()renders a structured brief from the classified mode: the original request verbatim, the expected output for that mode, and the standing constraints. The user is told the result came from the offline path. - This is what makes invariant 2 true for the enhancer rather than aspirational: the feature degrades to a lesser result, never to an error dialog.
Output routing
- The enhanced text is written to the system clipboard via
vscode.env.clipboard.writeText. - If text was selected in the active text editor, it replaces the selection in-place.
- A non-blocking notification reports the classified mode and whether the offline path produced the result, with an action button: "Yeni Belgede Aç".
- Self-contained, zero-dependency HTML/CSS dashboard rendered inside the extension sidebar.
- Styled with modern dark-mode glassmorphism (
#0f172aslate background,#1e293bcards). - Resilient Real-time Sync:
- Primary: Asynchronous file watcher on
~/.gemini/logs/srp_guardian_live.json. - Secondary: 1.5-second polling interval to guarantee synchronization even on platforms where filesystem watch events are throttled or dropped.
- Primary: Asynchronous file watcher on
- Bi-directional Webview IPC:
- Webview sends
clearLogsandrefreshmessages back to the extension host viavscode.postMessage().
- Webview sends
- Security boundary:
policy_integrity.pyenforces the mandatory security floor;publication_guard.pyscans Git added text independently of file tools.governance_control.pyis the trusted extension entrypoint for locked advisory waivers. Review evidence requiresreceipt_auth.pyverification using an operator-provisioned key outside the workspace; mandatory review cannot use the advisory retry escape. Host filesystem permissions remain necessary against arbitrary same-user shell writes. - Tool compatibility boundary:
gravityguard_engine/operations.pynormalizes supported argument schemas intoWRITE,EDIT,MULTI_EDIT, or explicit knownREADoperations. Tool names never override mutation arguments. Both provider adapters reuse this module; unsupported file shapes are forwarded intact and denied by the engine. Path-only unknown calls are not assumed to be reads. Wildcard hook registration removes the name-list subscription gap, but cannot intercept a host that does not emit a compatible event. - Standalone, highly performant CLI tool written in standard Python (zero external dependencies).
- Evaluates code mutations using lightweight AST inspection and regex pattern matching:
- SRP Violation Check: Scans for the simultaneous presence of UI elements (e.g. PyQt, Tkinter, Blender
bpy.types.Panel, DOM manipulations) and Network operations (e.g.urllib,requests,aiohttp,websocket) within the same file. - File Scale Heuristics: Distinguishes cohesive single-responsibility files from unmaintainable god-files without arbitrary mechanical line-count blocking.
- SRP Violation Check: Scans for the simultaneous presence of UI elements (e.g. PyQt, Tkinter, Blender
- Hosts: Antigravity calls the engine directly (
plugin/hooks.json). Claude Code goes throughplugin/claude-code/gravityguard_claude_hook.py, which translatesPreToolUse(Write/Edit/MultiEdit/NotebookEdit) andStopevents to the engine payload and the answer back (deny/additionalContext/{"decision":"block"}), using the conversation idclaude:<session_id>. The adapter is not packaged into the VSIX and never copies a rule. - Doc policy:
gravityguard_engine/doc_policy.pyis the single definition of which files owe a CHANGELOG entry;project_context.is_doc_governed_target(Stop-time tracker) andtools/verify_doc_governance.py(git pre-commit, also callable from another repository's hook) both use it. - State scope: obligations and Stop retries are per conversation (
governance.json→sessions[<id>]); the project-wide lists are a monitor-facing union plus legacy entries nobody owns. Seedocs/KNOWLEDGE.md§2.5.
Opt-in (.gravityguard.json → review.enabled), path-based, and split in two so the trigger can be tested without touching state:
- Trigger —
review_policy.py.should_require_reviewfires only for production code suffixes and never for tests (tests/,test_*,*.test.ts, …) or configuredexemptPatterns.is_review_enabledkeeps the feature inert until a project asks for it. - Obligation & candidate fingerprint —
review_governance.py. A session's governed writes accumulate into one candidate keyed byreview_id, withsource_fingerprint= SHA-256 over the sorted newline-normalized file hashes. The agent reviews its own diff and writes a self-review record to.gravityguard/self-review/<review_id>.json(reviewId,sourceFingerprint,findings: [],notes≥ 20 chars).evaluate_review_obligationscloses an obligation only when that record is schema-valid, itssourceFingerprintequals the obligation fingerprint, and the candidate on disk is not stale. Rejections carry a reason:receipt-missing,receipt-invalid-id,receipt-findings-invalid,receipt-notes-too-short,fingerprint-mismatch,stale-candidate. - Two guards. Pre-write (intent): an approved governed write records the obligation. Final diff guard (state): at Stop,
record_final_diff_guardrunsgit status --porcelainand folds in governed code changed out-of-band (e.g. a shell write), best-effort and fail-open. - Hook wiring & Stage Separation. While dispatcher.py records candidate obligations on governed file operations, full Self-Review enforcement is decoupled from interactive Stop events and elevated to Stage 4 (pre-push via ools/verify_review_governance.py). Furthermore, review obligations are risk-gated: changes modifying fewer than 5 files and 120 lines without touching security-critical or engine files are automatically exempt. When triggered before push, the agent reviews its own diff and produces .gravityguard/self-review/.json. This eliminates bureaucratic interruptions during conversational iteration while ensuring no unreviewed high-risk change reaches GitHub.
- Invariant. A self-review record proves a review step happened against a specific candidate state, not that it was correct. GravityGuard catches omission, not malice. History:
docs/adr/0001-specialist-review-v1.md(superseded).
To eliminate agent paralysis and cognitive fatigue without compromising security or architectural integrity, GravityGuard partitions all governance checks across four distinct stages:
-
Stage 1: In-Flight Gatekeeper (PreToolUse Airbag)
- Operates synchronously before filesystem mutation (<5ms latency).
- Prevents critical hazards: secret leaks (G0), silent exception suppression (G1), active test tampering/deletion (G2), structural layer violations (G4), and destructive shell commands.
- Non-blocking heuristics (G3, OE_SPIKE, ARCH_FILE_GROWTH) emit structured warnings.
-
Stage 2: Turn End (Stop Advisory)
- Executes at conversation turn completion.
- Strictly advisory and non-intrusive: delivers lightweight test evidence reminders (T1) and observes file lifecycle events without blocking conversation progression or imposing repetitive review loops.
-
Stage 3: Local Git Gate (pre-commit)
- Enforces change integrity at commit time via standalone verification scripts:
- ools/verify_doc_governance.py: Validates the same-commit rule requiring CHANGELOG.md updates whenever governed production modules are modified.
- ools/verify_removal_governance.py: Detects and blocks orphaned test deletions (TEST_DELETED_SUBJECT_REMAINS), preventing test suite degradation while permitting legitimate feature retirements.
- Enforces change integrity at commit time via standalone verification scripts:
-
Stage 4: GitHub Push Gate (pre-push)
- Enforces quality and self-review before code leaves the local machine:
- ools/verify_review_governance.py: Checks pending self-review receipts (.gravityguard/self-review/.json) for high-risk modifications (≥5 files, ≥120 lines, or changes touching security/engine infrastructure). Low-risk changes are automatically exempt.
- Enforces quality and self-review before code leaves the local machine:
Both rules are WARN-only and both are calibrated against 6,404 real production file-writes (11 repositories, last 400 commits each, one file per commit as the unit of work; see the CHANGELOG for the method and its limits). Every number is a default in DEFAULT_COMPLEXITY_THRESHOLDS and can be overridden per project through the complexity block of .gravityguard.json.
| Key | Default | Meaning |
|---|---|---|
monolithLoc |
1000 | File size at which a module is a monolith. Fires on the crossing write. |
ratchetLoc |
500 | Debt ratchet ceiling (debt_ratchet.py): a file over this size may never grow again; shrinking it lowers its accepted ceiling for good. First-seen baseline = size at git HEAD. |
newFileMaxLoc |
600 | G5_NEW_FILE_BLOAT_DENY: a brand-new source file written above this size is denied before it reaches the disk. |
srpMixedImportsMinLoc |
150 | UI + network imports in one Python file block (SRP_BOUNDARY) only from this size. |
srpMinClassLoc |
25 | A class shorter than this does not count toward the 4-class God-module limit. |
srpMixMinLoc |
400 | SRP_RESPONSIBILITY_MIX (warn): file size from which 3 mixed concerns are reported (2 concerns at twice this). |
srpMaxFunctionLoc |
120 | SRP_RESPONSIBILITY_MIX (warn): one function this long that mixes 2 concerns. |
singleWriteLoc |
180 | One tool call adding this much to an existing file. |
creepBaseLoc |
800 | File size above which additions count as creep. |
creepAddedLoc |
80 | Addition that counts as creep on such a file. |
overEngineeringMaxLoc |
50 | "Small change" window for the abstraction spike. |
overEngineerAbstractions |
2 | Declarations inside that window that trip it. |
Two properties matter more than the numbers:
- ARCH_FILE_GROWTH measures growth, not state. A monolithic file is reported on the write that made it a monolith, and afterwards only when it grows materially. Measured justification: 60 writes land on files already past 1,000 lines and only 30 of them carry a material addition, so the previous state check repeated itself on half its fires.
- Creation is not accumulation. The two growth rules skip files that do not exist yet: 359 of 1,636 real file creations added 180+ lines, and a new cohesive module is the outcome the rules ask for. The crossing rule still applies, so a file born over
monolithLocis reported.
srp: allow-monolith (and the rest of the marker vocabulary the SRP boundary rule already honours) silences the two growth rules. It deliberately does not silence the crossing rule: the marker means "this file is intentionally one unit", so incremental growth is not news — but the write that creates a monolith still is.
User Action (Click Button or Press Ctrl+Alt+E)
│
▼
Check Active Editor Selection?
├── Yes ──> Pre-fill InputBox with selection
└── No ──> Open InputBox with placeholder
│
▼
User Submits Input (Enter)
│
▼
classifyIntent() (local, <1ms, no network)
├── "#denetle:" / "#danış:" / "#kodla:" ──> override wins
└── else weighted TR+EN signal score ──> consult | implement | audit
│
▼
Show IDE Progress Notification ("<MODE> modunda prompt hazırlanıyor...")
│
▼
buildSystemPrompt(mode) ──> only that mode's directive is sent
│
▼
POST /v1/chat/completions to the local gateway (model cascade)
├── HTTP 200 ─────────────> choices[0].message.content
├── model-level failure ──> next model in the cascade
├── connection failure ───> abort the cascade (no model can answer)
└── cascade exhausted ────> buildOfflinePrompt() deterministic brief
│
▼
Write to System Clipboard (Ctrl+V Ready)
│
▼
Display Success Notification (mode + offline/LLM origin) with "Yeni Belgede Aç"
AI Agent Tool Call Triggered
│
▼
[TIER 1: FAST GUARD (<10ms, In-Memory)]
├── Check G0 (Secret Leaks) ─────────────> BLOCK / WARN
├── Check G1 (Silent Exceptions) ────────> BLOCK
├── Check G2 (Test Silencing & Deletion) ─> BLOCK / WARN
├── Check G3 (Compiler Bypass) ──────────> WARN
├── Check G4 (Import Matrix) ────────────> BLOCK
├── Check OE_SPIKE (Over-Engineering) ───> WARN
├── Check ARCH_FILE_GROWTH (Monolith) ───> WARN (growth event, not file state)
├── Check SRP Boundaries ────────────────> BLOCK
├── Check T1-T3 (Test Evidence) ─────────> WARN
└── Read diagnostics.json (<0.5ms) ──────> Surface previous Linter findings (WARN)
│
▼
All Blocking Rules Passed?
├── No ──> Output { decision: "deny", reason: "..." } -> Exit 0
└── Yes ──> Output { decision: "allow", reason?: "[RULE_ID] ..." } -> Exit 0
(schema: decision | reason | permissionOverrides | overwrite, protojson camelCase)
│
▼
Tool Execution Completes
│
▼
[TIER 2: ASYNC STATIC VALIDATION (Background Runner)]
Changed file triggers engine/async_runner.py in background:
├── Python ──> Ruff check
├── TypeScript ──> ESLint check
└── GDScript ──> Godot check-only
│
▼
Writes findings to .gravityguard/runtime/diagnostics.json
│
▼
[TIER 3: BATCH COMPILER CHECK (Debounced)]
Tool burst ends (3s idle) ──> tsc --noEmit across project
A PreToolUse hook response accepts only these keys:
| Key | Type | Required |
|---|---|---|
decision |
string (allow / deny / ask / force_ask) |
yes |
reason |
string | no |
permissionOverrides |
array of strings | no |
overwrite |
object (shallow top-level merge into tool args) | no |
Payloads are protojson-encoded, and protojson rejects unknown fields. Emitting any other key makes the harness discard the entire response, so an intended WARN becomes a hard tool failure.
- v1.2.5 fix: warnings were previously emitted as a
warnings/warning_rule_idsarray. That silently blocked every write tool whenever a warning fired — the safer the guard (WARN rather than DENY), the worse the outcome. Warnings now travel insidereasonformatted as[RULE_ID] message, joined with" ⚠ ", so rule IDs stay machine-readable through their prefix. - Regression protection:
TestHookStdoutContractasserts the warn path emits no schema-invalid key and still delivers its warning, andrun_validator()in the test harness gates every response against the allowed key set. A plainjson.loadsaccepts any key — which is why the suite stayed green while production writes were blocked.
reason is the only agent-visible text channel in the contract, and a second channel
would mean changing a schema the IDE side validates. So the question the roadmap left open
— is a pre-tool architectural whisper a warning, or a new mechanism? — is answered here:
A whisper IS a warning. Any pre-tool advisory text is delivered as a WARN-only rule's
[RULE_ID] ...payload inreason.
Consequences, binding on future work:
- A new advisory capability (the architecture-context whisperer) is added as a WARN rule with its own rule id, not as a side channel. It therefore inherits the same guarantees as every other warning: never blocks, phrased as actionable advice, machine-identifiable by its id.
- It must never be the only carrier of a blocking decision. Anti-Goal 5 applies: an advisory the agent can ignore is fine, one that hides a BLOCK is a security hole.
- Every new WARN rule must add a case to
TestHookStdoutContract, so the id-prefixedreasonformat is proven per rule rather than assumed.
3.4. Hidden Background Orchestration & Debounce Worker
- Fire-and-Forget Trigger (
trigger_background_validation):- Executed on
ALLOWdecisions inengine/gravity-validator.py. - Spawns
async_runner.pywithCREATE_NO_WINDOW+STARTUPINFO(SW_HIDE)on Windows, orstart_new_sessionon POSIX, with all streams sent toDEVNULL. DETACHED_PROCESSis intentionally not used: a detached process owns no console, so every console child it launches (cmd.exevianpx,ruff.exe,godot.exe) allocates a fresh visible console window.CREATE_NO_WINDOWinstead grants a hidden console that all descendants inherit.- The pre-tool hook exits immediately (
~1msspawn overhead); AI tool-call continues with zero wait.
- Executed on
- Silent Linter Invocation (
run_hidden):- All Tier 2/3 tool invocations (
ruff,eslintvianpx,godot,tscvianpx) route through a singlerun_hidden()policy so no linter can ever flash a terminal window. - On timeout,
_kill_process_tree()usestaskkill /F /Tto terminate the whole process tree, preventing orphanedcmd.exe/node.exegrandchildren from accumulating.
- All Tier 2/3 tool invocations (
- State-Based Debounce Worker (
debounce_state.json):- Records
last_edit_time = time.time(). - Spawns a background worker process that sleeps in 3.0s idle intervals.
- If an AI agent performs 5 edits in 2.5 seconds, the worker continually resets until a full 3.0s quiet window elapses, then fires
tsc --noEmitonce. - Claim-release invariant (v1.2.3): every exit path that leaves a state file behind must clear
worker_runningbefore returning. Themax_lifetimeguard previously exited without doing so, leaving a staleTruethat blocked all future spawns — the safety mechanism locked the feature it protected.
- Records
- Per-File Lint Coalescing (
run_coalesced_file_lint_worker):- Single-file linters (
ruff,eslint,godot) use a 300ms quiet window. The first trigger claims the file indebounce_state.json; subsequent triggers inside the window only refresh the timestamp. This is state-based duplicate suppression, not a formally atomic mutex — concurrentload → claim → savesequences are not guarded by a lock. - New-File Grace Period (v1.2.2): because GravityGuard is a
PreToolUsehook, the worker spawns before the AI writes the file. After the quiet window, the worker polls for a bounded 2.0s grace period. If the file appears it is linted once; if it never appears the claim is released and the worker exits silently.execute_single_file_lint()keeps its own existence check as the final safety net.
- Single-file linters (
- Sub-10ms Fast Guard Execution: The synchronous pre-tool interceptor must never stall the AI agent. Heavy external CLI tools (linters, compilers, package managers) are strictly forbidden in Tier 1.
- Deterministic & Offline-First: The guard engine needs nothing but the Python standard library. The prompt enhancer classifies intent locally with no network at all, and reaches an OpenAI-compatible local gateway only as an enhancement — when the gateway is absent the command still returns a usable, mode-correct brief. Offline is the floor, not the degraded path.
- Lossless Failure Handling: If 9Router or diagnostic files are temporarily unavailable, the extension displays friendly notifications without crashing or throwing unhandled exceptions.
- Zero Host File Patching: No files in the host IDE installation are modified; all integration is handled through officially supported VS Code extension interfaces.
- Architectural Airbag Principle: GravityGuard acts as a deterministic seatbelt; it prevents secret leaks and silent errors with BLOCK, while guiding architecture and test evidence through informative WARN signals without paralyzing developer velocity.
- Status: Accepted & Invariant
- Context: As AI-assisted development ("vibecoding") scales, agents produce code at unprecedented velocity. A common temptation is to evolve GravityGuard into an all-encompassing static code analyzer (detecting code smells, cyclomatic complexity, dead code, duplication, or deep taint analysis) similar to SonarQube, CodeQL, or Semgrep.
- Decision: GravityGuard must never attempt to become a general-purpose static analysis platform or SonarQube clone. GravityGuard is strictly an AI-Native Pre-Write Gatekeeper / Airbag, operating synchronously before files touch the disk. Deep static analysis belongs to asynchronous post-write tooling in the developer's defense-in-depth pipeline.
In modern AI agent workflows, software integrity is maintained across four distinct, non-overlapping defense rings:
flowchart TD
subgraph Ring1 ["Ring 1: Pre-Write Gatekeeper (GravityGuard)"]
direction TB
R1A["PreToolUse Hook (<5ms latency)"]
R1B["Prevents Secret Leaks (G0)"]
R1C["Prevents Silent Catch / Fallbacks (G1)"]
R1D["Prevents Test Deletion / Silencing (G2)"]
R1E["Enforces Layer Boundaries (G4 / SRP)"]
R1F["Tracks Stateful Test Evidence (T1 Deferred)"]
end
subgraph Ring2 ["Ring 2: Post-Write Fast Compilers & Linters"]
direction TB
R2A["tsc --noEmit (Type soundness)"]
R2B["Ruff / ESLint (Syntax & local idioms)"]
R2C["Triggered asynchronously via Tier 2/3 Runner"]
R2D["Results surfaced into next prompt via diagnostics.json"]
end
subgraph Ring3 ["Ring 3: Behavioral Proof (Test Runners)"]
direction TB
R3A["vitest / pytest (Unit & Integration)"]
R3B["Proves code actually runs and satisfies contracts"]
R3C["Resolves pending T1 test evidence in GravityGuard"]
end
subgraph Ring4 ["Ring 4: Deep Static Analysis & Governance (CI/CD)"]
direction TB
R4A["SonarQube / Semgrep / CodeQL"]
R4B["Cyclomatic & Cognitive Complexity"]
R4C["Code Duplication & Cross-file Dataflow Taint"]
R4D["CVE Vulnerability & Security Hotspots"]
R4E["Runs asynchronously in minutes, not milliseconds"]
end
ToolIntent["AI Agent File Write Intent"] --> Ring1
Ring1 -->|ALLOW| DiskWrite["File Written to Disk"]
DiskWrite --> Ring2
DiskWrite --> Ring3
DiskWrite -.->|Pull Request / Git Push| Ring4
| Dimension | Ring 1: GravityGuard | Ring 2: Linters / Compilers (tsc, ruff) |
Ring 4: SonarQube / Semgrep |
|---|---|---|---|
| Execution Point | Pre-Write (Tool invocation interception before disk I/O) | Post-Write (After file lands on disk) | Post-Commit / CI/CD (Entire repo scan) |
| Latency Budget | < 10ms (Typical: 0.1ms - 2ms) | 300ms - 5s (Debounced) | 30s - 15 minutes |
| Primary Failure Mode Addressed | Destructive / deceptive AI agent shortcuts (secret commits, empty catches, deleting tests to pass CI, god-file creep) | Syntax errors, type mismatches, unmet compiler contracts | Architecture decay, technical debt, code smells, CVEs, cognitive complexity |
| Enforcement Style | Synchronous Gatekeeping (ALLOW / BLOCK / WARN) |
Diagnostic feedback | Quality gates, PR blocks, compliance dashboards |
| State Tracking | Ephemeral tool diffs + lightweight session evidence (test_evidence_state.json) |
None (per-run file analysis) | Full persistent database of historic codebase metrics |
- Latency Budget Annihilation: SonarQube performs cross-file AST traversal, symbol resolution, and dataflow graph generation. Running this in a synchronous
PreToolUsehook would introduce 5-30 second latencies on every single file write, causing the developer or AI agent to disable the hook immediately. - Reinventing Decades of Mature Tooling: SonarQube, Semgrep, and CodeQL represent hundreds of engineer-years of rule development for thousands of language edge cases. Duplicating a lightweight, buggy subset of these in a Python script creates maintenance debt without delivering industrial-grade depth.
- Misaligned Purpose: SonarQube answers: "Is this entire codebase maintainable, secure, and compliant with enterprise standards over time?" GravityGuard answers: "Is the AI agent about to commit an irreversible, sloppy, or hazardous act right this millisecond?"
- The Airbag Principle: GravityGuard is an airbag, not a full annual vehicle inspection. An airbag must deploy in 5 milliseconds when a crash (secret leak, silent error, test destruction) occurs. It does not inspect whether the car's upholstery matches or if the engine oil has 10% wear.
Üretim tarihi: 2026-11-10 — sürüm 1.5.0
- Toplam dosya: 228, dolu satır: 33779
- Test dosyası: 76, test sayısı: 777
| Katman | Dosya | Dolu satır |
|---|---|---|
| Tier 1 Fast-Path Guardrail | 5 | 841 |
| Tier 4 Deep-Path Güvenlik Denetçisi | 1 | 417 |
| Yönetişim & Yaşam Döngüsü | 4 | 777 |
| Extension UI & Client | 32 | 4667 |
engine/ (alan) |
87 | 14888 |
plugin/ (alan) |
14 | 1262 |
src/ (alan) |
50 | 7794 |
tests/ (alan) |
77 | 9835 |