Skip to content

Revival, and a host that supplies real values (#61) - #64

Merged
lex00 merged 1 commit into
mainfrom
refimpl-revival
Sep 12, 2026
Merged

Revival, and a host that supplies real values (#61)#64
lex00 merged 1 commit into
mainfrom
refimpl-revival

Conversation

@lex00

@lex00 lex00 commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

Closes #61.

F-Val-Fate was unimplemented. Host carried descriptions of what a host supplies and no values, so a {__resource} envelope had no class to become and stayed an envelope in the namespace.

What landed

  • Host.values: specifier to export name to the real value. F-Import binds a host-owned specifier's real exports, which is F-Host-Trust arm 1 and what makes revival possible at all.
  • revive.ts, from values.md. Five of the six envelopes: resource construction honouring F-Val-Arity, intrinsic invocation in both forms, helper invocation, dotted-chain symbol resolution. {__attrRef} passes through, and is rejected inside a host call's arguments per F-Val-Position. {__compositeStep} rejects — there is no composite factory form here, recorded in CAVEATS.md.
  • packages/conformance/src/host.ts: one named host, with two entity classes covering both arities, an intrinsic tag, a helper, and a live object the host owns outright. Fixtures name the host they need with a "host" key.
  • Four fixtures: F-Val-Fate, F-Val-Arity, F-CallLeak, F-Val-Live. Coverage 51 to 57 of 126.

Two bugs this found in what already shipped

Revival was rebuilding plain structures. The first version returned a fresh object every time, so X(g) became a copy and F-Memo's guarantee went vacuous — precisely the failure J3 warns about, "F-Capture would record an edge to a copy, and the judgment would be vacuous". It now returns the original when every child came back identical, and the backward-taint fixture is what caught it.

F-Capture is stated over X(f), not over what f imported, and #60's implementation recorded the edge at import time. That made every import of a project-local function a capture, since a FoldableFunction is an object — which defeats the parameter helper F-CallLeak exists to protect. Captures are now decided by walking the produced namespace against an owner index; F-CallLeak's own edge is still recorded at the call site, since the object it leaks was never in the definer's namespace.

F-NoOwnExecution, asserted

Three cases in packages/reference/src/no-own-execution.test.ts: a top-level side effect in a folded file never runs, a side effect in a called body is rejected rather than executed, and with no host a resource cannot revive so the file falls back rather than silently keeping an envelope in its namespace.

🤖 Generated with Claude Code

https://claude.ai/code/session_01RfnRhfdYHLFAZJKHwZhBYc

F-Val-Fate was unimplemented: `Host` carried descriptions of what a host
supplies and no values, so a `{__resource}` envelope had no class to become
and stayed an envelope in the namespace.

`Host` gains `values`, specifier to export name to the real value, and
F-Import binds a host-owned specifier's real exports per F-Host-Trust arm 1.
`revive.ts` walks a declarator's folded tree and replaces five of the six
envelopes: the resource is constructed by the class the folding file imports,
honouring F-Val-Arity's props/attributes against spread-args split; the
intrinsic is invoked in whichever form the envelope recorded; the helper is
invoked; the symbol resolves as a dotted chain. `{__attrRef}` passes through,
and is rejected inside a host call's arguments per F-Val-Position.
`{__compositeStep}` rejects, since there is no composite factory form here.

Two things fell out of getting this right.

Revival must not rebuild a structure that holds no envelope. The first
version returned a fresh object every time, which made X(g) a copy and
F-Memo's guarantee vacuous, exactly as J3 warns. It now returns the original
when every child came back identical.

F-Capture is stated over X(f), not over what f imported, and the previous
implementation recorded the edge at import time. That made every import of a
project-local function a capture, since a FoldableFunction is an object,
which defeats the parameter helper F-CallLeak exists to protect. Captures are
now decided by walking the produced namespace against an owner index, and
F-CallLeak's own edge is recorded at the call site.

Conformance fixtures name a host: `packages/conformance/src/host.ts` carries
one, with two entity classes covering both arities, an intrinsic tag, a
helper, and a live object the host owns outright for the leak case. Four
fixtures land on it, and F-CallLeak's shows a leaking call and a pure one in
the same file.

F-NoOwnExecution is asserted directly: a top-level side effect in a folded
file never runs, a side effect in a called body is rejected rather than
executed, and with no host a resource cannot revive and the file falls back
rather than silently keeping an envelope.

Coverage 51 to 57 of 126 rules.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RfnRhfdYHLFAZJKHwZhBYc
@lex00
lex00 merged commit f026a59 into main Sep 12, 2026
2 checks passed
@lex00
lex00 deleted the refimpl-revival branch September 12, 2026 01:01
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.

refimpl: revival, and a host that supplies real values

1 participant