Skip to content

compass(detect): the set-iteration lint over atom/compass, carried from #96 - #512

Merged
jgong5 merged 6 commits into
feature/atomcompass_newfrom
compass/issue-487-set-iteration-lint
Sep 30, 2026
Merged

jgong5 merged 6 commits into
feature/atomcompass_newfrom
compass/issue-487-set-iteration-lint

Conversation

@jgong5

@jgong5 jgong5 commented Sep 30, 2026 •

Copy link
Copy Markdown
Owner

Closes #487. Ready for review. No blocking issues.

Adds atom/compass/detect/set_iteration.py, carried from #96 at ee5b591dc, and gates atom/compass with it in tests/compass/test_set_iteration_lint.py. Stacked on #511, whose ClockSourceLint.modules, scopes and scope_at it imports.

Dev record

Named result

atom/compass goes from 2 reported sites at 0e16d3a98 to 0 at the head, both settled in code.

Gates

Evidence

Revert-red: one line-preserving edit of the head tree each, run over tests/compass/test_set_iteration_lint.py (89 pass unedited).

edit failed red node
capture_token_shapes back to tuple(sorted(s for s in shapes if ...)) 1 test_the_simulated_path_is_clean_today: assert 1 == 0
_sorted_away and its call reinstated 1 test_every_form_it_claims_to_report_is_reported[sorted-generator]: assert () != ()
connector.py back to 0e16d3a98 1 test_the_simulated_path_is_clean_today: assert 1 == 0
ClockSourceLint.modules walks the top directory only 1 test_the_simulated_path_is_clean_today: kv/connector.py not among the scanned modules

The last two rows are from eb29a5a92; neither line changed since. Reinstating the exemption is not line-preserving; no test in the file reads line numbers of set_iteration.py.

capture_token_shapes old and new forms return equal tuples on 2004 inputs: four fixed ladders and 2000 random ones, with empty ladders and a zero budget among them.

Changes to the carried code, relative to ee5b591dc:

  • set_iteration.py: +9 / -6 lines. The public scopes and scope_at imports, one docstring sentence saying a comprehension under sorted is reported, and a _binds docstring that states no count.
  • Test file: the set-iteration tables, the reading_sets fixture and TestTheSetIterationLint, with a new module docstring and the walk assertion. It adds the sorted-generator fire form and leaves out the clock-source cases, which are in compass(detect): the clock-source lint over atom/compass, without asyncio.sleep #511.
  • connector.py: 3 lines changed. graph_pool.py: 1 line changed.

Cost, as docstring-inclusive AST statements / non-blank physical lines at 0554449a3:

  • set_iteration.py: 278 / 486 (carried 278 / 483).
  • Test file: 103 / 527.

Generated with Claude Code

jgong5 and others added 2 commits September 30, 2026 06:36
…ncio.sleep

Carries ClockSourceLint from the closed #96 head (ee5b591) with its
anchored read comparison, and its tests from #91 and #96, into
atom/compass/detect/clock_source.py and tests/compass/test_clock_source_lint.py.

Changes from the carried module:
- asyncio.sleep leaves CLOCK_READS: an asyncio timer runs on the event
  loop's clock, which a simulated run replaces.
- The watchdog allow-list entry goes with the watchdog; the list is empty.
- The unused enabled flag and scan_tree are dropped.

The lint is clean over atom/compass at the tip.

