Skip to content

fix(swift): capture single-letter imports - #2628

Open
kanishk083 wants to merge 1 commit into
squid-protocol:mainfrom
kanishk083:fix/swift-import-regex
Open

fix(swift): capture single-letter imports#2628
kanishk083 wants to merge 1 commit into
squid-protocol:mainfrom
kanishk083:fix/swift-import-regex

Conversation

@kanishk083

Copy link
Copy Markdown

Description

Swift's _dependency_capture required an initial identifier character followed by one or more
[\w.] characters. This made module names at least two characters long, so a valid single-letter
import such as import a was silently omitted from the dependency DAG.

This changes the tail quantifier from + to *, preserving existing imports while accepting
single-letter module names.

Changes

  • Accept single-letter Swift module names.
  • Add import a as a regression case.
  • Ensure bare import remains invalid.
  • Add adversarial ReDoS and scaling coverage.

Validation

  • Swift extraction and strict suites: 130 passed
  • Real compiled-regex candidates: 4/4 passed
  • Scaling sweep: linear behavior
  • AST accuracy audit: passed
  • git diff --check: passed
  • Full-suite run: 7,146 passed, 14 skipped, 2 deselected, 9 xfailed, 3 xpassed, and 15 failed
  • The dependency-related failures passed after installing their expected optional dependencies: 31
    relevant tests passed
  • The two remaining failures are Windows-host constraints involving CP1252 console output and
    symlink privileges
  • No golden-master or baseline files changed

Core Engine Modification Checklist

  • Golden Master Verification: Both Crucible engine scans completed across 2,817 files, but
    the Windows wrapper failed afterward while printing a Unicode timing glyph. Linux CI is
    authoritative.
  • Tri-Comparison Audit: Requires ctags, which was unavailable locally; handled
    automatically by CI.
  • Tree-Sitter Accuracy: Local execution was blocked by Windows corpus path handling; Linux
    CI is authoritative.

Proof

Cross-repo

No companion code change is required. The control-corpus reproducer already exists. Rerun the Swift
corpus ledger after this engine change lands.

Fixes #2543

Allow Swift dependency capture to retain modules such as a by accepting an empty identifier tail after the initial character. Add regression and adversarial scaling coverage.

Refs squid-protocol#2543

Co-authored-by: Codex <noreply@openai.com>
@kanishk083
kanishk083 marked this pull request as ready for review September 1, 2026 07:51
@kanishk083

Copy link
Copy Markdown
Author

The Rosetta failure is the expected result of this fix: a.swift API 0→3, b.swift 1→4, and
c.swift 0→3.

Would you prefer that I open the companion keyword-rosetta re-baseline PR, or will you handle it
with the pin update?

The Crucible/tree-sitter/tri-comparison failures occurred before testing because
LANGUAGE_CRUCIBLE_REF expanded to an empty value.

@squid-protocol

Copy link
Copy Markdown
Owner

Thanks for this! Your diagnosis is correct on both counts, and
the second one is our bug, not yours.

The Crucible / tree-sitter / tri-comparison failures are ours. You're right that
LANGUAGE_CRUCIBLE_REF expanded to empty. The variable is set (v1.2.0), but GitHub doesn't
expose repository variables to pull_request runs from forks, so those four workflows run
git clone --branch "" and die before your code is ever exercised. rosetta-audit happens to
guard this with || 'main'; the crucible-family workflows don't. Yours is the first fork PR
this repo has had in a long while, which is why nobody had hit it. We're fixing that in a
separate PR and adding a note to CONTRIBUTING.md so the next contributor isn't left guessing.
Nothing for you to do there.

The Rosetta failure is real and is the gate working as intended. Your read is exactly right:
this is case 2 in docs/self_scan/BUMPING_THE_ROSETTA_PIN.md — an intentional, corpus-visible
improvement. The corpus plants single-letter module names deliberately, and data/swift/expected_signals.json
locks in the old behaviour ("import a never resolves and popularity stays 0"). Once the chain
resolves, orphan→api conversion fires and you get exactly the 0→3 / 1→4 / 0→3 you observed.

Nice symmetry worth noting: the corpus is what filed #2543 in the first place. Ledger entry
swift-import-capture-min-two-chars says "the +-quantifier looks unintentional next to other
languages' * shapes." Your PR is what lets that entry flip to still_reproduces: false.

Yes please, go ahead and open the companion keyword-rosetta PR — that'd be great. Pointers:

  • Follow the corpus repo's docs/GATING.md: update data/swift/expected_signals.json, flip
    swift-import-capture-min-two-chars to still_reproduces: false, and refresh the notes
    field (it currently states the 2+ char rule as an invariant).
  • Set the committed ENGINE_REF file to pull/2628/head. That points the corpus gates at this
    unmerged branch so your corpus PR goes green immediately, rather than against main where the
    fix doesn't exist yet.
  • One timing note: corpus PR Feature/edge case tests #20 is currently in flight and still holds ENGINE_REF: pull/2634/head.
    We'll land that first so you don't collide on that file — we'll ping you here when it's clear.
  • Restoring ENGINE_REF to main and bumping KEYWORD_ROSETTA_REF on this side both need repo
    admin, so leave those to us. We'll handle the pin bump once your corpus PR merges, and
    rosetta-audit should go green here on the rerun.

The fix itself looks good — the import invalid case and the ReDoS coverage were the right
things to add. Thanks for the unusually careful writeup, and for catching our CI defect on the
way through.

@squid-protocol

Copy link
Copy Markdown
Owner

Correction to my note above: the coast is already clear — please go ahead now, no need to wait.

I said corpus PR #20 was in flight holding ENGINE_REF and that we'd land it first. That was
wrong. keyword-rosetta#19 had already merged the same re-baseline, corpus main is back to
ENGINE_REF: main, and the pin here already points at it. #20 is a leftover duplicate on our
side and we'll close it — it never had a claim on ENGINE_REF.

So nothing is blocking you: open the corpus PR whenever you like, with ENGINE_REF set to
pull/2628/head. Sorry for the misdirection.

Separately, the four Crucible/tree-sitter/tri-comparison failures now have a fix in #2637 — it
replaces the bare fatal: Remote branch not found with an explicit message saying the pin is
unavailable on fork PRs and that it isn't your change. Thanks again for surfacing it.

squid-protocol added a commit that referenced this pull request Sep 1, 2026
…EF (#2637)

GitHub withholds repository variables -- like secrets -- from pull_request
runs raised from a fork, so `vars.LANGUAGE_CRUCIBLE_REF` expands to an empty
string there and the five corpus-backed workflows ran `git clone --branch ""`,
failing with a bare `fatal: Remote branch  not found in upstream origin`
before any engine code was exercised.

#2628 is the first fork PR this repo has seen in a long while, which is why
this went unnoticed: it arrived with four red audits that had nothing to do
with the contributor's change.

Guard the clone instead of falling back to the corpus's `main`: these pins
exist to make the audits deterministic, and silently auditing against a
different corpus snapshot would trade a confusing failure for an
authoritative-looking wrong answer. The guard fails with an explicit
`::error::` explaining the fork limitation and pointing at CONTRIBUTING.md.

Also document what a fork contributor should expect, and add the
`rosetta-audit` cross-language gate (#2557) to the baselines section -- it
shipped without a CONTRIBUTING entry, so the cross-repo re-baseline protocol
it depends on was undiscoverable from here.

Co-authored-by: Joe Esquibel <squid-protocol@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.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.

swift: _dependency_capture requires 2+ char module names, silently dropping single-letter imports from the DAG

2 participants