Skip to content

feat(effects): infer Partial from catch-less try/? + check vs declared row (Refs #59)#207

Merged
hyperpolymath merged 1 commit into
mainfrom
feat/effects-partial-inference-59
May 18, 2026
Merged

feat(effects): infer Partial from catch-less try/? + check vs declared row (Refs #59)#207
hyperpolymath merged 1 commit into
mainfrom
feat/effects-partial-inference-59

Conversation

@hyperpolymath
Copy link
Copy Markdown
Owner

STAGE-B effect-tracking spine (issue #59)

ctx.current_eff was 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)

  • ExprTry with no catch arm — including 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 snapshots/resets current_eff around the body, then — only when an effect row is explicitly declared — requires inferred ⊆ declared (Effect.eff_subset), erroring with a new EffectNotDeclared type_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

Full gate 257/257 (253 + 4, zero regression).

Refs #59 — left open for joint-close per the requirements-target rule.

🤖 Generated with Claude Code

… 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>
@hyperpolymath hyperpolymath merged commit c5c7272 into main May 18, 2026
11 of 12 checks passed
@hyperpolymath hyperpolymath deleted the feat/effects-partial-inference-59 branch May 18, 2026 09:14
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>
@github-actions
Copy link
Copy Markdown

🔍 Hypatia Security Scan

Findings: 44 issues detected

Severity Count
🔴 Critical 12
🟠 High 21
🟡 Medium 11

⚠️ Action Required: Critical security issues found!

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

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