Closes #101.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A static pass that reports every read of a set in hash order under
atom/compass: file, line, form and enclosing symbol, parsed with ast.
Membership is not reported. Carried from ee5b591, stacked on the
clock-source lint (#511) whose module walk and scope lookup it reuses,
with two settlements of the sites it reports at the tip:

- a comprehension handed straight to sorted() is not a read; it is the
  same remedy as sorted(s) with a filter
  (graph_pool.capture_token_shapes);
- SimulatedKVConnector._matured collects the finished requests in a
  list in the dict's own order, so no set is iterated.

The tests move to tests/compass/test_set_iteration_lint.py; the
clock-source cases they shared are in #511.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@jgong5
jgong5 added this pull request to stack #513 September 30, 2026 06:57
…old recursion, alias chains and innermost scope

check() refuses a root holding no module, so a mistyped path no longer
reports clean over zero modules. The seeded read sits one directory down,
so the walk's recursion is held; the clean-line test checks a single file,
so the file-root branch that #512 relies on is held too.

CLOCK_READS_THAT_FIRE pairs each spelling with its exact report line,
which folds in the three exact-report tests and the datetime test and adds
alias-of-alias and innermost-scope cases. _scopes and _scope_at become
scopes and scope_at for the set-iteration lint.

Dropped: the believable-number test (it ran no repository code), the
CLOCKS_HANDED_AROUND table (it asserted blind spots), main and argparse
(no caller), scan_modules (one caller, inlined). The alias-expansion
record is a set.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Comment thread atom/compass/detect/set_iteration.py Outdated
yield from _scoped(child, inner)


def _sorted_away(tree) -> set:

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

REQUEST CHANGES, required 1. A call in the element or filter still runs in the set's order and is not reported: sorted(ids.take(x) for x in s) gives (), the same body as a for loop is reported. Delete _sorted_away and write capture_token_shapes as tuple(s for s in sorted(shapes) if s <= max_num_batched_tokens); atom/compass is then clean. Or exempt only an element and filters with no Call, NamedExpr, Await or Yield, with a fire form.

SIMULATED_PATH = os.path.dirname(atom.compass.__file__)

#: A step loop that reads its participants out of a set every way the pass
#: claims to see, and seven more it does not. Everything here runs; nothing

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

REQUEST CHANGES, required 2. seven more counts BEYOND_THE_PARSER and goes stale when an entry moves, as do Two false positives (module docstring) and Half of these (above FORMS_THAT_STAY_QUIET). Drop the numbers.

code, report = lint.check(SIMULATED_PATH)
assert code == 0
assert report == (
f"set-iteration lint: clean over {len(lint.modules(SIMULATED_PATH))} "

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No blocking issues; ponytail. The second lint.modules(SIMULATED_PATH) walks the tree again. Use len(scanned).

@jgong5

jgong5 commented Sep 30, 2026

Copy link
Copy Markdown
Owner Author

Review, round 1. Verdict: CHANGES NEEDED. REQUEST CHANGES: 2 blocking, head eb29a5a92, own commit only (7d59d13b0..eb29a5a92).

Required:

  1. _sorted_away hides a call in the element or filter, which still runs in the set's order (inline). It buys one site; sorting the set first in capture_token_shapes instead is clean and about 27 lines shorter.
  2. Three item counts in the test file's prose (inline).

Checked: carried code matches ee5b591dc outside the listed hunks; nothing from the do-not-carry list; #96's lint findings sit in #110, as #487 says; no design-doc references; ruff clean.

Accepted with reservation: the _matured change serves the lint only. Deletion order leaves the same dict, and the issue allows settling a site in code.

Watch next: Scheduler._update_from_kv_xfer_finished iterates the returned sets and deallocates in that order, outside the scan root, while the connector docstring says nothing may turn on it (#466). sorted({x for x in s}) is still reported. #110's exit names tests/compass/clock/test_static_checks.py, now tests/compass/test_set_iteration_lint.py.

Evidence

Probes at the head (scan_source, then with _sorted_away returning an empty set):

source head no exemption
sorted(ids.take(x) for x in s) () comprehension over s
sorted([x for x in s if log.append(x) is None]) () comprehension over s
sorted((next(counter), x) for x in s) () comprehension over s
same body as a for loop appending ids.take(x) for-loop over s for-loop over s
sorted(x for x in s if x <= m) () comprehension over s

Over atom/: 35 reads with the exemption, 36 without; the one silenced is capture_token_shapes. With no exemption and that line written as tuple(s for s in sorted(shapes) if s <= max_num_batched_tokens), atom/compass gives no reads, and the two forms return equal tuples on three inputs.

Revert-red on tests/compass/test_set_iteration_lint.py (92 pass unedited, null-comment control 92 pass), one line-preserving edit each:

edit result red node
_matured back to 7d59d13b0 1 failed / 91 test_the_simulated_path_is_clean_today
exemption off 3 failed / 89 the same, plus [sorted-generator], [sorted-list-comprehension]
sorted by attribute tail 1 failed / 91 [method-named-sorted]
every comprehension under the argument 1 failed / 91 [comprehension-inside-a-sorted-element]
ListComp dropped 1 failed / 91 [sorted-list-comprehension]

Ponytail review: the exemption and its four test forms can go (above); len(lint.modules(SIMULATED_PATH)) can be len(scanned). net: -27 lines possible.

Generated with Claude Code

jgong5 and others added 2 commits September 30, 2026 07:19
Base update. #511 publishes `scopes` and `scope_at` (formerly `_scopes` and
`_scope_at`, same signatures) and deletes `ClockSourceLint.scan_modules` and
`main`. `set_iteration.py` now imports the public names, and the local that
held the spans is renamed `enclosing` so it does not shadow `scopes`.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…t first in capture_token_shapes

A comprehension's element and filter run in the set's order before `sorted`
sees them, so `sorted(ids.take(x) for x in s)` is an order dependence the
exemption hid. The exemption and its test forms are gone; the fire list
carries that case instead. `capture_token_shapes` sorts the set before
filtering, which returns the same tuple and reads no set in hash order.

The test file's prose no longer states item counts, and the clean-today
assertion reuses the scanned module list instead of walking the tree twice.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@jgong5

jgong5 commented Sep 30, 2026

Copy link
Copy Markdown
Owner Author

Round 2 pushed 0554449. Both required findings fixed; the ponytail comment taken.

7911684be merges #511 at 8056b1933 and imports scopes and scope_at; the local is now enclosing. 0554449a3 deletes _sorted_away, and capture_token_shapes sorts the set before filtering. The Scheduler._update_from_kv_xfer_finished watch item is recorded in the body for #466.

branch @ 0554449a3: 5327 passed, 155 skipped, 3 xfailed, GATE_CPU_RC=0; control #511 @ 8056b1933 5238 passed, the +89 are this test file.

Findings, fixes and reds

Each defect reinstated on the head tree, over tests/compass/test_set_iteration_lint.py (89 pass unedited, 92 at the merge commit before the form changes).

finding fix reinstated defect reddens
1 exemption hides calls _sorted_away deleted with its two quiet forms and two fire forms; sorted(ids.take(x) for x in s) added as fire form sorted-generator exemption back: test_every_form_it_claims_to_report_is_reported[sorted-generator], assert () != ()
1 capture_token_shapes tuple(s for s in sorted(shapes) if s <= max_num_batched_tokens); equal to the old form on 2004 inputs old line back: test_the_simulated_path_is_clean_today, assert 1 == 0
2 item counts "seven more", "Two false positives" and "Half of these" reworded none: prose
ponytail len(scanned) the report assertion reuses scanned none: no behaviour change
base update set_iteration.py imports the public names old import back: collection error, ImportError: cannot import name '_scope_at'

ruff 0.16.7 check rc 0, format and black clean on the three changed files.

Generated with Claude Code

"augmented": "def f(n, t):\n s = set(n)\n s |= t\n for x in s:\n yield x\n",
"typing-Set": "from typing import Set\n\n\ndef f(r: Set[str]):\n return [x for x in r]\n",
"string-annotation": 'def f(r: "set[str]"):\n return [x for x in r]\n',
"sorted-generator": "def f(s: set[str], ids):\n return sorted(ids.take(x) for x in s)\n",

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No blocking issue. A list comprehension handed to sorted has no fire form, so only the generator case is held. Put the exemption back for ast.ListComp alone and tests/compass still passes: 1371 passed, 6 skipped. Add one beside this form, e.g. sorted([ids.take(x) for x in s]).

@jgong5

jgong5 commented Sep 30, 2026

Copy link
Copy Markdown
Owner Author

Review, round 2. Verdict: APPROVE. APPROVE at head 0554449a392538ff1e2197d99b7538f5b10b2c75, delta eb29a5a92..0554449a3.

Both round-1 findings are closed:

  1. _sorted_away is deleted. With it back as it was at eb29a5a92, test_every_form_it_claims_to_report_is_reported[sorted-generator] fails.
  2. The three item counts in the test file's prose are gone.

Checked: the merge 7911684be resolves only the rename to scopes and scope_at. The body records the graph_pool.py change and why it was made. No design-doc references. ruff check and format are clean on the four changed files.

Accepted with reservation: a list comprehension handed to sorted has no fire form (inline).

Watch next: #511 has not landed. The stacked form below takes #511 onto the current tip first. The literal merge-tree --merge-base 8056b1933 91e19c53b <head> deletes clock_source.py, because #511 is not on the tip yet.

Evidence

The stacked tree is the head tree plus #478's three files (sync_sites.json, cliargs.rs, worker_manager.rs), none of them in this PR.

Reinstated on the head tree and run over tests/compass/test_set_iteration_lint.py (89 pass unedited):

edit lines result red node, assertion
null control: 17 comment lines where the exemption goes +17 89 passed none
exemption as at eb29a5a92 +17 1 failed / 88 [sorted-generator], assert () != ()
exemption for ast.GeneratorExp only +17 1 failed / 88 [sorted-generator], assert () != ()
exemption for ast.ListComp only +17 89 passed; tests/compass 1371 passed, 6 skipped none
capture_token_shapes back to eb29a5a92 0 1 failed / 88 test_the_simulated_path_is_clean_today, assert 1 == 0

Ponytail review of the delta: Lean already. Ship.

Generated with Claude Code

Base automatically changed from compass/issue-488-clock-source-lint to feature/atomcompass_new September 30, 2026 08:03
…ass/issue-487-set-iteration-lint

Base update only. One add/add conflict in tests/compass/test_clock_source_lint.py,
resolved by taking the integration tip's version unchanged (the final version of #511;
this branch carried an earlier round of it and never changed the file itself).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@jgong5

jgong5 commented Sep 30, 2026

Copy link
Copy Markdown
Owner Author

Base update pushed 1be46ea. No blocking issues.

Merged fork/feature/atomcompass_new @ 073cebf (#511 landed). No code change of this PR's own.

@jgong5

jgong5 commented Sep 30, 2026

Copy link
Copy Markdown
Owner Author

Review, round 3. Verdict: APPROVE. APPROVE at head 1be46ea86a504ccf264fe4580eda55b396a3dc1a, delta 0554449a3..1be46ea86, one base-update merge of 073cebf25 (#511).

Checked: the only remerge hunk is the add/add in tests/compass/test_clock_source_lint.py, taken as the tip's version. On this branch only #511's own commits 7d59d13b0 and 8056b1933 touched that file, so the tip's version (#511 final) drops nothing. 1be46ea86^2..1be46ea86 is exactly this PR's four files. Head tree is 307d31ba9, the tree gated in #511's final review (5330 passed, rc 0), so no new gate run. merge-tree --write-tree against the tip 073cebf25 gives the same tree.
Accepted with reservation: none.
Watch next: none beyond round 2.

Generated with Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

module: compass-detect atom/compass/detect/ and its tests module: compass-kv atom/compass/kv/ and its tests module: compass-memory atom/compass/memory/ and its tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant