Skip to content

The demo shows the refusal it claims - #964

Merged
onatozmenn merged 1 commit into
mainfrom
the-demo-shows-what-it-claims
Aug 9, 2026
Merged

The demo shows the refusal it claims#964
onatozmenn merged 1 commit into
mainfrom
the-demo-shows-what-it-claims

Conversation

@onatozmenn

Copy link
Copy Markdown
Collaborator

demo/ is what this project leads with — "One clause. Two worlds." It is the
one-clause page and the sentence the
capability model is sold on.

Both it and the site say:

A host that provides Io.read but not Io.save can run read_only without
restriction. It refuses read_write because the module declared a need the
host cannot meet.

The refusal happens before any code runs.

The test under that sentence ran the module with no host at all and
asserted only that the answer began deed:io:

let stopped = call(&module, "process", &[Value::I64(0), Value::I64(0)])
    .expect_err("read_write needs a host to provide save");
let Trap::NeedsAHost(what) = stopped else {};
assert!(what.starts_with("deed:io"));

What it actually said

Asked it to name the operation it is named for — what == "deed:io.save":

FAIL  running_read_write_without_save_names_what_it_wanted
      it should name an Io operation: deed:io.read

process reads before it saves, so with no host it stops on read. A test
called running_read_write_without_save_names_what_it_wanted never mentioned
save, and the operation it did name is the one both modules share — the
opposite of the difference the demo exists to show. The two doc comments in the
file disagreed with each other about this; the second one already said "or
deed:io.save depending on execution order".

A host that behaved the way this test does would have read the file before
noticing it could not save. That is not "before any code runs".

What it says now

Host::link is the mechanism the prose describes. It reads the whole import
section and answers before an instruction runs:

let mut host = Host::new();
host.offer("deed:io", "read", |_| Ok(Some(Value::I64(0))));

let refused = host
    .link(&module_for("read_write.deed"))
    .expect_err("a host that cannot save should refuse the module that saves");

assert_eq!(refused.name, "save");

Three tests where there were two:

  • a_host_without_save_refuses_read_write_and_names_save
  • the_same_host_links_read_only_without_restriction — the half that makes the
    first half mean something. A host that refused both would be a host with no
    filesystem.
  • running_without_a_host_stops_at_the_first_import_either_way — the weaker
    guarantee, kept and renamed, asserting both modules stop at deed:io.read so
    the two shapes can be told apart.

The other listing on the page

The README prints this file's test names. It was typed, said running 5 tests,
and named a test that no longer exists. It is now read back and compared to the
tests the file declares — the same treatment the import listing on that page
has had since #783.

That ratchet found something the moment it ran: it counted itself, because
the marker it splits the source on is spelled in the source it reads. Fixed by
spelling it in two pieces, which is the sort of thing only a self-reading test
runs into.

Also

demo/README.md said the host is "the runner in crates/deed-rt". That crate
is hashing, http, reach and sandbox; Host, link and call are all
in crates/deed-codegen.

The site carries the same snippet, the same transcript and the same claim, so
it needs the matching change: deed-lang/deed-lang.github.io#44.

`demo/README.md` and the site's one-clause page both say a host that offers
`Io.read` and not `Io.save` refuses `read_write`, and that the refusal happens
before any code runs. The test under that sentence ran the module with no host
at all and asserted only that the answer began `deed:io`.

Asked it to name the operation it is named for. It said `deed:io.read`.

So a test called `running_read_write_without_save_names_what_it_wanted` never
mentioned `save`, and the operation it did name is the one both modules share,
which is the opposite of the difference the whole demo is about. A host
behaving that way would have read the file before noticing it could not save.
The second test's own comment already admitted it — "depending on execution
order" — while the first one's name and comment claimed otherwise.

`Host::link` is the mechanism the prose describes: it reads the whole import
section and refuses before an instruction runs. The demo uses it now, and
asserts the refusal names `save` exactly. Beside it, the half that makes the
first half mean something: the same host links `read_only` and hands it back
ready to call, because a host that refused both would be a host with no
filesystem and would say nothing about the clause.

Running with no host is kept, renamed for what it shows, and asserts both
modules stop at `deed:io.read` — the weaker guarantee, now distinguishable
from the stronger one.

Also: the list of test names printed in the README was typed, said `running 5
tests`, and named a test that no longer exists. It is now read back and
compared to the tests the file declares, which is what has held the import
listing on the same page since #783. Writing that ratchet immediately found
one more thing: it counted itself, because the string it splits on is spelled
in the file it reads.

And `demo/README.md` said the host is "the runner in `crates/deed-rt`". That
crate is hashing, http, reach and sandbox; `Host`, `link` and `call` are in
`crates/deed-codegen`.
@onatozmenn
onatozmenn merged commit bcffdef into main Aug 9, 2026
10 checks passed
@onatozmenn
onatozmenn deleted the the-demo-shows-what-it-claims branch August 9, 2026 16:32
onatozmenn added a commit to deed-lang/deed-lang.github.io that referenced this pull request Aug 9, 2026
The page's own heading says "A host without `Io.save` refuses the second
module, before any of it runs." The snippet under it ran the module with no
host at all and read whichever import execution reached first, which for both
of these modules is `deed:io.read` — the operation they share, not the clause
that is the difference. Measured in deed-lang/deed#964.

`Host::link` reads the whole import section and answers before an instruction
runs, which is what the heading says, so that is what the page shows now. The
other half is on the page too: the same host links the read-only module and
hands it back ready to call. A host that refused both would be a host with no
filesystem and would say nothing about the clause.

The test transcript further down was five tests and named one that no longer
exists. It is seven now, and the compiler's repository reads that list back out
of `demo/README.md` on every commit, so this page and that one cannot drift
apart quietly again.
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