Skip to content

extdeps/git: model diff interface (name-status -z) - #6297

Merged
briansrls merged 13 commits into
mainfrom
session/nimble-otter-431
Jul 5, 2026
Merged

briansrls merged 13 commits into
mainfrom
session/nimble-otter-431

Conversation

@gunbai-bot

@gunbai-bot gunbai-bot Bot commented Jul 5, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Models git's git diff --name-status -z machine interface as the single
typed authority for path-grain diff observation (extdeps/git), replacing
a unified-diff header-scrape reimplementation of the same fact.

  • dag/extdeps/git/git.dag: GitDiffChangeStatus (A/M/D/R<score>/C<score>,
    typed rename/copy similarity), GitDiffStatusEntry, a NUL-token parser
    (parse_git_diff_name_status_z), and touched_paths/departed_paths
    projections, plus DiffNameStatus/DiffNameStatusMerge service
    operations (shell transport, one realization of the interface shape).
  • src/v2/workflow/floor_diff_observe.dag: a provider-agnostic
    FloorNameStatusDiffResult observation entry point
    (floor_observe_git_diff_name_status_for_ci), fail-closed on a
    nonzero exit or an unrecognized status letter (never silently
    absorbed).
  • src/v1/stage0/src/cli_run.rs: host cutover — the CI floor's
    changed_paths/departed_paths for path grain now come from this
    typed name-status observation instead of scraping
    diff --git a/OLD b/NEW headers out of the unified diff text. LINE
    grain (hunk ranges, decl-overlap attribution) still legitimately uses
    the unified diff and is untouched.
  • Base-ref policy (DiffPolicy) stays in the workflow layer, unmoved.

Test plan

  • .dag witnesses, verified green under real (--wet) shell execution,
    not the hermetic mock:
    • extdeps_git_diff_name_status_witnesses (parser: A/M/D/R/C, rename
      old+new paths, malformed status letter refuses typed-not-absorbed)
    • git_mock_consumer_is_total_holds / git_mock_omitted_member_is_red_holds
      (mock-corpus totality, red-on-omission control)
    • floor_diff_observe_host_effect_apply_holds (unified + name-status
      script serialization, real CI-policy observation, invalid-base
      fail-closed control, for both diff shapes)
  • cargo check / cargo clippy --all-targets -- -D warnings: clean.
  • cargo test -p v1-compiler --lib cli_run::: 115 passed, 1 pre-existing
    unrelated failure (test_migration_debt_tests::delete_guard_holds_with_no_v1_test_deletions_in_diff,
    its own separate git-diff plumbing querying origin/main; reproduces
    identically on this exact commit and is untouched by this change).

briansrls and others added 8 commits July 5, 2026 19:55
…h types

git_diff_status_entry_departed_path nested an if around a match, and one
arm returned entry.old_path (Optional<FilePath>) while a sibling arm under
the outer if's else returned a bare Present{..} — the typechecker rejected
the if/match split as incompatible (Product(FilePath) vs Coproduct(Optional)).
Flattened to a single match over entry.status with three arms; green via
claim_batch on the new extdeps_git_diff_name_status_witnesses witness.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…iff_observe

Add FloorNameStatusDiffResult / floor_observe_git_diff_name_status(_for_ci),
mirroring the existing unified-diff mechanism but targeting
`git diff --name-status -z` and routing raw stdout through
extdeps.git.parse_git_diff_name_status_z + git_diff_status_entries_touched_paths
(single-authority parser, no re-parsing in the workflow layer). An unrecognized
status letter (typed DiffUnknownGitStatus) refuses (NameStatusDiffFail), never
silently drops the entry.

Also fixes a latent bug shared by the pre-existing unified-diff path: Converged
{ ShellEffectApplied { exit_code, .. } } was matched with exit_code discarded
(`_`), so a nonzero-but-"Converged" evidence value would have been read as Ok.
realize_shell_on_host already gates Converged on process success, but the
reconciliation consumer should not silently trust that invariant either -
check exit_code explicitly at the point of use. Found via `--wet` execution
of a real invalid-base-ref case (claim_batch defaults to --hermetic/mocked
shell.Exec.Run; --wet is required to exercise real host execution).

