feat(effects): infer Partial from catch-less try/? + check vs declared row (Refs #59)#207
Merged
Merged
Conversation
… row (Refs #59) STAGE-B effect-tracking spine. Until now ctx.current_eff was declared but never read or mutated — effect inference did nothing, and #59's explicit motivating case ('{Partial} — short-circuit failure, ? on Result') produced no tracking. Root-cause, single concrete effect source for tracking-only v1: - ExprTry with no catch arm (incl. the 'e?' desugar, parser.mly expr_postfix QUESTION) unions Partial into ctx.current_eff; a handled try (catch arm present) discharges it and adds nothing. - check_fn_decl now snapshots/resets current_eff around the body, then — only when an effect row is *explicitly declared* — requires the inferred row ⊆ declared (Effect.eff_subset), erroring with a new EffectNotDeclared type_error. Undeclared rows stay permissive (tracking-only v1), so blast radius is zero: no stdlib/test uses '?' or an explicit row. Other effect sources (IO calls, Async) remain unconstrained for now — deliberately scoped; this stands up the accumulate→subsume path they will plug into, it does not fake full inference. Tests: test/test_effects.ml — declared /{Partial}+? ok; declared /{IO}+? rejected (#59 mismatch naming Partial); undeclared permissive; handled try adds no Partial. Full gate 257/257 (253 + 4, no regression). Refs #59 (left open for user joint-close per requirements-target rule). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This was referenced May 18, 2026
hyperpolymath
added a commit
that referenced
this pull request
May 18, 2026
#209) The #207 squash-merge landed only the code commit; the docs commit (235e161) never reached main, leaving SPEC.adoc §3.4 still showing the retired Exn[Error] and lib/effect.ml still claiming Throws[E] is 'not yet threaded' — both now stale/incorrect on main. Re-landing them: - SPEC.adoc §3.4: Exn[Error] → Throws[E]; new 'Effect inference (tracking-only v1)' subsection (catch-less try/? ⇒ Partial; declared rows enforced inferred⊆declared; undeclared permissive); 'Partial by Default' disambiguated from the Partial effect. - lib/effect.ml: corrected the doc-drift comment (#204 threads Throws[E] via name-mangling in Typecheck.lower_effect_expr). Pure docs/comment; gate unchanged. Refs #59 (closed — lineage only, do not reopen). Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
🔍 Hypatia Security ScanFindings: 44 issues detected
View findings[
{
"reason": "Stray AI.a2ml in root -- use 0-AI-MANIFEST.a2ml only",
"type": "banned",
"file": "AI.a2ml",
"action": "delete",
"rule_module": "root_hygiene",
"severity": "high"
},
{
"reason": "Superseded by 0-AI-MANIFEST.a2ml",
"type": "banned",
"file": "AI.djot",
"action": "delete",
"rule_module": "root_hygiene",
"severity": "high"
},
{
"reason": "Issue in quality.yml",
"type": "missing_workflow",
"file": "quality.yml",
"action": "create",
"rule_module": "workflow_audit",
"severity": "high"
},
{
"reason": "Issue in security-policy.yml",
"type": "missing_workflow",
"file": "security-policy.yml",
"action": "create",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Action hyperpolymath/standards/.github/workflows/governance-reusable.yml@main needs attention",
"type": "unpinned_action",
"file": "governance.yml",
"action": "pin_sha",
"rule_module": "workflow_audit",
"severity": "high"
},
{
"reason": "TypeScript file detected -- banned language",
"type": "banned_language_file",
"file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/example/smoke_driver.ts",
"action": "flag",
"rule_module": "cicd_rules",
"severity": "critical"
},
{
"reason": "TypeScript file detected -- banned language",
"type": "banned_language_file",
"file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/cli.ts",
"action": "flag",
"rule_module": "cicd_rules",
"severity": "critical"
},
{
"reason": "TypeScript file detected -- banned language",
"type": "banned_language_file",
"file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/mod.ts",
"action": "flag",
"rule_module": "cicd_rules",
"severity": "critical"
},
{
"reason": "TypeScript file detected -- banned language",
"type": "banned_language_file",
"file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/lib/compile.ts",
"action": "flag",
"rule_module": "cicd_rules",
"severity": "critical"
},
{
"reason": "TypeScript file detected -- banned language",
"type": "banned_language_file",
"file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/lib/runner.ts",
"action": "flag",
"rule_module": "cicd_rules",
"severity": "critical"
}
]Powered by Hypatia Neurosymbolic CI/CD Intelligence |
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.
STAGE-B effect-tracking spine (issue #59)
ctx.current_effwas declared but never read or mutated — effect inference did nothing, so #59's explicit motivating case ({Partial}— short-circuit failure,?on Result) produced no tracking.Change (root-cause, single concrete source)
ExprTrywith no catch arm — including thee?desugar (parser.mlyexpr_postfix QUESTION) — unionsPartialintoctx.current_eff. A handledtry(catch arm present) discharges it and adds nothing.check_fn_declsnapshots/resetscurrent_effaround the body, then — only when an effect row is explicitly declared — requires inferred ⊆ declared (Effect.eff_subset), erroring with a newEffectNotDeclaredtype_error. Undeclared rows stay permissive (tracking-only v1) ⇒ blast radius zero (no stdlib/test uses?or an explicit row).Other effect sources (IO calls, Async) remain unconstrained — deliberately scoped; this stands up the accumulate→subsume path they plug into, it does not fake full inference.
Tests —
test/test_effects.ml/{Partial}+?→ accepted/{IO}+?→ rejected with the [Repo] Effect-row v1 name list: define IO/Async/Partial/Throws[E]/Mut early #59 mismatch naming Partialtry→ no PartialFull gate 257/257 (253 + 4, zero regression).
Refs #59 — left open for joint-close per the requirements-target rule.
🤖 Generated with Claude Code