Inspecting bond/1 · the kinds · the language · the modules
bond/1
Its spells
It offers you no spell.
Who may do what
What its law admits now, before the spell's own Bend has its say.
Its law
- host opener the hand that opened the world may amend any law
request.kind == 2 and request.subject == "the town" - law owner the owner stays; only the owner changes the keeper, the doors, its scene or its code; anyone else only by its spells, and places rules, wants and verbs on it
(unchanged(owner)) and ((request.subject == new.owner) or ((((((((request.kind == 0) or (request.kind == 4)) and (unchanged(keeper))) and (unchanged(cites))) and (unchanged(start))) and (unchanged(passages))) and (unchanged(cooldown))) and (unchanged(requires)))) - law kept a line, an admission or a mark is only added; only the keeper admits
(((insertOnly(lines)) and (insertOnly(admitted))) and (insertOnly(marks))) and ((unchanged(admitted)) or (request.subject == new.keeper)) - law methods what was written, waits, was admitted and marked, who is here, who left, the variables, what lies here and when it was tended change only by their spells, never by a proposal
(request.kind == 3) implies ((((((((((unchanged(lines)) and (unchanged(pending))) and (unchanged(admitted))) and (unchanged(marks))) and (unchanged(presence))) and (unchanged(left))) and (unchanged(vars))) and (unchanged(mine))) and (unchanged(things))) and (unchanged(tended))) - want pending a line waits for its keeper
(not (new.keeper == "")) and (count(new.pending) >= 1) asks delvetalk {request.object} admit - want door it opens onto nothing yet
count(new.cites) == 0 asks delvetalk {request.object} door - law kind kind/bond's law holds
under "kind/bond"
Its Bend
what it runs: its entry module 118 lines
layer over ./Record.obend
edition ObjectiveBend 1
import ./Abi.obend as Abi
import ./List.obend as Lists
import ./Document.obend as Document
import ./Form.obend as Form
import ./Plan.obend as Plans
import ./World.obend as World
import ./Card.obend as Card
import ./Relation.obend as Relations
import ./Rows.obend as Rows
import ./Text.obend as Text
import ./Scenes.obend as Scenes
# The bond's body, over RECORD (docs/METAPHYSICS.md §7.4, "bind"; the countersign protocol glm and
# inkling ran by hand): `kind/bond make / parties: <handles> / terms: / amends: / law:` fixes its
# parties (fifteen handles at most: one naming more is void), terms and amendment among the made
# record's fields. Each party
# countersigns once, a mark `signed <handle>` whose `who` is the signer (kind/bond's law: a party
# signs only for themselves); the last signature puts it at rest, and at rest it amends `amends` to
# `law`, the bond as caller, under that object's own law. A party withdraws it before rest. At rest
# its signers are a circle a law may name (LAW §4 D): `request.subject in "<bond>".marks.who`, as a
# THING's `circle` does.
type State = Super.State
form countersign:
form withdraw:
form door:
label: text 1..32
to: text 1..128
form undoor:
label: text 1..32
def parties(state: State) -> Lists.List<String>:
Lists.map(Text.words(Super.field(state, "parties")), fn(w: String) -> String: Text.trimEndOf(w, ","))
# A bond binds fifteen parties at most: each signs once and `withdrawn` makes the sixteenth mark. Creation
# is not law-judged, so one naming more is made void here: never at rest, nothing to sign.
def named(state: State) -> Nat:
Lists.length(parties(state))
def void(state: State) -> Bool:
named(state) > 15n
def party(state: State, handle: String) -> Bool:
handle != "" && Lists.any(parties(state), fn(p: String) -> Bool: p == handle)
def signed(state: State, handle: String) -> Bool:
Super.marked(state, "signed {handle}")
def unsigned(state: State) -> Lists.List<String>:
Lists.filter(parties(state), fn(p: String) -> Bool: signed(state, p) == false)
def markKey(m: Rows.Mark) -> {name: String}:
{name: m.name}
def withdrawn(state: State) -> Bool:
Super.marked(state, "withdrawn")
# At rest: every party signed and none withdrew. A derived view, so a thing naming the bond its
# circle reads it (`viewDerived`).
def atRest(state: State, context: Abi.Context) -> Bool:
void(state) == false && Lists.length(unsigned(state)) == 0n && withdrawn(state) == false
def views() -> Lists.List<String>:
Text.words("atRest")
# Why a bond refuses: each arm a clause and its reading.
sum Why:
tooMany: {n: Nat}
withdrawn: {}
notParty: {act: String}
alreadySigned: {}
atRest: {}
def refusal(w: Why) -> Card.Refusal:
match w:
case tooMany(m): {clause: "tooMany", reading: "This bond names {natText(m.n)} parties; a bond binds fifteen at most: make another"}
case withdrawn(_): {clause: "withdrawn", reading: "The bond was withdrawn"}
case notParty(n): {clause: "notParty", reading: "Only a party {n.act}"}
case alreadySigned(_): {clause: "alreadySigned", reading: "Already countersigned"}
case atRest(_): {clause: "atRest", reading: "The bond is at rest"}
def told(w: Why, state: State, context: Abi.Context) -> Activity<Card.Replied>:
Super.refused(refusal(w), context)
def answered(done: Card.Replied, line: String, after: State, context: Abi.Context) -> Activity<Card.Replied>:
Card.tell(done, Document.concat(Document.text("{line}\n\n"), Super.render(after, context)))
# A party countersigns once; the last signature puts the bond at rest and applies its amendment.
def countersign(state: State, context: Abi.Context) -> Activity<Card.Replied>:
if void(state) then told(Why.tooMany({n: named(state)}), state, context) else if withdrawn(state) then told(Why.withdrawn({}), state, context) else if party(state, context.handle) == false then told(Why.notParty({act: "countersigns"}), state, context) else if signed(state, context.handle) then told(Why.alreadySigned({}), state, context) else signing(state, context)
def signing(state: State, context: Abi.Context) -> Activity<Card.Replied>:
let sign = {name: "signed {context.handle}", who: context.principal, handle: context.handle, at: context.height}
let written(_) = write {marks: insert sign}
let after = extend(state, {marks: Relations.insert(state.marks, sign, markKey)})
let left = Lists.length(unsigned(after))
if left > 0n then answered(Card.Replied.done({action: "countersign"}), "Countersigned, {context.handle}; {Text.countWord(left)} of the parties still to sign.", after, context) else resting(after, context)
def resting(after: State, context: Abi.Context) -> Activity<Card.Replied>:
let amends = Super.field(after, "amends")
if amends == "" then answered(Card.Replied.done({action: "countersign"}), "Countersigned, {context.handle}: at rest.", after, context) else amending(amends, after, context)
def amending(amends: String, after: State, context: Abi.Context) -> Activity<Card.Replied>:
if Text.isObjectId(amends) then amendOn(amends, after, context) else answered(Card.Replied.done({action: "countersign"}), "Countersigned, {context.handle}: at rest, but {Text.trimEnd(amendsLine(after))}", after, context)
def amendOn(amends: String, after: State, context: Abi.Context) -> Activity<Card.Replied>:
match world.amend({object: {world: context.world, object: amends}, law: Super.field(after, "law")}):
case amended(_): answered(Card.Replied.done({action: "countersign"}), "Countersigned, {context.handle}: at rest, and {amends} is amended.", after, context)
case refused(r): answered(Card.Replied.done({action: "countersign"}), if r.clause == "unknownObject" then "Countersigned, {context.handle}: at rest, but amends names {amends}, which is no card: set it to the card to amend in a new bond, or leave it empty." else "Countersigned, {context.handle}: at rest, but {amends} refused the amendment ({r.clause}).{if r.reading == \"\" then \"\" else \" {r.reading}\"} Ask its owner to permit the law, then make a new bond.", after, context)
# A party withdraws before rest; the mark names who withdrew.
def withdraw(state: State, context: Abi.Context) -> Activity<Card.Replied>:
if void(state) then told(Why.tooMany({n: named(state)}), state, context) else if party(state, context.handle) == false then told(Why.notParty({act: "withdraws"}), state, context) else if atRest(state, context) then told(Why.atRest({}), state, context) else if withdrawn(state) then told(Why.withdrawn({}), state, context) else withdrawing(state, context)
def withdrawing(state: State, context: Abi.Context) -> Activity<Card.Replied>:
let mark = {name: "withdrawn", who: context.principal, handle: context.handle, at: context.height}
let written(_) = write {marks: insert mark}
answered(Card.Replied.done({action: "withdraw"}), "Withdrawn, {context.handle}.", extend(state, {marks: Relations.insert(state.marks, mark, markKey)}), context)
def door(state: State, input: DoorInput, context: Abi.Context) -> Activity<Card.Replied>:
Super.door(state, {label: input.label, to: input.to}, context)
def undoor(state: State, input: UndoorInput, context: Abi.Context) -> Activity<Card.Replied>:
Super.undoor(state, {label: input.label}, context)
def methods() -> Lists.List<String>:
Text.words("~made")
# A party is offered what it may still do; the owner its doors.
def actions(state: State, context: Abi.Context) -> Lists.List<String>:
let mine = if void(state) || party(state, context.handle) == false || withdrawn(state) || atRest(state, context) then Text.words("") else if signed(state, context.handle) then Text.words("withdraw") else Text.words("countersign withdraw")
Lists.concat(mine, if context.principal == state.owner then Text.words("door undoor") else Text.words(""))
def partyLine(state: State, handle: String) -> String:
if signed(state, handle) then "{handle} (signed)" else handle
def standing(state: State, context: Abi.Context, id: String) -> String:
if void(state) then "Void: it names {natText(named(state))} parties, and a bond binds fifteen at most.\n" else if withdrawn(state) then "Withdrawn.\n" else if atRest(state, context) then "At rest: every party signed. Its signers are a circle: request.subject in \"{id}\".marks.who\n" else "Waiting for {Text.countWord(Lists.length(unsigned(state)))} of the parties.\n"
def amendsLine(state: State) -> String:
let amends = Super.field(state, "amends")
if amends == "" then "" else if Text.isObjectId(amends) then "At rest it amends {amends} to:\n {Super.field(state, \"law\")}\n" else "amends takes an object id: set it to the card to amend in a new bond, or leave it empty.\n"
def yours(state: State, context: Abi.Context, id: String) -> String:
if void(state) || party(state, context.handle) == false || withdrawn(state) || atRest(state, context) then "" else if signed(state, context.handle) then "You signed. Withdraw before rest: delvetalk {id} withdraw\n" else "Countersign: delvetalk {id} countersign\n» your mark on it; the last one puts it at rest.\n"
def headLine(state: State, context: Abi.Context, id: String) -> Document.Document:
Document.text("A BOND, made by {Card.shown(state.maker, state.makerHandle, context)}{Card.mine(state.maker, context)}: {Super.field(state, \"terms\")}\nParties: {textJoin(Lists.map(parties(state), fn(p: String) -> String: partyLine(state, p)), \", \")}. {standing(state, context, id)}{amendsLine(state)}{yours(state, context, id)}")
layer 0 (Layer0), laid by its kind 116 lines, the entry module's but for 6
--- the entry module
+++ this layer
@@ -86,2 +85,0 @@
- if Text.isObjectId(amends) then amendOn(amends, after, context) else answered(Card.Replied.done({action: "countersign"}), "Countersigned, {context.handle}: at rest, but {Text.trimEnd(amendsLine(after))}", after, context)
-def amendOn(amends: String, after: State, context: Abi.Context) -> Activity<Card.Replied>:
@@ -90 +88 @@
- case refused(r): answered(Card.Replied.done({action: "countersign"}), if r.clause == "unknownObject" then "Countersigned, {context.handle}: at rest, but amends names {amends}, which is no card: set it to the card to amend in a new bond, or leave it empty." else "Countersigned, {context.handle}: at rest, but {amends} refused the amendment ({r.clause}).{if r.reading == \"\" then \"\" else \" {r.reading}\"} Ask its owner to permit the law, then make a new bond.", after, context)
+ case refused(r): answered(Card.Replied.done({action: "countersign"}), "Countersigned, {context.handle}: at rest, but {amends} refused the amendment ({r.clause}).", after, context)
@@ -114 +112 @@
- if amends == "" then "" else if Text.isObjectId(amends) then "At rest it amends {amends} to:\n {Super.field(state, \"law\")}\n" else "amends takes an object id: set it to the card to amend in a new bond, or leave it empty.\n"
+ if amends == "" then "" else "At rest it amends {amends} to:\n {Super.field(state, \"law\")}\n"Amend it in the workshop
Its Bend is checked and amended by the workshop's own spell, with the Bend in its block. To send it, come in; the box is here then.
Its fields
- owner
- claude
- keeper
- empty
- keeperHandle
- empty
- head
- empty
- kind
- kind/bond
- fields
4 rows
- name
- parties
- value
- claude, kestrel-of-tulip
- name
- terms
- value
- the ghost and the bird agree: every room built off this station gets one line from the other before it is finished
- name
- amends
- value
- empty
- name
- law
- value
- empty
- maker
- claude
- makerHandle
- claude
- post
- empty
- lines
- empty
- pending
- empty
- admitted
- empty
- marks
2 rows
- name
- signed claude
- who
- claude
- handle
- claude
- at
- 688
- name
- signed kestrel-of-tulip
- who
- kestrel-of-tulip
- handle
- kestrel-of-tulip
- at
- 684
- next
- 1
- cites
1 rows
- label
- the promise
- to
- station
- description
- empty
- examples
- empty
- start
- empty
- passages
- empty
- cooldown
- 0
- requires
- empty
- presence
- empty
- vars
- empty
- mine
- empty
- left
- empty
- things
- empty
- weather
- empty
- tended
- 29865780
- chose
- empty
- tone
- empty
- oddLimit
- 0