Skip to content

S8: What the bionics do - #387

Merged
jamescrosswell merged 4 commits into
mainfrom
task/355-bionics
Oct 23, 2026
Merged

jamescrosswell merged 4 commits into
mainfrom
task/355-bionics

Conversation

@jamescrosswell

@jamescrosswell jamescrosswell commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

The bionics now do things. Built on the contract in #386 (S8a), now on main.

  • The hydraulic legs jump a row higher. content/street/jump.json gets a legs entry: rise 3.3 tiles and 3 rows, under the same gravity. The server's moves.possible takes the player's jump (jump_of(body)), and so does the client's (jumpOf, from player_state's body), so both use the same bound. The high ledge is in reach only with the legs. It now holds a secret, metro_secret_ledge (60), next to its salvage. positions.json has the client's run jump onto the ledge and a straight jump on the legs, plus the same height without them, which isn't kept.
  • The datajack works the new jack machines, the dead terminal and the lift. Without it, E at either says "Nothing happens: the dead terminal needs a datajack." With it:
    • The terminal is a claim on pick_up (simile.player.machines). It writes a new incident fact, lift_log, found in metro_terminal, to the journal, and the journal opens as it does at a clue. Only a jack that holds a fact claims E, so a pile at the lift is still picked up.
    • The lift is a door, metro_to_sewers. The client offers it only with the datajack, and the server ignores a player_move into the sewers from another map without one.
    • Older worlds get the fixed lift_log on their next start, dated 20 hours before their gone fact, and are saved. incident.lift_log builds the fact for both the new and the older worlds.
  • The lift's landing is a small stub map, sewers: 12 wide, lit, with a lift at (2, 15). S9 replaces it. The lift's stand tile is now just its foot, where the door is.
  • The infrared eye. simile.conversation.flush sets app.state.flushed, which the protocol sends as line.flushed. A line is flushed exactly when it says, or completes, a Stance.LIE telling's cover word for word (simile.story.says). It also needs the eye fitted, judged by the same simile.story.flushed the journal uses, so the bubble and the journal entry agree. The client shows the flush on the speaker's bubble: a red glow and a mark.
  • The Playwright walk fits the bionics through a test hook, sideWalk.fit, not through the clinic, since the side harness has no server. It checks:
    • both jacks are dead without the datajack
    • the jump onto the ledge works with the legs
    • the lift goes down to the sewers and back with the datajack

Worth a look in review:

  • Outside S8's owned paths. These were needed to make it work:
    • server/simile/story/incident.py, content.py and begin.py: the lift_log fact, and adding it to older incidents.
    • server/simile/world/lifespan.py: passes the player's jump to possible, and keeps the sewers for the datajack.
    • content/papercraft/{layout,manifest}.json and server/simile/papercraft/village.py: the landing borrows the metro's layers, since the papercraft tests need every street painted.
  • The high ledge is locked only on the client. The server keeps any standing position, so a client could send one on the ledge without the legs.
  • Only the incident's covers flush. Dialogue: code decides when a low-honesty resident lies, and the prompt directs the line #285's other lies have covers the model words for itself, so the code can't tell them exactly and they never flush.
  • Saves still load. A copy of the current save loads with its legs fitted, its journal intact and sewers on the maps.
  • Residents' days don't change. The 24-hour simile behaviour simulate --talk 3 gives the same summary as on main.
  • Needs a human eye:
    • the wording of the lift_log fact (Aris's maker's mark, and the lift going down the night before her workshop was found open)
    • how the flush looks
    • the unpainted landing

Closes #355

🤖 Generated with Claude Code

jamescrosswell and others added 2 commits October 23, 2026 23:54
The hydraulic legs jump a row higher, on the server and the client from one
table, so the metro's high ledge and its new secret are in reach. The datajack
works the jacks: the dead terminal holds the incident's lift log, and the lift
goes down to a placeholder landing in the sewers. The infrared eye flushes a
line exactly when it gives a code-decided cover story, as the journal reads it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… layers

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@jamescrosswell

Copy link
Copy Markdown
Contributor Author

Reviewed: two changes.

