{{ message }}
feat(borrow): CORE-01 Slice D (#177 pt3) — reject @linear capture by closure at borrow check#397
Merged
Merged
Conversation
5 tasks
Owner
Author
3 tasks
hyperpolymath
added a commit
that referenced
this pull request
May 27, 2026
…ans + machines) (#401) ## Summary Documents the entire round of work across **six open PRs** that together cover the four entries in the \`lib/borrow.ml\` deferred-items comment at lines 1483-1505. Two artefacts, one for each audience. ### For humans — \`docs/history/SESSION-HANDOFF-2026-05-27.adoc\` \`.adoc\` per the repo's DOC-FORMAT rule. Sections: - What this session actually did - **Parallel-implementation map** — which of my PRs paired with which existing PR - PR state table (draft? auto-merge? mergeability?) - **Audit findings** — the load-bearing deltas: self-assign hole + return-escape gap (#395), sub-place soundness divergence (#396), Cmd-typed-param tracking gap (#397) - **Safe-to-close conditions per PR** — the matrix the next agent needs - Cleanup performed - Guidance for the next agent ### For machines — \`.machine_readable/sessions/2026-05-27-borrow-deferred-items.a2ml\` New \`sessions/\` subdirectory (the existing \`.machine_readable/6a2/\` is the canonical state-snapshot dir; sessions are per-event records). Schema declared as \`a2ml/session-record/v1\`. Structured records: - One \`[[deferred-item]]\` per entry in the comment block - One \`[[open-pr]]\` per the six PRs - One \`[[close-condition]]\` per PR with fallback paths - \`[cleanup]\`, \`[lessons]\` blocks ### Cleanup landed alongside - \`.git/gc.log\` removed after \`git prune\` (the persistent \"unreachable loose objects\" warning is gone). - Two stale parallel-Claude untracked dirs (\`affinescript-vite/\`, \`editors/vscode/node_modules/\`) **not touched** — they're not this session's work. ## What's NOT in this PR - No \`lib/\` changes. No \`test/\` changes. - No closes/state-changes on the six open PRs (#395/#396/#397/#398/#399/#400). Per maintainer direction \"keep both PR sets open\", parallel implementations stay parallel. - No edits to \`STATE.a2ml\` or other \`6a2/\` files — those are flagged STALE and updating them is a separate disciplined task. ## Safe-to-close ledger (also in the docs) | PR | Close condition | Fallback | |---|---|---| | **#395** | auto-merge fires once CI clears | n/a | | **#396** | auto-merge fires once CI clears | if merges without sub-place fix, **#399** stays open as follow-up | | **#397** | auto-merge fires once CI clears | audit posted a must-fix; owner can incorporate or file follow-up | | **#398** | owner ratifies ADR-022 via the posted one-liner | do-not-close — only deferred-item that needs an architectural change | | **#399** | **#396** merges with sub-place fix | rebase as sub-place soundness correction | | **#400** | **#395** merges with self-assign-guard + return-escape test | rebase as follow-up adding the two missing pieces | | **this PR** | safe to close once merged | n/a — pure docs | ## Test plan - [ ] CI green (this PR only touches \`docs/\` and \`.machine_readable/\` — no test-relevant code). - [ ] \`asciidoctor docs/history/SESSION-HANDOFF-2026-05-27.adoc\` renders without errors (if you have asciidoctor installed; CI doesn't enforce). - [ ] The \`docs/history/SESSION-HANDOFF-2026-05-27.adoc\` cross-references in the body resolve to actual PR numbers / file paths in the repo. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…closure at borrow check Tighter integration with the quantity checker for captured linears: the borrow checker now refuses to let a closure capture a @linear (QOne) binding. Pre-Slice-D, this case fell only to the quantity checker (which scales lambda captures by QOmega and emits LinearVariableUsedMultiple); now the same constraint fires earlier in the pipeline (Typecheck → Borrow → Quantity) with a more specific diagnostic that points at the *lambda span* — the actual capture site — rather than the downstream "used multiple times" message. Mechanism: - New [state.linear_bindings] tracks sym-ids of @linear bindings declared in the current function: explicit @linear annotations on `let`-statements and `let`-expressions, @linear function params, and `let x: Cmd[T] = …` (linear-by-construction per ADR-002). - At ExprLambda, collect-free walks the body; for each captured free-name we look up its symbol and reject with [LinearCapturedByClosure name * lambda_span] if the sym-id is in [linear_bindings]. - The Shared-borrow creation for non-linear captures is unchanged. Tests (+3, all green): - slice_d_captured_linear_let_rejected: @linear let captured → LinearCapturedByClosure("x", _) - slice_d_captured_linear_param_rejected: @linear param captured → LinearCapturedByClosure("y", _) - slice_d_captured_nonlinear_ok: anti-regression, non-linear capture must still pass Gate: 327 → 330 tests, 0 failures under `dune runtest --force`. Refs #177, CORE-01 pt3 (Slice D). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
eb66a13 to
04ec7d7
Compare
hyperpolymath
added a commit
that referenced
this pull request
May 27, 2026
…efs #177) — surgical refile of #398 (#407) ## Summary Surgical refile of #398. The original branch `core-01/polonius-adr` carried 386 commits' worth of phantom history (commits with main equivalents at different SHAs after squash-merges), and a naive cherry-pick onto current main would have clobbered the `linear_bindings` work landed today via #397. This branch carries **only** the 3 intended changes from #398: - `docs/decisions/0022-polonius-origin-variables.adoc` (347 lines) — long-form ADR - `.machine_readable/6a2/META.a2ml` (143 lines) — structured `[[adr]]` block - `lib/borrow.ml` (5 lines net) — single in-comment edit in the closing residual-TODO block, pointing readers at ADR-022 Owner ratified the architectural bundle 2026-05-27: OCaml Polonius solver in `lib/borrow_polonius/`, surface-syntax fully elided for v1, M1–M4 stage gates with lexical checker as merge oracle through M3. ## Closes Closes #398 (the stale-base original). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
🔍 Hypatia Security ScanFindings: 56 issues detected View findings[
{
"reason": "Action actions/checkout@v6 needs attention",
"type": "unpinned_action",
"file": "publish-jsr.yml",
"action": "pin_sha",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Action denoland/setup-deno@v2 needs attention",
"type": "unpinned_action",
"file": "publish-jsr.yml",
"action": "pin_sha",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in affine-vscode-publish.yml",
"type": "unknown",
"file": "affine-vscode-publish.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in casket-pages.yml",
"type": "unknown",
"file": "casket-pages.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in casket-pages.yml",
"type": "unknown",
"file": "casket-pages.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in ci.yml",
"type": "unknown",
"file": "ci.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in ci.yml",
"type": "unknown",
"file": "ci.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in ci.yml",
"type": "unknown",
"file": "ci.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in ci.yml",
"type": "unknown",
"file": "ci.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in ci.yml",
"type": "unknown",
"file": "ci.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
}
]Powered by Hypatia Neurosymbolic CI/CD Intelligence |
3 tasks
hyperpolymath
added a commit
that referenced
this pull request
May 30, 2026
#177 (#473) ## Summary - Refresh `docs/TECH-DEBT.adoc` CORE-01 row: ledger listed Slices C' / D / ref-to-ref binding as residual, but those landed (PRs #395 / #396 / #397). - Flip the Stage D ASCII status from `ACTIVE` to `CLOSED`. - Mark the row `CLOSED 2026-05-30`; remaining residual is scoped exclusively to ADR-022 (Polonius origin/region variables) which is a separate, ADR-gated workstream filed at `docs/decisions/0022-polonius-origin-variables.adoc` (PR #407). ## Why now #177 was the issue tracking CORE-01 Phase-3 (borrow-graph validation, S1). The stated scope — adding graph validation plus regression fixtures under `tests/` — has shipped: - **Code:** `lib/borrow.ml:1635-1715` documents pt1 + pt2 (return-escape + `&mut` parser surface) + pt3 Slices A (NLL last-use) / B (flow-sensitive re-assignment) / C-light (CFG-join for `ExprHandle`/`ExprTry`) / C' (loop soundness) / D (linear-capture by closure) + ref-to-ref binding. - **Tests:** `test/test_e2e.ml` "E2E Borrow Graph" suite — **28 hermetic regression tests** (covering each landed slice with positive + anti-regression cases). - **Slices that landed since the ledger was last updated:** #395 (ref-to-ref binding), #396 (Slice C' loop soundness), #397 (Slice D linear-capture), #399 (whole-place assignment clears moves), #400 (self-assign guard + return-escape coverage for ref-to-ref). - **ADR-022 (#407):** Polonius origin/region variables — architectural change to the type system. M1–M4 migration plan in the ADR; lexical checker is the merge oracle through M3. ## Build oracle Local toolchain has an unrelated cross-installation OCaml conflict (`astring.cmxa` from opam vs system `stdlib.cmxa`); using CI-on-main as oracle instead. CI green on `main` at `4f0f3ca7` (2026-05-30 15:19Z) with all CORE-01 work present. ## Test plan - [ ] CI green on this branch - [ ] No code in the diff; doc-only change (no behaviour impact) - [ ] `Closes #177` link resolves on merge Closes #177. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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
Tighter integration with the quantity checker for captured linears: the borrow checker now refuses to let a closure capture a @linear (QOne) binding. Pre-Slice-D, this case fell only to the quantity checker (which scales lambda captures by QOmega and emits `LinearVariableUsedMultiple`); now the same constraint fires earlier in the pipeline (Typecheck → Borrow → Quantity) with a diagnostic that points at the lambda span — the actual capture site — rather than the downstream "used multiple times" message.
Mechanism
Refs
Test plan
🤖 Generated with Claude Code