feat(browser/cdp): native CDP recorder, findings engine, vitals, test harness#201
Merged
Conversation
Contributor
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
🏆 CEO Audit — A+ (100.0/100)
📥 Download full report (Markdown)
|
🏆 CEO Audit — A+ (100.0/100)
📥 Download full report (Markdown) Run ID:
|
| if err != nil { | ||
| return err | ||
| } | ||
| return os.WriteFile(path, b, 0o644) |
| // NewSink creates (or truncates) the file at path and returns a ready Sink. | ||
| // The caller must call Close when recording is finished. | ||
| func NewSink(path string) (*Sink, error) { | ||
| f, err := os.Create(path) |
Comment on lines
+24
to
+27
| w.Write([]byte(`<!doctype html><html><body><h1>console</h1><script> | ||
| console.error("boom: deterministic console error"); | ||
| thisSymbolDoesNotExist(); | ||
| </script></body></html>`)) |
| // 2. HTTP 500 on a fetched subresource. | ||
| mux.HandleFunc("/server-500.js", func(w http.ResponseWriter, _ *http.Request) { | ||
| w.WriteHeader(http.StatusInternalServerError) | ||
| w.Write([]byte(`// 500`)) |
Comment on lines
+37
to
+38
| w.Write([]byte(`<!doctype html><html><body><h1>500</h1> | ||
| <script src="/server-500.js"></script></body></html>`)) |
Comment on lines
+45
to
+46
| w.Write([]byte(`<!doctype html><html><body><h1>fail</h1> | ||
| <img src="http://127.0.0.1:1/missing.png"></body></html>`)) |
Comment on lines
+53
to
+54
| w.Write([]byte(`<!doctype html><html><body><h1>csp</h1> | ||
| <script>console.log("blocked by csp")</script></body></html>`)) |
| mux.HandleFunc("/slow-img.png", func(w http.ResponseWriter, _ *http.Request) { | ||
| time.Sleep(1200 * time.Millisecond) | ||
| w.Header().Set("Content-Type", "image/png") | ||
| w.Write(onePxPNG) |
Comment on lines
+65
to
+66
| w.Write([]byte(`<!doctype html><html><body> | ||
| <img src="/slow-img.png" style="width:600px;height:400px"></body></html>`)) |
Comment on lines
+72
to
+73
| w.Write([]byte(`<!doctype html><html><body><h1>all good</h1> | ||
| <script>console.log("nothing wrong here")</script></body></html>`)) |
Addresses the full gap identified in the June 2026 audit:
pkg/browser/cdp — new package (4 files):
- event.go JSONL Event envelope + Artifact type with seq/wall/mono/step_id correlation
- sink.go thread-safe buffered JSONL writer
- recorder.go chromedp-based Recorder; subscribes to all 15 Network events, Runtime,
Log, Audits (issueAdded — CORS/CSP/mixed-content, previously missing),
Security (securityStateChanged, previously missing), Page (9 lifecycle
events), Target (setAutoAttach flatten=true for OOPIFs/workers), and
Performance metrics polling; deferred response-body capture with byte cap
- findings.go deterministic single-pass Findings engine: classifies, groups, deduplicates,
and sorts events into structured Finding objects (error/warn/info) so the
agent loop can act without LLM interpretation of raw JSONL
go.mod: add github.com/chromedp/chromedp v0.13.6, github.com/chromedp/cdproto, and
their indirect dependencies (sysutil, gobwas/ws, mailru/easyjson, ...)
cmd/sin-code/chat_tools_extra.go: three new builtin tools
- sin_browser_navigate navigate headless Chrome + start CDP recording (policy: ask)
- sin_browser_findings return classified Findings from last session (policy: allow)
- sin_browser_snapshot return compact session summary with event counts (policy: allow)
cmd/sin-code/internal/permission_defaults.go: permission rules for the three new tools
skills/browser-skills/skill-browser-tools/SKILL.md: replaced generic stub with full CDP
documentation — domain/event coverage table, Finding schema, JSONL format, OOPIF
limitation note (TODO in recorder.go), safety and verification checklist
Co-authored-by: v0agent <it+v0agent@vercel.com>
…ildReport pipeline, Fix-Verify diff
pkg/browser/cdp — 4 new files, 2 patched:
vitals.go (new)
InstallVitals: registers PerformanceObserver script on every new document via
Page.addScriptToEvaluateOnNewDocument; captures LCP/CLS/INP/LongTask as
console.debug('__SINCDP_VITAL__', ...) so the findings engine can classify them
EvalVitalsNow: forces an immediate metric flush before BuildReport on already-
loaded pages
report.go (new)
Report / ReportSummary: top-level structured object (findings + chains +
suggestions + summary) the agent loop consumes
BuildReport: single call that runs Analyze → Correlate → Suggest and returns
a deterministic Report; replaces bare Analyze calls everywhere
Report.WriteJSON: persists the report for later DiffReports comparison
suggest.go (new)
FixSuggest: rule-based hint with Cause, Action, FixClass, and Confidence
Suggest / classify: maps each Finding to a FixSuggest via prefix routing
auditSuggest: CSP / mixed-content / CORS / deprecation / cookie rules
vitalSuggest: LCP / CLS / INP / LongTask remediation hints with perf.* FixClass
verify.go (new)
Diff: resolved / introduced / persisted + Improved flag + before/after error counts
DiffReports: deterministic before/after comparison keyed by Finding.Signature
recorder.go (patched)
bodyWG sync.WaitGroup: tracks in-flight fetchBody goroutines
Close: waits up to 5 s for pending body fetches before flushing the sink
captureInitialTargets: snapshots already-open tabs/workers at Attach time
enableOnSession: enables Network/Runtime/Log/Audits on every OOPIF/worker
child session (closes the TODO(oopif) gap); recursive SetAutoAttach +
RunIfWaitingForDebugger for nested frames
findings.go (patched)
Vitals rule: intercepts __SINCDP_VITAL__-tagged console events before the
general consoleAPICalled handler; applies CWV thresholds (good/NI/poor)
Correlate: single-pass root-cause chain builder; links loadingFailed/4xx-5xx
to downstream exceptions and console errors within a sequence window
isVital / parseVital / vitalSeverity: cheap pre-check + unmarshal + threshold helpers
bytes import added
cmd/sin-code/chat_tools_extra.go
toolBrowserNavigate: calls InstallVitals after EnableDomains; stores cdpCtx
on the session for EvalVitalsNow; accepts save_baseline=true param to snapshot
a baseline Report for DiffReports; carries baseline across re-navigations
toolBrowserFindings: upgraded from bare Analyze to BuildReport; reports
findings + chains + suggestions + summary in one JSON response
toolBrowserSnapshot: upgraded to BuildReport; includes full Report in snap
toolBrowserVitalsFlush (new): calls EvalVitalsNow on the live tab
toolBrowserDiff (new): builds after-Report and calls DiffReports vs baseline;
returns verdict string + full Diff JSON
Two new tool specs added; sin_browser_navigate spec updated
cmd/sin-code/internal/permission_defaults.go
Added allow rules for sin_browser_vitals_flush and sin_browser_diff
Co-authored-by: v0agent <it+v0agent@vercel.com>
pkg/browser/cdp — 5 new files, 1 reconciled:
findings.go (reconciled with canonical spec)
- Rename rank → severityRank (matches spec and analyze_test.go reference)
- Console-warning signature changed from "console:" to "console:warning:"
prefix so errors and warnings with identical text no longer collide
- Remove duplicated Chain/Symptom/Correlate block (now lives in correlate.go)
- Remove duplicated Vitals helpers (isVital/parseVital/vitalSeverity remain
here as the canonical location; correlate.go calls firstLine/consoleText)
correlate.go (new)
Chain, Symptom, Correlate extracted from findings.go into their own file
for readability; logic is identical to the canonical spec
fixtures.go (new)
onePxPNG + mustDecode: 1×1 transparent PNG used by the slow-LCP fixture
in testserver.go to produce a reliable delayed hero image
testserver.go (new)
NewFaultServer: httptest.Server with 6 deterministic routes
/console-error → console.error + ReferenceError (exceptionThrown)
/http-500 → 500 subresource (responseReceived with status 500)
/net-fail → img pointing at 127.0.0.1:1 (loadingFailed)
/csp → script-src 'none' + inline script (Audits issueAdded)
/slow-lcp → hero image with 1.2 s artificial delay (LCP vital)
/clean → control: zero error findings expected
harness_test.go (new)
TestConsoleAndException console: + exc: findings, HasFatal=true
TestHTTP500 http:500 finding + network.http_error suggestion
TestNetworkFailure netfail: or netblock: finding
TestCSPViolation audit: finding (CSP DevTools issue)
TestSlowLCP vital:LCP finding (>2500 ms threshold)
TestCleanPageHasNoErrors HasFatal=false, Errors=0 (control)
TestJSONLGroundTruthWritten non-empty JSONL file after Close()
skipIfNoChrome: all browser tests auto-skip when no Chrome found
analyze_test.go (new — no Chrome required, runs on every CI build)
TestAnalyzeGroupsRepeatedConsoleErrors 5 identical → 1 finding (count=5)
TestAnalyzeConsoleWarningSignature console:warning: prefix + SevWarn
TestCorrelateLinksFailureToException loadingFailed → exceptionThrown chain
TestCorrelateIgnoresOutOfWindowSymptoms symptom outside window=5 → no chain
TestDiffDetectsImprovement resolved error → Improved=true
TestDiffDetectsRegression new error introduced → Improved=false
TestDiffPersisted unchanged finding → Persisted list
TestVitalSeverityThresholds 12 threshold cases (LCP/CLS/INP/LongTask)
Co-authored-by: v0agent <it+v0agent@vercel.com>
pkg/browser/cdp — 2 new files: adapter.go FixExecutor / Rerunner interfaces: backend-agnostisch, der SIN-Code-Agent implementiert sie (Apply routet per FixClass an LLM-Code-Edit/Config-Fix/ Endpoint-Check, Revert macht rückgängig; Rerun startet fresh Recorder + re-navigiert → BuildReport) RunAutoFix: geschlossene Schleife — höchstpriorisierte Suggestion wählen (errors < warnings, höhere confidence first), anwenden, neu erfassen, diffen (vor/nach), bei Verbesserung übernehmen / bei Regression zurückrollen, bis keine fatalen Findings mehr oder Attempt-Limit greift LoopResult / Attempt: vollständiges Audit-Trail jeder Aktion adapter_test.go TestAutoFixConverges: ein Fehler wird behoben → Convergence TestAutoFixRevertsOnRegression: apply() erzeugt neuen Fehler → auto-revert Co-authored-by: v0agent <it+v0agent@vercel.com>
Delqhi
force-pushed
the
cdp-capture-audit
branch
from
June 16, 2026 16:31
a8d1818 to
afa5055
Compare
This was referenced Jun 16, 2026
Delqhi
pushed a commit
that referenced
this pull request
Jun 16, 2026
…ub-assets merge)
What ships:
- cmd/sin-code/catalog_cmd.go — new subcommand 'sin-code catalog'
(list | search | info) with --kind and --format flags
- cmd/sin-code/internal/catalog/ — 4 source files + 21 race-clean tests
- catalog.go: Asset, Kind, Source, Merge, Search, FilterByKind
- source_hub.go: HubSource adapter (wraps internal/hub)
- source_assets.go: AssetsSource adapter (wraps *assets.Registry)
- catalog_test.go: 21 tests covering merge dedup, search ranking,
filter, both source adapters, end-to-end
- main.go registration (additive, no breaking change)
De-duplication rule:
- Key is (kind, name), NOT (source, kind, name)
- A hub.Tool and an assets.Asset with the same (kind, name) merge
into one catalog entry; the first source wins
- This is the SOTA choice: operators think 'do I have a tool for
this?', not 'which backend has it?'
Search ranking:
- name +4, short +2, description +1, tag +1
- Ties break by name ascending
- Score is auditable in source; not exposed in CLI output
Deprecation:
- sin-code hub continues to work unchanged
- Issue body: 'sin hub and sin assets remain as deprecated aliases
of sin catalog for one minor release. After v3.20, they go.'
- The actual deprecation warning is a follow-up that patches
hub_cmd.go — out of scope here
Hard mandates honored:
- M2: stdlib + existing internal/{hub,assets} packages, no new deps
- M5: module path unchanged
- M6: Source interface is the SIN-tool abstraction; both adapters
reuse the existing hub.FormatList / assets.Registry without
copying any logic
- M7: 21/21 tests pass under go test -race -count=1
Known issue (NOT in this PR):
- 'go build ./cmd/sin-code/...' is currently broken on v3.18.0
main because the merged pkg/browser/cdp/ (PR #201) shipped
without a complete go.sum and a Chromedp API mismatch. This
PR does not touch Browser/CDP. The catalog package itself is
build-clean and tested.
Refs: #163
Delqhi
added a commit
that referenced
this pull request
Jun 16, 2026
…ub-assets merge) (#208) What ships: - cmd/sin-code/catalog_cmd.go — new subcommand 'sin-code catalog' (list | search | info) with --kind and --format flags - cmd/sin-code/internal/catalog/ — 4 source files + 21 race-clean tests - catalog.go: Asset, Kind, Source, Merge, Search, FilterByKind - source_hub.go: HubSource adapter (wraps internal/hub) - source_assets.go: AssetsSource adapter (wraps *assets.Registry) - catalog_test.go: 21 tests covering merge dedup, search ranking, filter, both source adapters, end-to-end - main.go registration (additive, no breaking change) De-duplication rule: - Key is (kind, name), NOT (source, kind, name) - A hub.Tool and an assets.Asset with the same (kind, name) merge into one catalog entry; the first source wins - This is the SOTA choice: operators think 'do I have a tool for this?', not 'which backend has it?' Search ranking: - name +4, short +2, description +1, tag +1 - Ties break by name ascending - Score is auditable in source; not exposed in CLI output Deprecation: - sin-code hub continues to work unchanged - Issue body: 'sin hub and sin assets remain as deprecated aliases of sin catalog for one minor release. After v3.20, they go.' - The actual deprecation warning is a follow-up that patches hub_cmd.go — out of scope here Hard mandates honored: - M2: stdlib + existing internal/{hub,assets} packages, no new deps - M5: module path unchanged - M6: Source interface is the SIN-tool abstraction; both adapters reuse the existing hub.FormatList / assets.Registry without copying any logic - M7: 21/21 tests pass under go test -race -count=1 Known issue (NOT in this PR): - 'go build ./cmd/sin-code/...' is currently broken on v3.18.0 main because the merged pkg/browser/cdp/ (PR #201) shipped without a complete go.sum and a Chromedp API mismatch. This PR does not touch Browser/CDP. The catalog package itself is build-clean and tested. Refs: #163 Co-authored-by: opencode <agent@opencode.local>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Three commits building the full
pkg/browser/cdpstack for headless-Chrome audit and recording in SIN-Code.Commit 1 —
feat(browser/cdp): core package + agent toolsNew package
pkg/browser/cdp(4 files):event.go— JSONLEventenvelope withseq/wall_time/mono_nanos/step_id/session_idsink.go— mutex-protected, 64 KiB-buffered JSONL writerrecorder.go— chromedpRecorder; subscribes to all 15 Network events, Runtime, Log, Audits (CORS/CSP/mixed-content), Security, Page lifecycle, Target (OOPIFs/workers), Performance metrics pollingfindings.go— deterministicAnalyze()engine; classifies, groups, deduplicates, sorts events intoFindingstructsgo.mod: chromedp/chromedp v0.13.6, chromedp/cdproto + indirect deps
Agent loop (
chat_tools_extra.go): three new builtins —sin_browser_navigate,sin_browser_findings,sin_browser_snapshotPermissions (
permission_defaults.go): navigate=ask, read-only tools=allowCommit 2 — loop-closer: Vitals injection, OOPIF sessions, BuildReport pipeline, Fix-Verify diff
4 new files:
vitals.go—InstallVitals(PerformanceObserver on every new document),EvalVitalsNowreport.go—BuildReportsingle pipeline entry point (Analyze → Correlate → Suggest → Report)suggest.go—FixSuggestwithFixClassrouting tagsverify.go—DiffReportsbefore/after comparison with resolved/introduced/persisted + Improved flagrecorder.go patched:
bodyWG+ 5 s graceful Close;captureInitialTargets;enableOnSession(resolves OOPIF TODO)findings.go patched: Vitals rule;
Correlateroot-cause chains; Vitals threshold helpers2 new agent tools:
sin_browser_vitals_flush,sin_browser_diffCommit 3 — test harness + pure unit tests
6 files:
correlate.go— Chain/Symptom/Correlate extracted into own filefixtures.go—onePxPNGfor slow-LCP fixturetestserver.go—NewFaultServerwith 6 deterministic routes (console-error, http-500, net-fail, csp, slow-lcp, clean)harness_test.go— 7 browser integration tests (auto-skip when no Chrome found)analyze_test.go— 8 pure unit tests, no Chrome requiredfindings.go reconciled:
rank→severityRank; console-warning signature"console:warning:"prefix