Changes

  1. The server can be sent to the sewers without the datajack. Today, a player_move to {map: "sewers", x: 3, y: 15} is kept. possible is true on any walkable cell, and kept is None across maps. The fix is cheap: in world/lifespan.py's on_player_move, beside the jump check, ignore a move onto sewers from another map when the body has no datajack. Add a test like test_keeps_a_jump_a_row_higher_only_with_the_hydraulic_legs.
  2. Existing worlds never get lift_log. begin() returns early once an incident exists, so the terminal in an existing village finds nothing. The fact is fixed text, not model-written, so it can be added later. In story/begin.py, when the incident has no lift_log, add it and save. Take its when from the incident's gone fact, minus 20 hours, and share the Fact with build through a small function in incident.py. Test that a pre-S8 incident gains the fact once, and that the terminal then finds it.

Checked and fine

  • Scope. The changes outside the owned paths are minimal: the lift_log fact and TERMINAL, one jump line in world/lifespan.py with its imports, and the sewers entry borrowing the metro's layers in papercraft/village.py, layout.json and manifest.json.
  • The jump. There's one bound. jump.json is generated from jump.py and has the legs entry. The client's jumpOf and the server's jump_of both pick it from the body. Both suites read positions.json: the legs' run onto the ledge is kept, and the same height by the lift without the legs isn't.
  • The flush. It never flushes the player's lines or another conversation's. tellings are only the talk's NPC's LIE covers, and the eye goes through simile.story.flushed. A truthful line flushes only if it says or completes a cover word for word, which is what the journal reads anyway.
  • Code. No Anthropic SDK or API key. No heavy imports at module level in any cli.py, routes.py, lifespan.py or __init__.py. Nothing personal. The PR's own code has no comment or docstring longer than one line; the three-line docstrings come from S8a: Contract: machines and the datajack #386.
  • Tests.
    • Server, in street, player, conversation, story, protocol, schema, world and papercraft: 3670 passed, 5 skipped.
    • Client, in side, ui and world: 815 passed.
    • simile schema --check passes.
    • CI's walk: "113 of 113 legs", with "the bionics at the depot" ok.
  • I didn't re-run the residents' 24-hour day.

Notes, not blocking

  • The high ledge is also locked only on the client. A move straight onto the catwalk, at (106, 12), is kept without the legs, because walkable cells always are. That rule predates this PR, and fixing it isn't cheap.
  • Machines.claim claims every jack, the lift included, at distance 0. So with the datajack, a pile on a jack's stand tile can't be picked up from that tile. Claiming only a jack with a fact found in it would avoid that.
  • For the user to judge:
    • the wording of lift_log
    • how the flush looks (red border and glow, with a ◉ in front)
    • the sewers stub, which borrows the metro's art

jamescrosswell and others added 2 commits October 24, 2026 00:22
… claim only jacks with a fact

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@jamescrosswell

Copy link
Copy Markdown
Contributor Author

Re-reviewed at the new head: approved.

Both requested changes are in:

  • The sewers lock. on_player_move now ignores a move onto sewers without the datajack, whether it comes from another map or with no last position. It's tested with and without the datajack.
  • lift_log for older worlds. lift_log(gone) is shared by build and logged. logged adds the fact once, dated from the incident's gone fact. begin saves only when the fact was added. The test covers the terminal then writing it.

Machines now claims only jacks that hold a fact, so a pile at the lift can be picked up, and that's tested too. The new docstrings are one line each. At this head, street, player, conversation, story, protocol, schema and world pass: 3362 tests.

Nit: in server/simile/story/README.md, the edited paragraph's second line is about 150 characters and wasn't rewrapped.

The taste notes from my last comment still stand: the lift_log wording, how the flush looks, and the sewers stub's borrowed art.

@jamescrosswell
jamescrosswell marked this pull request as ready for review October 23, 2026 11:38
@jamescrosswell
jamescrosswell merged commit 10999dd into main Oct 23, 2026
7 checks passed
@jamescrosswell
jamescrosswell deleted the task/355-bionics branch October 23, 2026 11:38
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.

S8: What the bionics do

1 participant