Witnesses (claim_batch --wet): floor_diff_observe_host_effect_apply_holds now
covers both the unified-diff and name-status-diff success/fail-closed paths.
floor_git_diff_name_status_range() (cli_run.rs) resolves
floor_observe_git_diff_name_status_for_ci and extracts changed_paths/
departed_paths from the typed NameStatusDiffOk/NameStatusDiffFail
result. run_discovery_corpus_with_options now sources changed_paths
and departed_paths from this real git diff --name-status -z
observation instead of the unified-diff header scrape/text scan.

parse_unified_diff_line_ranges drops the `diff --git a/OLD b/NEW`
header-scrape block (path grain); it stays scoped to LINE grain
(hunk ranges) only, as decl-overlap attribution still needs it.
Hunkless .dag paths (pure rename, mode-only, binary) are seeded into
line_ranges_by_file from the name-status changed_paths so
floor_diff_edits_from_line_ranges keeps attributing them at path
grain with no regression.

Updates floor_disposition_refusal_note to record the git-interface
grain gap (name-status, rename pairs) as closed.

Verified: cargo check/clippy -D warnings clean; cargo test -p
v1-compiler --lib cli_run:: green except one pre-existing,
unrelated flake (test_migration_delete_guard, its own separate
git-diff plumbing, reproduces identically on this exact commit
before this change too). .dag witnesses re-verified green under
--wet (real shell execution, not the hermetic mock).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@gunbai-bot
gunbai-bot Bot marked this pull request as ready for review July 5, 2026 20:45
Review finding (claude/claude-opus-4-7 on #6297): the existing
malformed-rename-score witness only checked the first entry's status,
not that token-alignment corruption downstream of an unscored R/C
token stays observable as Unknown. Adds
w_malformed_rename_score_corruption_stays_fail_closed_downstream,
which feeds a malformed rename token followed by further tokens
through parse_git_diff_name_status_z and asserts
git_diff_status_entries_any_unknown still holds - so
floor_name_status_diff_from_reconciliation always routes to
NameStatusDiffFail on this input, never a silently-corrupted
NameStatusDiffOk.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@gunbai-bot

gunbai-bot Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor Author

Addressed both findings from the claude/claude-opus-4-7 review:

  1. git.dag:70-83 malformed rename-score corruption — valid, fixed in ba41eb7. Added w_malformed_rename_score_corruption_stays_fail_closed_downstream, which feeds an unscored R token followed by further tokens through parse_git_diff_name_status_z and pins that git_diff_status_entries_any_unknown still holds despite the token-alignment corruption — so floor_name_status_diff_from_reconciliation always routes to NameStatusDiffFail on this input, never a silently-corrupted NameStatusDiffOk. Verified green under --wet (real execution).

  2. cli_run.rs:5175 empty changed_paths when skip_unaffected_node_frontier: false — verified not an issue. changed_paths is only read inside run_discovery_rows's if skip_enabled branch (calls to call_floor_host_scaffold_would_skip/call_floor_kernel_would_skip at lines ~5517/5526), and skip_enabled is unconditionally false in that mode (set at the call site), so should_skip short-circuits to false before changed_paths is ever touched. No other consumer reads it. Confirmed by re-reading the full call chain; no fix needed.

— sent from nimble-otter-431

briansrls and others added 2 commits July 5, 2026 21:08
…stream

Cursor review on #6297 (composer-2.5, REQUEST_CHANGES) flagged two issues:

1. git_diff_status_entry_is_unknown was a hand-rolled match-based
   is-variant predicate; the codebase already has a canonical idiom for
   this (discriminant(v: ...) equality, see affected_set.dag's
   universe_has_process_of_kind and model_core.dag's axis dispatch).
   Dissolved into an inline discriminant comparison in the fold step.

2. parse_git_diff_name_status_z discarded final_state.pending after
   folding tokens, so a truncated/incomplete git diff --name-status -z
   stream (e.g. a trailing status letter or rename pair with no
   closing path token) silently produced entries == [] - indistinguishable
   from a legitimately empty diff. This is exactly the widen-instead-of-
   refuse failure DESIGN.md S5 forbids (state-space conflation between
   "nothing changed" and "observation is corrupt").

   Split parse_git_diff_name_status_z into
   git_diff_name_status_parse_state (exposes the full fold state) +
   git_diff_name_status_parse_state_is_truncated (checks pending is
   terminal). floor_name_status_diff_from_reconciliation now refuses
   with a typed NameStatusDiffFail on a non-terminal pending state
   before trusting entries.

New witnesses pin both: w_lone_trailing_status_token_is_typed_truncated_not_empty,
w_rename_missing_new_path_is_typed_truncated_not_empty,
w_complete_stream_is_never_flagged_truncated.

Verified via claim_batch --wet (real fold execution, not hermetic mock).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@gunbai-bot

gunbai-bot Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor Author

Addressed both cursor/composer-2.5 REQUEST_CHANGES findings with fix commits:

  1. git_diff_status_entry_is_unknown predicate dissolution — confirmed valid; the codebase has an established discriminant(v: ...)-equality idiom for exactly this (e.g. affected_set.dag's universe_has_process_of_kind, model_core.dag's axis dispatch). Replaced the hand-rolled match-based predicate with an inline discriminant comparison in the fold step (git_diff_status_entries_any_unknown).

  2. Truncated-stream fail-open — confirmed valid and the more serious of the two: parse_git_diff_name_status_z was discarding final_state.pending after folding tokens, so a genuinely incomplete git diff --name-status -z stream (e.g. a trailing status letter with no path, or a rename pair missing its new-path token) silently produced entries == [], indistinguishable from a legitimately empty diff — the exact widen-instead-of-refuse conflation DESIGN.md S5 forbids.

    Fixed by splitting parse_git_diff_name_status_z into git_diff_name_status_parse_state (exposes the full fold state) + git_diff_name_status_parse_state_is_truncated (checks pending is terminal). floor_name_status_diff_from_reconciliation now refuses with a typed NameStatusDiffFail on non-terminal pending state before trusting entries.

Both pinned with new witnesses in extdeps_git_diff_name_status_witness_test.dag and verified green via claim_batch --wet (real fold execution).

— sent from nimble-otter-431

briansrls and others added 2 commits July 5, 2026 21:24
Cursor review on #6297 (composer-2.5, REQUEST_CHANGES) on the previous
fix: the workflow consumer was guarded, but the exported convenience
parse_git_diff_name_status_z still projected only .entries and dropped
pending, so any OTHER caller of the extdeps authority could still get
an empty-looking result from a truncated stream. A sibling *_is_truncated
validator alongside a lossy accessor keeps the hazard structurally
possible, not unrepresentable.

Replaced parse_git_diff_name_status_z with a single parse authority,
git_diff_name_status_parse, returning an outcome coproduct:
GitDiffNameStatusComplete { entries } | GitDiffNameStatusTruncated
{ pending, entries }. There is no accessor that yields entries without
also naming which outcome produced them - truncation can't be silently
dropped by a future caller. floor_name_status_diff_from_reconciliation
now matches the outcome directly instead of calling a separate
state+is_truncated pair.

Witness test updated to consume the outcome coproduct (test-local
well_formed_entries/is_truncated helpers over the outcome, not a
reintroduction of the lossy accessor), plus a new witness pinning that
Complete and Truncated are distinct variants
(w_truncated_outcome_is_a_distinct_variant_from_complete).

Verified via claim_batch --wet (real fold execution).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@gunbai-bot

gunbai-bot Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor Author

Addressed cursor/composer-2.5's follow-up REQUEST_CHANGES finding: confirmed valid — the workflow consumer was guarded, but the exported parse_git_diff_name_status_z still projected only .entries and silently dropped pending, so any other caller of the extdeps authority could still observe an empty-looking result from a truncated stream.

Fixed by replacing it with a single parse authority, git_diff_name_status_parse, returning an outcome coproduct: GitDiffNameStatusComplete { entries } | GitDiffNameStatusTruncated { pending, entries }. There is no longer any accessor that yields entries without naming which outcome produced them — truncation is unrepresentable as silence now, not just checked by a sibling validator. floor_name_status_diff_from_reconciliation matches the outcome directly.

New witness w_truncated_outcome_is_a_distinct_variant_from_complete pins that Complete/Truncated are distinct variants; existing witnesses updated to consume the outcome coproduct. Verified via claim_batch --wet.

— sent from nimble-otter-431

@briansrls
briansrls merged commit 69cce49 into main Jul 5, 2026
1 of 2 checks passed
@briansrls
briansrls deleted the session/nimble-otter-431 branch July 5, 2026 22:20
briansrls added a commit that referenced this pull request Jul 5, 2026
Run 28757531898 @ e65f569: rust gate still failed cannot cast
String — stdout_lines projects plain strings; List<FilePath>
mismatch bit when git_success triggers should_run_gates path
selection. Revert DiffNameOnly/Merge path grain to List<String>
until interpreter brands stdout_lines (dissolve-on: #6297 host).

Co-authored-by: Cursor <cursoragent@cursor.com>
briansrls added a commit that referenced this pull request Jul 5, 2026
Run 28757531898 @ e65f569: rust gate still failed cannot cast
String — stdout_lines projects plain strings; List<FilePath>
mismatch bit when git_success triggers should_run_gates path
selection. Revert DiffNameOnly/Merge path grain to List<String>
until interpreter brands stdout_lines (dissolve-on: #6297 host).

Co-authored-by: Cursor <cursoragent@cursor.com>
briansrls added a commit that referenced this pull request Jul 5, 2026
Run 28757870966 @ e69f7cd: rust_tests still failed cannot cast
String — #6297 models List<FilePath> from stdout_lines but the host
projected plain strings; cast targets with empty authored names also
missed FilePath = String alias resolution. Resolve string-family cast
seeds through inferred types and coerce stdout_lines list elements.

Co-authored-by: Cursor <cursoragent@cursor.com>
briansrls added a commit that referenced this pull request Jul 6, 2026
Run 28757531898 @ e65f569: rust gate still failed cannot cast
String — stdout_lines projects plain strings; List<FilePath>
mismatch bit when git_success triggers should_run_gates path
selection. Revert DiffNameOnly/Merge path grain to List<String>
until interpreter brands stdout_lines (dissolve-on: #6297 host).

Co-authored-by: Cursor <cursoragent@cursor.com>
briansrls added a commit that referenced this pull request Jul 6, 2026
Run 28757870966 @ e69f7cd: rust_tests still failed cannot cast
String — #6297 models List<FilePath> from stdout_lines but the host
projected plain strings; cast targets with empty authored names also
missed FilePath = String alias resolution. Resolve string-family cast
seeds through inferred types and coerce stdout_lines list elements.

Co-authored-by: Cursor <cursoragent@cursor.com>
briansrls added a commit that referenced this pull request Jul 6, 2026
* WIP: InterfaceSummary v0: std carrier + first consumer

* InterfaceSummary v0: rebase onto main (1a19d49).

Std carrier + lens + firewall witness + export_signature_facts host bridge.
CI interim budgets (split build/floor/rust-gate, 30min build, floor_diff
relative roots). Replayed cleanly — no unrelated main reverts.

Co-authored-by: Cursor <cursoragent@cursor.com>

* WIP: InterfaceSummary v0: std carrier + first consumer

* WIP: InterfaceSummary v0: std carrier + first consumer

* WIP: InterfaceSummary v0: std carrier + first consumer

* WIP: InterfaceSummary v0: std carrier + first consumer

* WIP: InterfaceSummary v0: std carrier + first consumer

* WIP: InterfaceSummary v0: std carrier + first consumer

* WIP: InterfaceSummary v0: std carrier + first consumer

* WIP: InterfaceSummary v0: std carrier + first consumer

* WIP: InterfaceSummary v0: std carrier + first consumer

* WIP: InterfaceSummary v0: std carrier + first consumer

* WIP: InterfaceSummary v0: std carrier + first consumer

* WIP: InterfaceSummary v0: std carrier + first consumer

* WIP: InterfaceSummary v0: std carrier + first consumer

* WIP: InterfaceSummary v0: std carrier + first consumer

* ci: retrigger PR checks after rust gate timeout fix (b79ba13).

Co-authored-by: Cursor <cursoragent@cursor.com>

* WIP: InterfaceSummary v0: std carrier + first consumer

* fix: git diff name-only paths stay List<String> at runtime.

Run 28757531898 @ e65f569: rust gate still failed cannot cast
String — stdout_lines projects plain strings; List<FilePath>
mismatch bit when git_success triggers should_run_gates path
selection. Revert DiffNameOnly/Merge path grain to List<String>
until interpreter brands stdout_lines (dissolve-on: #6297 host).

Co-authored-by: Cursor <cursoragent@cursor.com>

* WIP: InterfaceSummary v0: std carrier + first consumer

* fix: brand stdout_lines for String-family list types at runtime.

Run 28757870966 @ e69f7cd: rust_tests still failed cannot cast
String — #6297 models List<FilePath> from stdout_lines but the host
projected plain strings; cast targets with empty authored names also
missed FilePath = String alias resolution. Resolve string-family cast
seeds through inferred types and coerce stdout_lines list elements.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix: restore fold_list in complexity_r1_accumulator_copy.

Run 28758528714 @ 03e3238: ci floor failed discovery corpus —
fold is not in v2 scope; r1_copied_port_index must use fold_list
from v2.std.algebra (same as main).

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix: rustfmt v1_interpreter stdout_lines map closure.

Run 28759362798 @ 1c12890: rust_tests failed cargo fmt --check
on the multiline map closure in map_shell_outputs.

Co-authored-by: Cursor <cursoragent@cursor.com>

* WIP: InterfaceSummary v0: std carrier + first consumer

* WIP: InterfaceSummary v0: std carrier + first consumer

* WIP: InterfaceSummary v0: std carrier + first consumer

* WIP: InterfaceSummary v0: std carrier + first consumer

* WIP: InterfaceSummary v0: std carrier + first consumer

* WIP: InterfaceSummary v0: std carrier + first consumer

* WIP: InterfaceSummary v0: std carrier + first consumer

* WIP: InterfaceSummary v0: std carrier + first consumer

* WIP: InterfaceSummary v0: std carrier + first consumer

* WIP: InterfaceSummary v0: std carrier + first consumer

* WIP: InterfaceSummary v0: std carrier + first consumer

* WIP: InterfaceSummary v0: std carrier + first consumer

* WIP: InterfaceSummary v0: std carrier + first consumer

* WIP: InterfaceSummary v0: std carrier + first consumer

* WIP: InterfaceSummary v0: std carrier + first consumer

* WIP: InterfaceSummary v0: std carrier + first consumer

* WIP: InterfaceSummary v0: std carrier + first consumer

* WIP: InterfaceSummary v0: std carrier + first consumer

* WIP: InterfaceSummary v0: std carrier + first consumer

* WIP: InterfaceSummary v0: std carrier + first consumer

* WIP: InterfaceSummary v0: std carrier + first consumer

* WIP: InterfaceSummary v0: std carrier + first consumer

* WIP: InterfaceSummary v0: std carrier + first consumer

* WIP: InterfaceSummary v0: std carrier + first consumer

* Raise rust gate CI budgets so reconcile+nextest fit the step cap.

gunbc run rust_gates_ci reconcile consumed ~22m before fmt/clippy/nextest on d7dc35e, leaving nextest killed at the 30m step timeout; bump gate to 45m, warm to 46m (warm>gate witness), and rust_tests job backstop to 106m.

Co-authored-by: Cursor <cursoragent@cursor.com>

* WIP: InterfaceSummary v0: std carrier + first consumer

* Inline bare == aliases and drop unused Bool imports (review 36011).

Remove rel_path_eq/module_path_eq nicknames per §3; use == directly.
Drop dead Bool imports from firewall_body fixtures.

Co-authored-by: Cursor <cursoragent@cursor.com>

* WIP: InterfaceSummary v0: std carrier + first consumer

* Fail-closed module_key imports and add export_signature host scaffold receipt.

- Add v2.std.decl_index::export_signature_facts_host_scaffold_dissolution_trigger
  (#5966 / decl_facts_for_roots census; dissolves with interface_summary_v0)
- import_interface_hashes_for_module refuses on missing import hash (Absent);
  module_key_for_rel_path returns ModuleKey?
- Witnesses: scaffold receipt cites #5966; unresolved import → Absent

Addresses Composer REQUEST_CHANGES review 36013.

Co-authored-by: Cursor <cursoragent@cursor.com>

* WIP: InterfaceSummary v0: std carrier + first consumer

* Raise CI floor step budget after 135m timeout on batch-1 compile-clean.

Receipt run 28786036501 @ 6527d01: plan resolve ~74m plus batch-1
reconcile ~53m exhausted the 135m floor step cap before batch-2.
Floor step 135→200m; ci job backstop 190→255m.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Convert interface_summaries_from_facts to fold (missing fold_list import).

Review 36025: fold_list call survived sibling refactors without its
v2.std.algebra import; use fold + list_snoc_item like the rest of the file.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Raise CI floor step to 300m after 200m timeout on batch-1 reconcile.

Receipt run 28794864868 @ c3e2093: plan resolve ~73m, batch-1 first
reconcile ~52m, killed at 200m cap during second reconcile before
batch-1 finished. Floor 200→300m; ci job backstop 255→355m.

Co-authored-by: Cursor <cursoragent@cursor.com>

* WIP: InterfaceSummary v0: std carrier + first consumer

* ci: restore step-level ci job backstop for floor completion.

The 10m starvation-kill (#6323) cancelled the ci job mid plan-resolve
(receipt: run 28811397826 @ 304fe94 — floor still in typecheck at t+8m).
Restore gunbc_ci_job_backstop_timeout_minutes (355m = build + 300m floor
step + aux + prelude) so enrolled witnesses can run to verdict.

Co-authored-by: Cursor <cursoragent@cursor.com>

* ci: align timeout disposition with live step-level backstop.

gunbc_ci_job_timeout_policy_disposition now documents the active policy
(ci_job emits gunbc_ci_job_backstop_timeout_minutes = 355m, RED-by-step-
failure). Retire unused gunbc_ci_floor_job_runner_starvation_kill_minutes;

Co-authored-by: Cursor <cursoragent@cursor.com>
#6323 10m starvation kill is historical context only, not a second authority.

* ci: restore 10m ci/floor job and 30m rust_tests job caps.

Operator request: lower job timeouts from interim 355m/106m back to
10m starvation-kill on ci job and 30m on rust_tests. Disposition
updated to match live policy.

Co-authored-by: Cursor <cursoragent@cursor.com>

* ci: drop unused rust job backstop helper

Co-authored-by: Cursor <cursoragent@cursor.com>

* WIP: InterfaceSummary v0: std carrier + first consumer

* ci: fix 10m job kill aborting release build before floor.

Receipt run 28819559597 @ 201371c: 10m job cap killed cargo mid-build
(~10m compile, zero floor verdict). Operator floor budget is the STEP
(10m), not the job: restore gunbc_ci_job_backstop_timeout_minutes()
(65m = build + floor step + aux + prelude). Align rust_tests steps
(15m warm, 10m gate) to fit 30m job cap.

Co-authored-by: Cursor <cursoragent@cursor.com>

* ci: add value-Measure dissolve-on marker for rust_tests job timeout.

Piggyback gunbc_ci_rust_tests_job_timeout_minutes_measure_grounding_
dissolution_trigger on the existing floor-step marker family (Opus 36075
non-blocking finding).

Co-authored-by: Cursor <cursoragent@cursor.com>

* ci: restore rust_tests step-sum job backstop (Composer 36079).

Remove fixed 30m gunbc_ci_rust_tests_job_timeout_minutes — job cap was
shorter than step budgets, producing cancelled silent-pass instead of
RED-by-step-failure. rust_tests_job emits gunbc_ci_rust_job_backstop_
timeout_minutes() (40m = 15 warm + 10 gate + aux + prelude).

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Brian Searls <briansrls@gunb.ai>
Co-authored-by: Cursor <cursoragent@cursor.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant