Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inner build does not correctly require Drill #394

Closed
xsebek opened this issue Jun 14, 2022 · 8 comments · Fixed by #817 or #1731
Closed

Inner build does not correctly require Drill #394

xsebek opened this issue Jun 14, 2022 · 8 comments · Fixed by #817 or #1731
Labels
Bug The observed behaviour is incorrect or unexpected. L-Capability checking Capability checking determines which capabilities are required by a given piece of code.

Comments

@xsebek
Copy link
Member

xsebek commented Jun 14, 2022

From #373 by @byorgey:

So I ran into one additional issue while testing out some things. In creative mode I tried something like this:

def forever = \c. c ; forever c end
def unblock = try {drill forward} {} end
def push = unblock; move end

build {forever (push; build {turn right; forever push})}

...
However, it doesn't work. The initial robot works fine, drilling along and building another robot at each step. However, all those secondary robots don't end up with a drill device and crash with a fatal error when they try to execute the drill command.

The problem was present before, but not visible until the robots stopped without a drill.

In this new iron age, it is immediately a fatal bug once the robot attempts to drill.

Screenshots

A bronze age screenshot from the main branch:

Screenshot from 2022-06-14 17-01-12
It's almost the same now too, so I won't include another screenshot here.

Log of the robot missing a drill:

Screenshot from 2022-06-14 17-19-14

Additional context

I traced the issue to the requiredCaps function which did not require CDrill.

@xsebek xsebek added Bug The observed behaviour is incorrect or unexpected. L-Capability checking Capability checking determines which capabilities are required by a given piece of code. labels Jun 14, 2022
@byorgey
Copy link
Member

byorgey commented Jun 14, 2022

Oh, I like your use of log and robotNamed to be able to find and view the log for the inner robot. =D Thanks for the detailed work tracking this down!

@xsebek
Copy link
Member Author

xsebek commented Jun 14, 2022

Btw. it is the same with if which also gets the previous behaviour because the drill will not run before meeting rocks:

def push = b <- blocked; if b {drill forward} {}; move end

@xsebek
Copy link
Member Author

xsebek commented Jun 15, 2022

Surprisingly this program in Classic mode does not run into a Fatal error:

def forever = \c. c ; forever c end;
def unblock = try {drill forward} {} end;
def push = unblock; move end;
log "Hi, I am base";
r <- build {
  wait 2;
  log "Hi, I am builder";
  forever (build {log "Hi, I am pusher"; turn forward; forever push}; log "- robot built")
};
give r "logger";
give r "drill";

These are all the robots logs:

Hi, I am base
Hi, I am builder
- robot built
build: You do not have required devices, please obtain: 
  - logger
Hi, I am pusher
You do not have the devices required for:
  'drill'
  please install:
   - metal drill or drill

EDIT: But to be clear it is still wrong, the drill should have been installed.

@xsebek xsebek mentioned this issue Jun 15, 2022
@xsebek
Copy link
Member Author

xsebek commented Jun 15, 2022

Once #400 is merged, you can test this with an included scenario:

$ cabal run test:swarm-integration -- -p '/build with drill (#394)/'
Up to date
Tests
  Test scenario solutions
    Regression tests
      build with drill (#394): FAIL (expected: Awaiting fix (#394)) (0.04s)
        test/integration/Main.hs:155:
        Fatal error: Drill is required but not installed?!
        Please report this as a bug at
        <https://github.com/swarm-game/swarm/issues/new>.
         (expected failure)

All 1 tests passed (0.04s)

xsebek added a commit that referenced this issue Jun 18, 2022
- add winning solutions to scenarios
- test the winning solutions
  - fail if any robot has a `Fatal error` in its log
  - timeout in X seconds (default 1)
- add a Testing scenario collection hidden without the `--cheat` flag
  - add a test case for #394

- closes #388
xsebek added a commit that referenced this issue Jun 18, 2022
- add winning solutions to scenarios
- test the winning solutions
  - fail if any robot has a `Fatal error` in its log
  - timeout in X seconds (default 1)
- add a Testing scenario collection hidden without the `--cheat` flag
  - add a test case for #394

- closes #388
@xsebek
Copy link
Member Author

xsebek commented Jul 29, 2022

@byorgey is this #540?

@byorgey
Copy link
Member

byorgey commented Aug 6, 2022

No, it's not #540. That one happens when you have a def and a build in the same expression, separated by a semicolon. You can tell that's not the problem since the push command does correctly lead to a drill being required for the outer robot, just not for the inner robots. However, it could be that somehow the correct requirements context with push in it is not being passed along to the requireCaps function for the inner build. I am still not sure.

@byorgey
Copy link
Member

byorgey commented Nov 1, 2022

OK, so the issue seems to be that newly built robots were not inheriting the robotContext of their parent, so the inner robot did not know what the requirements were for push. Copying the robotContext over is easy enough, but first I want to understand why a lot of other things weren't already broken by this. Like, why were built robots still able to use definitions from the parent robot, if they were starting with an empty context?

EDIT: Ah, I understand why now:

  • The contents of build is a delayed command which carries along with it the environment that was in effect when it was written. This actually makes sense: when I write build {foo; bar} the meaning of foo and bar is determined based on what is in scope at the instant that I write it, not later when it actually runs.
  • The same goes for the store: it is carried along in the CESK machine, and the CESK machine of the child robot has its initial store copied from the current store of the parent robot. The Store in the RobotContext is kind of ignored for all but the base robot.
  • The type context is also irrelevant, because the child robot won't need to do any typechecking.
  • The requirements context is quite relevant, though, as we can see from this issue. However, it seems like that's kind of due to the hacky way that we handle requirements checking. Once we implement Handle requirements properly as part of the type system #231 I kind of wonder if we can get rid of the RobotContext entirely (that is, we'll just have a single top-level RobotContext but they won't be stored in robots any more).

Should have a fix soon.

@byorgey
Copy link
Member

byorgey commented Nov 2, 2022

Hmm, this actually gives me an idea how to fix #540...

@mergify mergify bot closed this as completed in #817 Nov 2, 2022
mergify bot pushed a commit that referenced this issue Nov 2, 2022
mergify bot pushed a commit that referenced this issue Jan 16, 2024
# Motivation

Want to remove dependence of `TRobot` on the `RobotContext` record.  However, a lens `trobotContext` had been added in #817 to fix #394.

# Test

    scripts/run-tests.sh --test-arguments '--pattern "394-build-drill"'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug The observed behaviour is incorrect or unexpected. L-Capability checking Capability checking determines which capabilities are required by a given piece of code.
Projects
None yet
2 participants