Correct the spec's effect section, and two dead/flaky things beside it - #5
Merged
Conversation
"Effects are inferred bottom-up. Explicit annotations are optional
documentation." The second sentence has been false for as long as the boundary
check has existed: a `pub` function that performs an undeclared effect is an
error, and any function that annotates at all is held to `inferred ⊆ declared`.
Calling the annotations optional documentation describes a language where the
capability gate does not exist.
§11.4 now states the rule the compiler enforces, and a new §11.5 gives the
concrete syntax for performing and handling, which the spec had only as the
[E-Handle] inference rule in §11.3. The implementation turns out to match that
rule exactly — body type preserved, the handled effect removed from the set —
which was not by reference; §11.3 was read afterwards.
Every claim in the new text was checked by running it. The §11.5 example is a
real file that reports `f transcribe: { audit }`, `f summarize: pure`, and
evaluates to "recorded 11 chars".
Also removes the `effect.perform` branch from the collector. `X.perform(args)`
parses as a `MethodCall`, never as a `Call` on a `FieldAccess`, so the branch
could not fire for the syntax it named; and it used `Effect::from_name` on the
raw capitalised receiver, which could never match the lowercased effect names
the declarations are keyed by. Dead code that looked live, and would have
misled the next person to touch effect inference.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`a_dead_worker_reports_a_transient_error_not_a_build_failure` connects to a freshly spawned worker before killing it. `spawn_worker` returns as soon as the thread is spawned, so the listener may not be accepting yet — and under the load of a full `scripts/test-all.sh` run the 300ms budget lapsed, giving a Windows `os error 10060` and a red suite. It passed on its own immediately afterwards, which is the signature of a timing assumption rather than a defect. The connect is setup; the test is about what happens once the worker is dead. It now uses the same `timeout()` as the rest of the file. Nothing is weakened: the fail-fast-rather-than-hang behaviour a short timeout looks like it covers is actually covered by `connecting_to_nothing_fails_transiently_rather_than_hanging`, which points at a port where nothing listens and keeps its 300ms deliberately. Second flaky test this week found by running the full suite rather than one crate — the other was `forge`'s registry temp directory. Co-Authored-By: Claude Opus 5 <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.
Three cleanups found by reading and running around the effect handlers merged in #4.
The spec described an effect system this compiler does not implement
MAGE_SPEC.md§11.4, in full:The second sentence has been false for as long as the boundary check has existed. A
pubfunction that performs an undeclared effect is an error, and any function that annotates at all is held toinferred ⊆ declared. Calling annotations "optional documentation" describes a language where the capability gate does not exist.§11.4 now states the rule the compiler actually enforces — private infers, published declares, over-declaration is an upper bound — and a new §11.5 gives the concrete syntax for performing and handling, which the spec previously had only as the
[E-Handle]inference rule in §11.3.Worth recording: the implementation from #4 turns out to match
[E-Handle]exactly — body type preserved, handled effect removed from the set. That was not by reference. §11.3 was read afterwards, while checking whether this PR contradicted the spec.Every claim in the new text was checked by running it. The §11.5 example is a real file that reports
f transcribe: { audit }/f summarize: pureand evaluates to"recorded 11 chars".Dead code that looked live
The collector had an
effect.performbranch. It could not fire for the syntax it named —X.perform(args)parses as aMethodCall, never as aCallon aFieldAccess— and it calledEffect::from_nameon the raw capitalised receiver, which can never match the lowercased names declarations are keyed by. Removed; nothing in the suite or the examples noticed, which is consistent with it never having run.A flaky test that reddened a full-suite run
a_dead_worker_reports_a_transient_error_not_a_build_failureconnects to a freshly spawned worker with a 300 ms timeout before killing it.spawn_workerreturns as soon as the thread is spawned, so the listener may not be accepting yet — and under the load of a fullscripts/test-all.shrun the budget lapsed, giving a Windowsos error 10060and a red suite. It passed on its own immediately afterwards, which is the signature of a timing assumption rather than a defect.The connect is setup; the test is about what happens once the worker is dead. It now uses the same
timeout()as the rest of the file. Nothing is weakened — the fail-fast-rather-than-hang behaviour a short timeout looks like it covers is really covered byconnecting_to_nothing_fails_transiently_rather_than_hanging, which points at a port where nothing listens and keeps its 300 ms deliberately.This is the second flaky test this week found by running the whole suite rather than one crate; the other was
forge's registry temp directory. Both were invisible to CI and visible locally.Verification
scripts/test-all.sh --check-docsgreen; 45 documented counts match the run.scripts/check-examples.shgreen — all 12 typecheck, run, print their recorded answers.ribosome145 tests green; 0 clippy warnings across the four owned crates.🤖 Generated with Claude Code