Skip to content

Commit 3376271

Browse files
authored
Merge pull request #20 from formula-code/feat/public-rls-and-grafana
Public RLS, grafana_ro policies, runner_progress trigger, doc polish
2 parents a3621d5 + ca037c6 commit 3376271

10 files changed

Lines changed: 483 additions & 399 deletions

File tree

.gitignore

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,3 +224,13 @@ PARITY_TODOs.md
224224
backup
225225
rebuild
226226
run_interpreter.py
227+
run_harbor_single.py
228+
run_neighbor_synthesis.py
229+
run_single_synthesis.py
230+
run_single_synthesis_test.py
231+
232+
# Local artifacts
233+
.claude/
234+
.python-version
235+
backups/
236+
jobs/

CLAUDE.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ Each task lives in `dataset/formulacode_verified/<owner_repo>/<sha>/` with a mul
8282

8383
After making a feature change, decide whether the change is significant enough to warrant updating the documentation in `docs/`. Changes that affect user-facing behavior, CLI flags, configuration knobs, pipeline stages, agent backends, or architectural decisions should be reflected in the relevant guide or design doc. Internal refactors, bug fixes, and implementation details generally do not need doc updates unless they change observable behavior.
8484

85+
**Diagrams**: use Mermaid (`` ```mermaid `` fenced blocks) for any architecture, flow, or state diagram in `.md` files. Do not use ASCII box-drawing art (`┌ ─ │ └ ──▶`). Mermaid renders natively on GitHub and in the docs site; ASCII does not, and is harder to edit.
86+
8587
### Tunable constants
8688

8789
Any module-level constant that is a knob — timeouts, retries, caps, windows,
@@ -130,6 +132,10 @@ The Supabase PostgREST API is also available at `https://db.formulacode.org` via
130132

131133
When both `DATASMITH_CF_ACCESS_*` vars are set, `get_client()` and `get_async_client()` in `utils/db.py` automatically inject the required headers. See `docs/guide/remote-access.md` for full setup instructions.
132134

135+
### Public read-only access (RLS)
136+
137+
Four tables have Row Level Security enabled with `public_read` SELECT-only policies for the `anon` role: `repositories`, `pull_requests`, `candidate_containers`, `harbor_runs`. The service-role key bypasses RLS, so pipeline processes are unaffected. See `supabase/migrations/00012_public_read_rls.sql`.
138+
133139
### Key tables
134140

135141
| Table | Purpose | Populated by |

docs/design/components/datasmith.agents.synthesizer.md

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -56,22 +56,21 @@ ctx = synth.run(
5656

5757
The synthesizer progresses through five states in order. Each state either returns a `DockerContext` (success) or falls through to the next state.
5858

59-
```
60-
CHECK_CACHE ──hit──> return DockerContext
61-
62-
│ miss
63-
v
64-
FIND_SIMILAR ──> TRY_SIMILAR ──any pass──> return DockerContext
65-
66-
│ all fail / none found
67-
v
68-
LLM_GENERATE (sandbox, up to max_attempts)
69-
70-
│ any pass ──> return DockerContext
71-
72-
│ all fail
73-
v
74-
FAIL ──> return None
59+
```mermaid
60+
flowchart TD
61+
Cache["CHECK_CACHE"]
62+
Find["FIND_SIMILAR"]
63+
Try["TRY_SIMILAR"]
64+
Gen["LLM_GENERATE<br/>(sandbox, up to max_attempts)"]
65+
Ok(["return DockerContext"])
66+
Fail(["FAIL: return None"])
67+
Cache -- hit --> Ok
68+
Cache -- miss --> Find
69+
Find --> Try
70+
Try -- "any pass" --> Ok
71+
Try -- "all fail / none found" --> Gen
72+
Gen -- "any pass" --> Ok
73+
Gen -- "all fail" --> Fail
7574
```
7675

7776
### State details

docs/design/components/datasmith.resolution.md

Lines changed: 62 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -175,90 +175,72 @@ A persistent JSON blocklist (`{CACHE_DIR}/package_blocklist.json`) tracks packag
175175

176176
### How `prepare_commits_for_building_reports.py` called the resolution module (archive)
177177

178-
```
179-
prepare_commits_for_building_reports.py
180-
181-
├─ Load parquet → DataFrame with commit data
182-
├─ crude_perf_filter(df) → filtered_df
183-
184-
├─ Build (sha, repo_name) pairs from filtered_df["pr_base"]["sha"]
185-
├─ _thread_map(safe_analyze_commit, pairs, max_workers=200)
186-
│ │
187-
│ └─ safe_analyze_commit((sha, repo_name))
188-
│ │
189-
│ └─ analyze_commit(sha, repo_name) # from resolution.__init__
190-
│ │
191-
│ └─ orchestrator.analyze_commit(sha, repo_name)
192-
│ │
193-
│ ├─ prepare_repo_checkout(repo_name, sha) [git_utils]
194-
│ ├─ asv_finder(commit) [git_utils]
195-
│ ├─ filter_python_versions_by_commit_date() [python_manager]
196-
│ ├─ discover_candidates(commit) [metadata_parser]
197-
│ ├─ analyze_candidate_meta(candidate) [metadata_parser]
198-
│ ├─ select_primary_candidate(...) [metadata_parser]
199-
│ │
200-
│ ├─ STRATEGY 1: For each source file × python version:
201-
│ │ ├─ run_uv(["venv", ...]) [python_manager]
202-
│ │ ├─ uv_compile_from_pyproject(...) [dependency_resolver]
203-
│ │ ├─ uv_dry_run_install(...) [dependency_resolver]
204-
│ │ └─ uv_install_real(...) [dependency_resolver]
205-
│ │
206-
│ ├─ STRATEGY 2: Aggregate requirements
207-
│ │ ├─ extract_requested_extras(...) [package_filters]
208-
│ │ ├─ split_shell_command(cmd) [package_filters]
209-
│ │ ├─ normalize_requirement(tok) [package_filters]
210-
│ │ ├─ resolve_requirements_file(...) [package_filters]
211-
│ │ ├─ uv_build_and_read_metadata(...) [dependency_resolver]
212-
│ │ ├─ infer_runtime_from_imports(...) [import_analyzer]
213-
│ │ ├─ filter_requirements_for_pypi(...) [package_filters]
214-
│ │ ├─ clean_pinned(...) [package_filters]
215-
│ │ ├─ uv_compile(...) [dependency_resolver]
216-
│ │ │ └─ Self-healing retry loop:
217-
│ │ │ ├─ extract_failing_package() [blocklist]
218-
│ │ │ ├─ add_to_blocklist() [blocklist]
219-
│ │ │ └─ remove_package_from_requirements() [blocklist]
220-
│ │ ├─ uv_dry_run_install(...) [dependency_resolver]
221-
│ │ │ └─ Self-healing retry loop (same)
222-
│ │ └─ uv_install_real(...) [dependency_resolver]
223-
│ │
224-
│ └─ Return dict with resolution results
225-
226-
├─ pd.DataFrame(analysis_dicts).add_prefix("analysis_")
227-
├─ Filter: analysis_can_install == True
228-
├─ Filter: analysis_resolution_strategy not startswith "unresolved"
229-
└─ Save enriched parquet
178+
```mermaid
179+
flowchart TD
180+
Entry["prepare_commits_for_building_reports.py"]
181+
Load["Load parquet → DataFrame"]
182+
Filter1["crude_perf_filter(df)"]
183+
Pairs["Build (sha, repo_name) pairs"]
184+
TMap["_thread_map(safe_analyze_commit, pairs, max_workers=200)"]
185+
Analyze["orchestrator.analyze_commit(sha, repo_name)"]
186+
subgraph Prep["Per-commit preparation"]
187+
direction TB
188+
Checkout["prepare_repo_checkout [git_utils]"]
189+
ASV["asv_finder [git_utils]"]
190+
PyVers["filter_python_versions_by_commit_date [python_manager]"]
191+
Discover["discover_candidates [metadata_parser]"]
192+
AnalyzeMeta["analyze_candidate_meta [metadata_parser]"]
193+
SelectCand["select_primary_candidate [metadata_parser]"]
194+
end
195+
subgraph S1["STRATEGY 1: per source file × python version"]
196+
direction TB
197+
Venv["run_uv(['venv', ...]) [python_manager]"]
198+
Pyproj["uv_compile_from_pyproject [dependency_resolver]"]
199+
DryRun1["uv_dry_run_install [dependency_resolver]"]
200+
Install1["uv_install_real [dependency_resolver]"]
201+
end
202+
subgraph S2["STRATEGY 2: aggregate requirements"]
203+
direction TB
204+
Extras["extract_requested_extras [package_filters]"]
205+
Split["split_shell_command / normalize_requirement [package_filters]"]
206+
Resolve["resolve_requirements_file [package_filters]"]
207+
BuildMeta["uv_build_and_read_metadata [dependency_resolver]"]
208+
Imports["infer_runtime_from_imports [import_analyzer]"]
209+
FilterPyPI["filter_requirements_for_pypi / clean_pinned [package_filters]"]
210+
Compile["uv_compile [dependency_resolver]"]
211+
Heal["Self-healing retry loop:<br/>extract_failing_package → add_to_blocklist →<br/>remove_package_from_requirements [blocklist]"]
212+
DryRun2["uv_dry_run_install (same heal loop)"]
213+
Install2["uv_install_real"]
214+
Compile --> Heal
215+
end
216+
Result["Return dict with resolution results"]
217+
Post["pd.DataFrame(...).add_prefix('analysis_')<br/>filter can_install == True<br/>filter resolution_strategy not startswith 'unresolved'<br/>save enriched parquet"]
218+
219+
Entry --> Load --> Filter1 --> Pairs --> TMap --> Analyze
220+
Analyze --> Prep --> S1
221+
Analyze --> S2
222+
S1 --> Result
223+
S2 --> Result
224+
Result --> Post
230225
```
231226

232227
### How the new pipeline will call resolution
233228

234-
```
235-
Pipeline._run_stage("resolve_packages")
236-
237-
├─ Query pull_requests WHERE is_performance_commit = TRUE
238-
│ AND NOT EXISTS (SELECT 1 FROM packages WHERE packages.sha = pr.merge_commit_sha
239-
│ AND packages.owner = pr.owner AND packages.repo = pr.repo)
240-
241-
├─ Deduplicate by (owner, repo, merge_commit_sha)
242-
│ (multiple PRs may share the same base commit)
243-
244-
├─ ResolvePackagesRunner.run(items, n_concurrent=N)
245-
│ │
246-
│ └─ For each (owner, repo, sha):
247-
│ ├─ analyze_commit(sha, f"{owner}/{repo}")
248-
│ ├─ If result and can_install:
249-
│ │ └─ Upsert into packages table
250-
│ └─ If None or not can_install:
251-
│ └─ Log to runner_failures
252-
253-
└─ Pipeline._synthesize_images() now reads:
254-
SELECT pr.*, pkg.env_payload, pkg.python_version
255-
FROM pull_requests pr
256-
JOIN packages pkg ON pr.owner = pkg.owner
257-
AND pr.repo = pkg.repo
258-
AND pr.merge_commit_sha = pkg.sha
259-
WHERE pr.is_performance_commit = TRUE
260-
AND pr.container_name IS NULL
261-
AND pkg.can_install = TRUE
229+
```mermaid
230+
flowchart TD
231+
Stage["Pipeline._run_stage('resolve_packages')"]
232+
Query["Query pull_requests WHERE is_performance_commit = TRUE<br/>AND NOT EXISTS (packages row for same owner/repo/sha)"]
233+
Dedup["Deduplicate by (owner, repo, merge_commit_sha)"]
234+
Runner["ResolvePackagesRunner.run(items, n_concurrent=N)"]
235+
PerItem["For each (owner, repo, sha):<br/>analyze_commit(sha, owner/repo)"]
236+
Upsert["Upsert into packages table"]
237+
Failure["Log to runner_failures"]
238+
Synth["Pipeline._synthesize_images() joins packages on<br/>(owner, repo, merge_commit_sha) and filters can_install"]
239+
240+
Stage --> Query --> Dedup --> Runner --> PerItem
241+
PerItem -- "result and can_install" --> Upsert
242+
PerItem -- "None or not can_install" --> Failure
243+
Upsert --> Synth
262244
```
263245

264246
## Key data models (from archive, ported as-is)

docs/guide/monitoring.md

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -39,16 +39,13 @@ cloudflared tunnel run datasmith-grafana
3939

4040
Grafana runs as a Docker container that joins the existing Supabase Docker network. It connects to Postgres via a **read-only** `grafana_ro` database role that can only `SELECT` — no writes are possible, even from the Explore SQL editor.
4141

42-
```
43-
┌──────────────┐ ┌──────────────────────────┐
44-
│ Browser │────▶│ Grafana (port 3001) │
45-
└──────────────┘ │ Anonymous Viewer access │
46-
└───────────┬──────────────┘
47-
│ SELECT only
48-
┌───────────▼──────────────┐
49-
│ Supabase PostgreSQL │
50-
│ (grafana_ro role) │
51-
└──────────────────────────┘
42+
```mermaid
43+
flowchart TD
44+
Browser["Browser"]
45+
Grafana["Grafana (port 3001)<br/>Anonymous Viewer access"]
46+
PG["Supabase PostgreSQL<br/>(grafana_ro role)"]
47+
Browser --> Grafana
48+
Grafana -- "SELECT only" --> PG
5249
```
5350

5451
## Dashboard Panels

0 commit comments

Comments
 (0)