diff --git a/README.md b/README.md index 4d345bb..cc430f9 100644 --- a/README.md +++ b/README.md @@ -173,6 +173,11 @@ the business's own words and held-out personas. line, the desk buttons' fallback labels, and written into needs.yaml as `stage_words` so the desk score describes an outcome in the site's own words. With them, the vel's desks score 26 of 26. +- `turned_down_from: [, ...]` on a need: the unfinished stages + a case can still be turned down from; omitted, every one. An + applicant is declined before they start and departs after, which + is what uhhm.no's live machine says and what two near-synonymous + desk buttons had been standing in for. - `attended_by:` on a need: who moves cases that no desk button moves, an automation listening on the bucket's events, written into aggregates.yaml as portal's own annotation for the reader. diff --git a/plans/uhhm.yaml b/plans/uhhm.yaml index 5d8eb4d..3e224de 100644 --- a/plans/uhhm.yaml +++ b/plans/uhhm.yaml @@ -77,6 +77,7 @@ needs: done_when: [accepted, declined] success: [accepted] events: { open: submitted } + stages_text: { open: "received", accepted: "taken on", declined: "not a fit for us" } # The client plays too: they can withdraw the brief themselves. moves_by: { declined: [submitter, owners] } mails: { open: submitter, accepted: submitter, declined: submitter } @@ -98,6 +99,7 @@ needs: stages: [open, approved, previewed, declined] done_when: [previewed, declined] success: [previewed] + stages_text: { open: "received", approved: "approved for a draft", previewed: "a preview is ready", declined: "not a fit for us" } mails: { open: submitter, approved: submitter, previewed: submitter, declined: submitter } attended_by: > approved -> previewed: the n8n workflow that builds the draft @@ -123,6 +125,9 @@ needs: done_when: [departed, declined] success: [departed] events: { open: applied, active: onboarded } + # Declined before starting; after that a person departs. + turned_down_from: [open, invited] + stages_text: { open: "received", invited: "invited in", active: "working with us", departed: "moved on", declined: "not a fit for us" } max_fields: 3 collects: - { name: name } @@ -138,6 +143,7 @@ needs: stages: [open, unsubscribed] done_when: [unsubscribed] events: { open: subscribed } + stages_text: { open: "on the list", unsubscribed: "off the list" } moves_by: { unsubscribed: [submitter, owners] } max_fields: 2 collects: @@ -154,6 +160,7 @@ needs: done_when: [approved, rejected] success: [approved] events: { open: proposed } + stages_text: { open: "received", approved: "approved", rejected: "turned down" } max_fields: 3 collects: - { name: submitted_by } @@ -173,6 +180,7 @@ needs: stages: [open, in_dialogue, resolved, declined] done_when: [resolved, declined] success: [resolved] + stages_text: { open: "received", in_dialogue: "in dialogue with a custodian", resolved: "resolved", declined: "closed without action" } # The person affected says when it is resolved, not only the custodian. moves_by: { resolved: [submitter, custodians] } mails: { open: submitter, resolved: submitter, declined: submitter } @@ -193,6 +201,7 @@ needs: stages: [prospect, client, past_client] done_when: [past_client] skippable: [client] + stages_text: { prospect: "a prospect", client: "a client", past_client: "a past client" } events: { prospect: identified, client: became_client, past_client: churned } max_fields: 2 collects: diff --git a/runs/uhhm-2026-09-23/README.md b/runs/uhhm-2026-09-23/README.md index 4335237..2d003ae 100644 --- a/runs/uhhm-2026-09-23/README.md +++ b/runs/uhhm-2026-09-23/README.md @@ -121,3 +121,13 @@ Easier on the whole, and specific where the fallback was formulaic: "Your brief is in front of us. We read the whole thing before we reply, so it may take a few days." `words-r7.json` is the words as used; the branch carries them. + +## Round 8: stage words, and turned down only where the plan says + +`stages_text` on every need, three owners' desk buttons reworded by +hand ("Archive as past client", "Part ways", "Withdraw the invite"), +and `turned_down_from: [open, invited]` on the collaborators, so a +person is declined before they start and departs after - the live +site's machine exactly. Desks: 18 of 18, from 15 of 18 read against +state ids. `words-r8.json` is the words as used; the branch carries +them. diff --git a/runs/uhhm-2026-09-23/site/aggregates.yaml b/runs/uhhm-2026-09-23/site/aggregates.yaml index fbde157..25d90c2 100644 --- a/runs/uhhm-2026-09-23/site/aggregates.yaml +++ b/runs/uhhm-2026-09-23/site/aggregates.yaml @@ -15,7 +15,6 @@ aggregates: transitions: active: - departed - - declined invited: - active - declined diff --git a/runs/uhhm-2026-09-23/site/llm/01-aggregates.yaml.md b/runs/uhhm-2026-09-23/site/llm/01-aggregates.yaml.md deleted file mode 100644 index 0cf9c65..0000000 --- a/runs/uhhm-2026-09-23/site/llm/01-aggregates.yaml.md +++ /dev/null @@ -1,132 +0,0 @@ -You write the words for one page of a website for this business. - -Business: UHHM -About: UHHM builds software around a clear argument: infrastructure, tools and products for organizations that can say what problem they have. It also builds and carries the redoal network - the gesture math, the relay, the first node, and the portal this site runs on - and answers for what that network keeps. -Contact: Bendik Aagaard Lynghaug -Language to write in: en - -Everyone the site serves: -- commission: an organization with a problem it wants software to solve - wants: a considered reply to a brief, from people who read the whole thing. Handled by owners. Stages: open -> accepted -> declined. -- trial: someone who runs a business where requests, approvals and handovers get lost, and wants to see it as a site before committing to anything - wants: a first draft of a site for their own roles, built from their own words and approved by a person first. Handled by owners. Stages: open -> approved -> previewed -> declined. -- collaborate: someone who wants to work with us on what we build - wants: to be read as a person, and invited in if there is a fit. Handled by owners. Stages: open -> invited -> active -> departed -> declined. -- subscribe: someone who wants to hear from us when there is something to say - wants: a note now and then, and an easy way out. Handled by owners. Stages: open -> unsubscribed. -- propose: a visitor who sees how a page on this site should change - wants: the change read by a person and, if approved, made. Handled by owners. Stages: open -> approved -> rejected. -- custody: someone who runs, builds on, or is affected by the redoal network and needs the people who keep its first node - wants: an answer from a custodian, and action where the network keeps something it should not. Handled by custodians. Stages: open -> in_dialogue -> resolved -> declined. -- prospect: an owner who has met an organization worth following up - wants: it written down and walked through its states from the desk. Handled by owners. Stages: prospect -> client -> past_client. - -The page: aggregates.yaml -It is the mails the site sends. Under each bucket, each stage that sends one has a `subject` and a `body`: the mail a person gets the moment their case enters that stage, saying what happened and what, if anything, they can do now. Plain text, short, in the business's voice. Keep every `{...}` placeholder exactly as it is - `{site}`, `{chain}`, `{email}` and any field name are filled in by the site - and keep any line with a link in it. - -Below is the page as JSON. Every value is a slot that says what to write there. Return the same JSON with every slot replaced by your words. Keep every key exactly as it is. A slot left as it is counts as no answer. - -Rules for the words: -- `question` is a question the reader could ask themselves. -- A heading says what the reader gets, in the reader's own words, and must work without its description. -- Lead with what a thing enables. No negations in headings. No trade jargon the reader would not use. -- Descriptions are one or two short sentences. Labels and buttons are a few words. -- The button says what pressing it does; the encouragement says what happens next or how little it takes; the form's guidance line says what to have ready. Placeholders are example answers in the reader's words. -- An icon is one name from this list, chosen for what the reader is doing, or empty: house, building-2, store, school, map-pin, route, footprints, trees, leaf, snowflake, sun, users, user, user-plus, user-check, baby, heart-handshake, hand-helping, handshake, smile, mail, phone, message-circle, megaphone, bell, send, inbox, alert-triangle, siren, shield, construction, hammer, wrench, ruler, package, truck, car, bus, train-front, bike, calendar, clock, file-text, clipboard-list, receipt, wallet, coins, banknote, credit-card, key, lock, search, star, gift, shopping-cart, lightbulb, flag, thumbs-up, check-circle, briefcase, stethoscope, activity, camera, pencil, refresh-cw, list, layers, vote, scale -- Write the way people in this trade and country actually speak. - -{ - "custody_requests": { - "declined": { - "body": "", - "subject": "" - }, - "open": { - "body": "", - "subject": "" - }, - "resolved": { - "body": "", - "subject": "" - } - }, - "projects": { - "accepted": { - "body": "", - "subject": "" - }, - "declined": { - "body": "", - "subject": "" - }, - "open": { - "body": "", - "subject": "" - } - }, - "trials": { - "approved": { - "body": "", - "subject": "" - }, - "declined": { - "body": "", - "subject": "" - }, - "open": { - "body": "", - "subject": "" - }, - "previewed": { - "body": "", - "subject": "" - } - } -} - -Reply with the JSON object only. - -=== REPLY === -```json -{ - "custody_requests": { - "declined": { - "body": "We've read your message and decided this isn't something we can take on as custodians. If you think we've missed something, write back and tell us.", - "subject": "On your message to the custodians" - }, - "open": { - "body": "Your message reached the custodians of the first node. We read everything that comes in - expect a real reply, not an autoresponder.", - "subject": "We have your message" - }, - "resolved": { - "body": "This is resolved. Here's what we found and what we did about it - write back if it isn't settled from where you sit.", - "subject": "Your case is resolved" - } - }, - "projects": { - "accepted": { - "body": "We want to take this on. Next we'll be in touch to talk through scope, timing and how we'll work together.", - "subject": "We'd like to take this on" - }, - "declined": { - "body": "We've read your brief and this isn't one we're taking on. It isn't a judgment on the problem - just not a fit for us right now.", - "subject": "On your brief" - }, - "open": { - "body": "Your brief is in front of us. We read the whole thing before we reply, so it may take a few days - you'll hear from us either way.", - "subject": "We have your brief" - } - }, - "trials": { - "approved": { - "body": "Your draft is approved and on its way. We built it from your own words - have a look when it's ready and tell us what to change.", - "subject": "Your draft is approved" - }, - "declined": { - "body": "We've decided not to build this draft. If the situation changes, get back in touch and we'll take another look.", - "subject": "On your draft" - }, - "open": { - "body": "We have what you sent. A person will read it and build your draft, or tell you why not - you'll hear from us either way.", - "subject": "We're looking at your draft" - }, - "previewed": { - "body": "Your draft is ready to look at. It's built from your own words - the link below takes you straight to it.", - "subject": "Your draft is ready to view" - } - } -} -``` diff --git a/runs/uhhm-2026-09-23/site/model.json b/runs/uhhm-2026-09-23/site/model.json new file mode 100644 index 0000000..2129de9 --- /dev/null +++ b/runs/uhhm-2026-09-23/site/model.json @@ -0,0 +1,947 @@ +{ + "needs": [ + { + "id": "commission", + "who": "an organization with a problem it wants software to solve", + "wants": "a considered reply to a brief, from people who read the whole thing", + "enters_as": null, + "lands_in": "projects", + "handled_by": "owners", + "done_when": [ + "accepted", + "declined" + ], + "success": [ + "accepted" + ], + "steps": [ + { + "page": "/", + "question": "What is UHHM, and what can you get here?", + "context": "What UHHM does: Two things, both built here and both running. A network that answers to you: UHHM builds and carries the redoal network: the gesture math, the relay, the first node, and the portal this page runs on. Run a node, build on it, or have a recording removed, and you say when it is resolved. A considered reply to your brief, and software that fits the argument: Infrastructure, tools and products for organizations that can say what problem they have. Bring the brief, or first see your own way of working as a working site, before you pay for anything. The brief stays yours: you can withdraw it yourself.\nHave a look around first: Nothing to fill in here. What is already out in the world, and the network as it runs right now. What we have built: A few things already out in the world. The redoal network, live: Straight from the relay, the first node of the network.", + "options": [ + { + "name": "Have us build it: send the brief", + "description": "You know the problem and want it solved, whether it is infrastructure, a tool, or the first version of a product. Write it up for people who read the whole thing." + }, + { + "name": "See your own business as a site, before you buy anything", + "description": "Describe how requests, approvals and handovers move through your business today. We approve it by hand and build a working draft of a site for your own roles, for you to click through." + }, + { + "name": "Work with us", + "description": "A developer, a designer, a student: say what you would want to build with us, and we read it as a person and invite you in if there is a fit." + }, + { + "name": "Hear from us now and then", + "description": "You'd rather hear from us now and then than check back on your own." + }, + { + "name": "Suggest a change to this website", + "description": "You have spotted a page on uhhm.no that should read differently, and you know roughly how." + }, + { + "name": "You are on the redoal network: a node, an app, or a recording that concerns you", + "description": "UHHM hosts the redoal network's first node and answers for what it keeps. Write here if you run a node, build on the network, or want something it holds about you looked at." + } + ], + "expect": [ + "Have us build it: send the brief" + ], + "alternative": "Have us build it: send the brief", + "fields": [ + { + "name": "name", + "label": "Your name", + "type": "text", + "optional": false, + "options": [] + }, + { + "name": "email", + "label": "Your email", + "type": "email", + "optional": false, + "options": [] + }, + { + "name": "project", + "label": "The problem you want solved", + "type": "textarea", + "optional": false, + "options": [] + }, + { + "name": "organization", + "label": "Your organization", + "type": "text", + "optional": false, + "options": [] + }, + { + "name": "org_contact", + "label": "Who we should talk to", + "type": "text", + "optional": true, + "options": [] + } + ] + } + ] + }, + { + "id": "trial", + "who": "someone who runs a business where requests, approvals and handovers get lost, and wants to see it as a site before committing to anything", + "wants": "a first draft of a site for their own roles, built from their own words and approved by a person first", + "enters_as": null, + "lands_in": "trials", + "handled_by": "owners", + "done_when": [ + "previewed", + "declined" + ], + "success": [ + "previewed" + ], + "steps": [ + { + "page": "/", + "question": "What is UHHM, and what can you get here?", + "context": "What UHHM does: Two things, both built here and both running. A network that answers to you: UHHM builds and carries the redoal network: the gesture math, the relay, the first node, and the portal this page runs on. Run a node, build on it, or have a recording removed, and you say when it is resolved. A considered reply to your brief, and software that fits the argument: Infrastructure, tools and products for organizations that can say what problem they have. Bring the brief, or first see your own way of working as a working site, before you pay for anything. The brief stays yours: you can withdraw it yourself.\nHave a look around first: Nothing to fill in here. What is already out in the world, and the network as it runs right now. What we have built: A few things already out in the world. The redoal network, live: Straight from the relay, the first node of the network.", + "options": [ + { + "name": "Have us build it: send the brief", + "description": "You know the problem and want it solved, whether it is infrastructure, a tool, or the first version of a product. Write it up for people who read the whole thing." + }, + { + "name": "See your own business as a site, before you buy anything", + "description": "Describe how requests, approvals and handovers move through your business today. We approve it by hand and build a working draft of a site for your own roles, for you to click through." + }, + { + "name": "Work with us", + "description": "A developer, a designer, a student: say what you would want to build with us, and we read it as a person and invite you in if there is a fit." + }, + { + "name": "Hear from us now and then", + "description": "You'd rather hear from us now and then than check back on your own." + }, + { + "name": "Suggest a change to this website", + "description": "You have spotted a page on uhhm.no that should read differently, and you know roughly how." + }, + { + "name": "You are on the redoal network: a node, an app, or a recording that concerns you", + "description": "UHHM hosts the redoal network's first node and answers for what it keeps. Write here if you run a node, build on the network, or want something it holds about you looked at." + } + ], + "expect": [ + "See your own business as a site, before you buy anything" + ], + "alternative": "See your own business as a site, before you buy anything", + "fields": [ + { + "name": "business", + "label": "Your business", + "type": "text", + "optional": false, + "options": [] + }, + { + "name": "email", + "label": "Your email", + "type": "email", + "optional": false, + "options": [] + }, + { + "name": "what_we_do", + "label": "What you do", + "type": "textarea", + "optional": false, + "options": [] + }, + { + "name": "who_comes_to_us", + "label": "Who comes to you", + "type": "textarea", + "optional": false, + "options": [] + }, + { + "name": "what_we_keep_track_of", + "label": "What you keep track of", + "type": "textarea", + "optional": false, + "options": [] + }, + { + "name": "who_is_involved", + "label": "Who's involved", + "type": "textarea", + "optional": false, + "options": [] + }, + { + "name": "what_slows_us_down", + "label": "What slows you down", + "type": "textarea", + "optional": true, + "options": [] + } + ] + } + ] + }, + { + "id": "collaborate", + "who": "someone who wants to work with us on what we build", + "wants": "to be read as a person, and invited in if there is a fit", + "enters_as": null, + "lands_in": "applicants", + "handled_by": "owners", + "done_when": [ + "departed", + "declined" + ], + "success": [ + "departed" + ], + "steps": [ + { + "page": "/", + "question": "What is UHHM, and what can you get here?", + "context": "What UHHM does: Two things, both built here and both running. A network that answers to you: UHHM builds and carries the redoal network: the gesture math, the relay, the first node, and the portal this page runs on. Run a node, build on it, or have a recording removed, and you say when it is resolved. A considered reply to your brief, and software that fits the argument: Infrastructure, tools and products for organizations that can say what problem they have. Bring the brief, or first see your own way of working as a working site, before you pay for anything. The brief stays yours: you can withdraw it yourself.\nHave a look around first: Nothing to fill in here. What is already out in the world, and the network as it runs right now. What we have built: A few things already out in the world. The redoal network, live: Straight from the relay, the first node of the network.", + "options": [ + { + "name": "Have us build it: send the brief", + "description": "You know the problem and want it solved, whether it is infrastructure, a tool, or the first version of a product. Write it up for people who read the whole thing." + }, + { + "name": "See your own business as a site, before you buy anything", + "description": "Describe how requests, approvals and handovers move through your business today. We approve it by hand and build a working draft of a site for your own roles, for you to click through." + }, + { + "name": "Work with us", + "description": "A developer, a designer, a student: say what you would want to build with us, and we read it as a person and invite you in if there is a fit." + }, + { + "name": "Hear from us now and then", + "description": "You'd rather hear from us now and then than check back on your own." + }, + { + "name": "Suggest a change to this website", + "description": "You have spotted a page on uhhm.no that should read differently, and you know roughly how." + }, + { + "name": "You are on the redoal network: a node, an app, or a recording that concerns you", + "description": "UHHM hosts the redoal network's first node and answers for what it keeps. Write here if you run a node, build on the network, or want something it holds about you looked at." + } + ], + "expect": [ + "Work with us" + ], + "alternative": "Work with us", + "fields": [ + { + "name": "name", + "label": "Name", + "type": "text", + "optional": false, + "options": [] + }, + { + "name": "email", + "label": "Email", + "type": "email", + "optional": false, + "options": [] + }, + { + "name": "interest", + "label": "What kind of work", + "type": "textarea", + "optional": false, + "options": [] + }, + { + "name": "note", + "label": "Tell us more", + "type": "textarea", + "optional": true, + "options": [] + } + ] + } + ] + }, + { + "id": "subscribe", + "who": "someone who wants to hear from us when there is something to say", + "wants": "a note now and then, and an easy way out", + "enters_as": null, + "lands_in": "subscribers", + "handled_by": "owners", + "done_when": [ + "unsubscribed" + ], + "success": [], + "steps": [ + { + "page": "/", + "question": "What is UHHM, and what can you get here?", + "context": "What UHHM does: Two things, both built here and both running. A network that answers to you: UHHM builds and carries the redoal network: the gesture math, the relay, the first node, and the portal this page runs on. Run a node, build on it, or have a recording removed, and you say when it is resolved. A considered reply to your brief, and software that fits the argument: Infrastructure, tools and products for organizations that can say what problem they have. Bring the brief, or first see your own way of working as a working site, before you pay for anything. The brief stays yours: you can withdraw it yourself.\nHave a look around first: Nothing to fill in here. What is already out in the world, and the network as it runs right now. What we have built: A few things already out in the world. The redoal network, live: Straight from the relay, the first node of the network.", + "options": [ + { + "name": "Have us build it: send the brief", + "description": "You know the problem and want it solved, whether it is infrastructure, a tool, or the first version of a product. Write it up for people who read the whole thing." + }, + { + "name": "See your own business as a site, before you buy anything", + "description": "Describe how requests, approvals and handovers move through your business today. We approve it by hand and build a working draft of a site for your own roles, for you to click through." + }, + { + "name": "Work with us", + "description": "A developer, a designer, a student: say what you would want to build with us, and we read it as a person and invite you in if there is a fit." + }, + { + "name": "Hear from us now and then", + "description": "You'd rather hear from us now and then than check back on your own." + }, + { + "name": "Suggest a change to this website", + "description": "You have spotted a page on uhhm.no that should read differently, and you know roughly how." + }, + { + "name": "You are on the redoal network: a node, an app, or a recording that concerns you", + "description": "UHHM hosts the redoal network's first node and answers for what it keeps. Write here if you run a node, build on the network, or want something it holds about you looked at." + } + ], + "expect": [ + "Hear from us now and then" + ], + "alternative": "Hear from us now and then", + "fields": [ + { + "name": "name", + "label": "Name", + "type": "text", + "optional": false, + "options": [] + }, + { + "name": "email", + "label": "Email", + "type": "email", + "optional": false, + "options": [] + } + ] + } + ] + }, + { + "id": "propose", + "who": "a visitor who sees how a page on this site should change", + "wants": "the change read by a person and, if approved, made", + "enters_as": null, + "lands_in": "development_proposals", + "handled_by": "owners", + "done_when": [ + "approved", + "rejected" + ], + "success": [ + "approved" + ], + "steps": [ + { + "page": "/", + "question": "What is UHHM, and what can you get here?", + "context": "What UHHM does: Two things, both built here and both running. A network that answers to you: UHHM builds and carries the redoal network: the gesture math, the relay, the first node, and the portal this page runs on. Run a node, build on it, or have a recording removed, and you say when it is resolved. A considered reply to your brief, and software that fits the argument: Infrastructure, tools and products for organizations that can say what problem they have. Bring the brief, or first see your own way of working as a working site, before you pay for anything. The brief stays yours: you can withdraw it yourself.\nHave a look around first: Nothing to fill in here. What is already out in the world, and the network as it runs right now. What we have built: A few things already out in the world. The redoal network, live: Straight from the relay, the first node of the network.", + "options": [ + { + "name": "Have us build it: send the brief", + "description": "You know the problem and want it solved, whether it is infrastructure, a tool, or the first version of a product. Write it up for people who read the whole thing." + }, + { + "name": "See your own business as a site, before you buy anything", + "description": "Describe how requests, approvals and handovers move through your business today. We approve it by hand and build a working draft of a site for your own roles, for you to click through." + }, + { + "name": "Work with us", + "description": "A developer, a designer, a student: say what you would want to build with us, and we read it as a person and invite you in if there is a fit." + }, + { + "name": "Hear from us now and then", + "description": "You'd rather hear from us now and then than check back on your own." + }, + { + "name": "Suggest a change to this website", + "description": "You have spotted a page on uhhm.no that should read differently, and you know roughly how." + }, + { + "name": "You are on the redoal network: a node, an app, or a recording that concerns you", + "description": "UHHM hosts the redoal network's first node and answers for what it keeps. Write here if you run a node, build on the network, or want something it holds about you looked at." + } + ], + "expect": [ + "Suggest a change to this website" + ], + "alternative": "Suggest a change to this website", + "fields": [ + { + "name": "submitted_by", + "label": "Your name", + "type": "text", + "optional": false, + "options": [] + }, + { + "name": "email", + "label": "Email", + "type": "email", + "optional": true, + "options": [] + }, + { + "name": "page", + "label": "Which page", + "type": "text", + "optional": true, + "options": [] + }, + { + "name": "rationale", + "label": "Why this is better", + "type": "textarea", + "optional": false, + "options": [] + }, + { + "name": "proposed_yaml", + "label": "Your proposed text", + "type": "textarea", + "optional": false, + "options": [] + } + ] + } + ] + }, + { + "id": "custody", + "who": "someone who runs, builds on, or is affected by the redoal network and needs the people who keep its first node", + "wants": "an answer from a custodian, and action where the network keeps something it should not", + "enters_as": null, + "lands_in": "custody_requests", + "handled_by": "custodians", + "done_when": [ + "resolved", + "declined" + ], + "success": [ + "resolved" + ], + "steps": [ + { + "page": "/", + "question": "What is UHHM, and what can you get here?", + "context": "What UHHM does: Two things, both built here and both running. A network that answers to you: UHHM builds and carries the redoal network: the gesture math, the relay, the first node, and the portal this page runs on. Run a node, build on it, or have a recording removed, and you say when it is resolved. A considered reply to your brief, and software that fits the argument: Infrastructure, tools and products for organizations that can say what problem they have. Bring the brief, or first see your own way of working as a working site, before you pay for anything. The brief stays yours: you can withdraw it yourself.\nHave a look around first: Nothing to fill in here. What is already out in the world, and the network as it runs right now. What we have built: A few things already out in the world. The redoal network, live: Straight from the relay, the first node of the network.", + "options": [ + { + "name": "Have us build it: send the brief", + "description": "You know the problem and want it solved, whether it is infrastructure, a tool, or the first version of a product. Write it up for people who read the whole thing." + }, + { + "name": "See your own business as a site, before you buy anything", + "description": "Describe how requests, approvals and handovers move through your business today. We approve it by hand and build a working draft of a site for your own roles, for you to click through." + }, + { + "name": "Work with us", + "description": "A developer, a designer, a student: say what you would want to build with us, and we read it as a person and invite you in if there is a fit." + }, + { + "name": "Hear from us now and then", + "description": "You'd rather hear from us now and then than check back on your own." + }, + { + "name": "Suggest a change to this website", + "description": "You have spotted a page on uhhm.no that should read differently, and you know roughly how." + }, + { + "name": "You are on the redoal network: a node, an app, or a recording that concerns you", + "description": "UHHM hosts the redoal network's first node and answers for what it keeps. Write here if you run a node, build on the network, or want something it holds about you looked at." + } + ], + "expect": [ + "You are on the redoal network: a node, an app, or a recording that concerns you" + ], + "alternative": "You are on the redoal network: a node, an app, or a recording that concerns you", + "fields": [ + { + "name": "name", + "label": "Name", + "type": "text", + "optional": false, + "options": [] + }, + { + "name": "email", + "label": "Email", + "type": "email", + "optional": false, + "options": [] + }, + { + "name": "about", + "label": "What's going on", + "type": "select", + "optional": false, + "options": [ + "Running a node of my own", + "Building on the network", + "Something the network keeps about me", + "Something else" + ] + }, + { + "name": "what", + "label": "In short", + "type": "textarea", + "optional": false, + "options": [] + } + ] + } + ] + }, + { + "id": "prospect", + "who": "an owner who has met an organization worth following up", + "wants": "it written down and walked through its states from the desk", + "enters_as": "owners", + "lands_in": "organizations", + "handled_by": "owners", + "done_when": [ + "past_client" + ], + "success": [], + "steps": [ + { + "page": "/owners/prospect", + "question": "Is there an organization I should be keeping track of?", + "context": "", + "options": [ + { + "name": "Keep an organization on your radar", + "description": "One line per organization worth watching, moved through the stages as things develop." + } + ], + "expect": [ + "Keep an organization on your radar" + ], + "alternative": "Keep an organization on your radar", + "fields": [ + { + "name": "name", + "label": "Organization", + "type": "text", + "optional": false, + "options": [] + }, + { + "name": "contact", + "label": "Contact", + "type": "text", + "optional": false, + "options": [] + }, + { + "name": "note", + "label": "Note", + "type": "textarea", + "optional": true, + "options": [] + } + ] + } + ] + } + ], + "buckets": { + "projects": { + "initial": "open", + "transitions": { + "open": [ + "accepted", + "declined" + ] + }, + "words": { + "accepted": "taken on", + "declined": "not a fit for us", + "open": "received" + }, + "desks": [ + { + "page": "/owners", + "group": "owners", + "moves": [ + { + "from": "open", + "to": "accepted", + "label": "Accept brief" + }, + { + "from": "open", + "to": "declined", + "label": "Decline brief" + } + ] + } + ], + "self_moves": [ + "declined" + ] + }, + "trials": { + "initial": "open", + "transitions": { + "approved": [ + "previewed", + "declined" + ], + "open": [ + "approved", + "declined" + ] + }, + "words": { + "approved": "approved for a draft", + "declined": "not a fit for us", + "open": "received", + "previewed": "a preview is ready" + }, + "desks": [ + { + "page": "/owners", + "group": "owners", + "moves": [ + { + "from": "approved", + "to": "previewed", + "label": "Mark previewed" + }, + { + "from": "approved", + "to": "declined", + "label": "Decline trial" + }, + { + "from": "open", + "to": "approved", + "label": "Approve trial" + }, + { + "from": "open", + "to": "declined", + "label": "Decline trial" + } + ] + } + ], + "self_moves": [] + }, + "applicants": { + "initial": "open", + "transitions": { + "active": [ + "departed" + ], + "invited": [ + "active", + "declined" + ], + "open": [ + "invited", + "declined" + ] + }, + "words": { + "active": "working with us", + "declined": "not a fit for us", + "departed": "moved on", + "invited": "invited in", + "open": "received" + }, + "desks": [ + { + "page": "/owners", + "group": "owners", + "moves": [ + { + "from": "active", + "to": "departed", + "label": "Mark departed" + }, + { + "from": "invited", + "to": "active", + "label": "Confirm active" + }, + { + "from": "invited", + "to": "declined", + "label": "Withdraw the invite" + }, + { + "from": "open", + "to": "invited", + "label": "Send invite" + }, + { + "from": "open", + "to": "declined", + "label": "Decline applicant" + } + ] + } + ], + "self_moves": [] + }, + "subscribers": { + "initial": "open", + "transitions": { + "open": [ + "unsubscribed" + ] + }, + "words": { + "open": "on the list", + "unsubscribed": "off the list" + }, + "desks": [ + { + "page": "/owners", + "group": "owners", + "moves": [ + { + "from": "open", + "to": "unsubscribed", + "label": "Unsubscribe them" + } + ] + } + ], + "self_moves": [ + "unsubscribed" + ] + }, + "development_proposals": { + "initial": "open", + "transitions": { + "open": [ + "approved", + "rejected" + ] + }, + "words": { + "approved": "approved", + "open": "received", + "rejected": "turned down" + }, + "desks": [ + { + "page": "/owners", + "group": "owners", + "moves": [ + { + "from": "open", + "to": "approved", + "label": "Approve change" + }, + { + "from": "open", + "to": "rejected", + "label": "Reject change" + } + ] + } + ], + "self_moves": [] + }, + "custody_requests": { + "initial": "open", + "transitions": { + "open": [ + "in_dialogue", + "declined" + ], + "in_dialogue": [ + "resolved", + "declined" + ] + }, + "words": { + "declined": "closed without action", + "in_dialogue": "in dialogue with a custodian", + "open": "received", + "resolved": "resolved" + }, + "desks": [ + { + "page": "/custodians", + "group": "custodians", + "moves": [ + { + "from": "in_dialogue", + "to": "resolved", + "label": "Mark resolved" + }, + { + "from": "in_dialogue", + "to": "declined", + "label": "Close, no action" + }, + { + "from": "open", + "to": "in_dialogue", + "label": "Open dialogue" + }, + { + "from": "open", + "to": "declined", + "label": "Decline case" + } + ] + }, + { + "page": "/owners", + "group": "owners", + "moves": [] + } + ], + "self_moves": [ + "resolved" + ] + }, + "organizations": { + "initial": "prospect", + "transitions": { + "prospect": [ + "client", + "past_client" + ], + "client": [ + "past_client" + ] + }, + "words": { + "client": "a client", + "past_client": "a past client", + "prospect": "a prospect" + }, + "desks": [ + { + "page": "/owners", + "group": "owners", + "moves": [ + { + "from": "client", + "to": "past_client", + "label": "Mark past client" + }, + { + "from": "prospect", + "to": "client", + "label": "Mark as client" + }, + { + "from": "prospect", + "to": "past_client", + "label": "Archive as past client" + } + ] + } + ], + "self_moves": [] + } + }, + "personas": [ + { + "id": "architecture-firm", + "need": "commission", + "text": "We run a small architecture firm and our project files are scattered across three cloud drives. We want to pay someone to set up proper storage and backups we control ourselves." + }, + { + "id": "climbing-gym-founder", + "need": "commission", + "text": "I have an idea for a booking app for climbing gyms and I'm looking for a team that can build the first version with me." + }, + { + "id": "municipality-buyer", + "need": "commission", + "text": "Our municipality needs an internal tool for tracking building permits. We are looking for a vendor who can scope it and deliver it." + }, + { + "id": "exhibition-visitor", + "need": "subscribe", + "text": "I saw your drawing network at an exhibition and liked it. I don't want to get involved, I'd just like to know when there is news." + }, + { + "id": "tech-journalist", + "need": "subscribe", + "text": "I write about Nordic technology. Keep me posted on what you release so I can cover it." + }, + { + "id": "rust-developer", + "need": "collaborate", + "text": "I'm a Rust developer between jobs and I like that you build in the open. I would love to contribute, and maybe join you." + }, + { + "id": "interaction-designer", + "need": "collaborate", + "text": "I'm an interaction designer. I want to work with you on the drawing interface." + }, + { + "id": "student-intern", + "need": "collaborate", + "text": "I'm a computer science student looking for a summer internship doing infrastructure work." + }, + { + "id": "plumber-owner", + "need": "trial", + "text": "I run a plumbing company with four vans. Jobs come in by phone and text and some get lost. I'd like to see how this would look for us before I spend any money." + }, + { + "id": "dance-school", + "need": "trial", + "text": "We are a dance school. Enrolments, cancellations and invoices all go through one email inbox that only I understand. Can you show me a version made for us?" + }, + { + "id": "node-runner", + "need": "custody", + "text": "I run a small server in Berlin and want to host a redoal node that peers with yours. Who do I talk to?" + }, + { + "id": "recorded-name", + "need": "custody", + "text": "Someone left a recording on redoal that says my full name and where I live. I want it gone, and I want to know who is responsible for that network." + }, + { + "id": "app-builder", + "need": "custody", + "text": "I'm building a music app and would like to use redoal's gesture addresses in it. Is that possible, and who decides?" + }, + { + "id": "wording-fix", + "need": "propose", + "text": "The subscribe page should say how often you actually write. I'd like to suggest that exact change to the page." + }, + { + "id": "rewrite", + "need": "propose", + "text": "One page on this site reads wrong to me and I know exactly how I'd rewrite it. Where do I send the new text?" + } + ] +} \ No newline at end of file diff --git a/runs/uhhm-2026-09-23/site/needs.yaml b/runs/uhhm-2026-09-23/site/needs.yaml index 4c8e7d3..b94a531 100644 --- a/runs/uhhm-2026-09-23/site/needs.yaml +++ b/runs/uhhm-2026-09-23/site/needs.yaml @@ -8,6 +8,10 @@ needs: lands_in: projects max_fields: 4 max_steps: 1 + stage_words: + accepted: taken on + declined: not a fit for us + open: received stages: - open - accepted @@ -26,6 +30,11 @@ needs: lands_in: trials max_fields: 6 max_steps: 1 + stage_words: + approved: approved for a draft + declined: not a fit for us + open: received + previewed: a preview is ready stages: - open - approved @@ -45,6 +54,12 @@ needs: lands_in: applicants max_fields: 3 max_steps: 1 + stage_words: + active: working with us + declined: not a fit for us + departed: moved on + invited: invited in + open: received stages: - open - invited @@ -64,6 +79,9 @@ needs: lands_in: subscribers max_fields: 2 max_steps: 1 + stage_words: + open: on the list + unsubscribed: off the list stages: - open - unsubscribed @@ -80,6 +98,10 @@ needs: lands_in: development_proposals max_fields: 3 max_steps: 1 + stage_words: + approved: approved + open: received + rejected: turned down stages: - open - approved @@ -98,6 +120,11 @@ needs: lands_in: custody_requests max_fields: 4 max_steps: 1 + stage_words: + declined: closed without action + in_dialogue: in dialogue with a custodian + open: received + resolved: resolved stages: - open - in_dialogue @@ -117,6 +144,10 @@ needs: lands_in: organizations max_fields: 2 max_steps: 1 + stage_words: + client: a client + past_client: a past client + prospect: a prospect stages: - prospect - client diff --git a/runs/uhhm-2026-09-23/site/questions/owners/index.yaml b/runs/uhhm-2026-09-23/site/questions/owners/index.yaml index a59e0b0..dc1985e 100644 --- a/runs/uhhm-2026-09-23/site/questions/owners/index.yaml +++ b/runs/uhhm-2026-09-23/site/questions/owners/index.yaml @@ -15,14 +15,11 @@ alternatives: - from: active label: Mark departed to: departed - - from: active - label: End collaboration - to: declined - from: invited label: Confirm active to: active - from: invited - label: Withdraw invite + label: Withdraw the invite to: declined - from: open label: Send invite @@ -85,7 +82,7 @@ alternatives: label: Mark as client to: client - from: prospect - label: Mark not pursued + label: Archive as past client to: past_client name: Organizations you're tracking - action: /owners diff --git a/runs/uhhm-2026-09-23/site/words.json b/runs/uhhm-2026-09-23/site/words.json index 3a53bd4..50f504b 100644 --- a/runs/uhhm-2026-09-23/site/words.json +++ b/runs/uhhm-2026-09-23/site/words.json @@ -328,10 +328,9 @@ "description": "People who've asked to build with us, waiting on a decision or already working alongside us.", "heading": "People who want to build with us", "moves": { - "active->declined": "End collaboration", "active->departed": "Mark departed", "invited->active": "Confirm active", - "invited->declined": "Withdraw invite", + "invited->declined": "Withdraw the invite", "open->declined": "Decline applicant", "open->invited": "Send invite" } @@ -355,7 +354,7 @@ "moves": { "client->past_client": "Mark past client", "prospect->client": "Mark as client", - "prospect->past_client": "Mark not pursued" + "prospect->past_client": "Archive as past client" } }, "projects": { diff --git a/runs/uhhm-2026-09-23/words-r8.json b/runs/uhhm-2026-09-23/words-r8.json new file mode 100644 index 0000000..50f504b --- /dev/null +++ b/runs/uhhm-2026-09-23/words-r8.json @@ -0,0 +1,500 @@ +{ + "aggregates.yaml": { + "custody_requests": { + "declined": { + "body": "We've read your message and decided this isn't something we can take on as custodians. If you think we've missed something, write back and tell us.", + "subject": "On your message to the custodians" + }, + "open": { + "body": "Your message reached the custodians of the first node. We read everything that comes in - expect a real reply, not an autoresponder.", + "subject": "We have your message" + }, + "resolved": { + "body": "This is resolved. Here's what we found and what we did about it - write back if it isn't settled from where you sit.", + "subject": "Your case is resolved" + } + }, + "projects": { + "accepted": { + "body": "We want to take this on. Next we'll be in touch to talk through scope, timing and how we'll work together.", + "subject": "We'd like to take this on" + }, + "declined": { + "body": "We've read your brief and this isn't one we're taking on. It isn't a judgment on the problem - just not a fit for us right now.", + "subject": "On your brief" + }, + "open": { + "body": "Your brief is in front of us. We read the whole thing before we reply, so it may take a few days - you'll hear from us either way.\n\nWhat you can do next: {site}/decide/commission?chain={chain}&email={email}", + "subject": "We have your brief" + } + }, + "trials": { + "approved": { + "body": "Your draft is approved and on its way. We built it from your own words - have a look when it's ready and tell us what to change.", + "subject": "Your draft is approved" + }, + "declined": { + "body": "We've decided not to build this draft. If the situation changes, get back in touch and we'll take another look.", + "subject": "On your draft" + }, + "open": { + "body": "We have what you sent. A person will read it and build your draft, or tell you why not - you'll hear from us either way.", + "subject": "We're looking at your draft" + }, + "previewed": { + "body": "Your draft is ready to look at. It's built from your own words - the link below takes you straight to it.", + "subject": "Your draft is ready to view" + } + } + }, + "questions/custodians/index.yaml": { + "buckets": { + "custody_requests": { + "description": "Cases from people who use, build on, or answer for something the redoal network touches, and need a custodian's word on it.", + "heading": "Custody cases waiting on you", + "moves": { + "in_dialogue->declined": "Close, no action", + "in_dialogue->resolved": "Mark resolved", + "open->declined": "Decline case", + "open->in_dialogue": "Open dialogue" + } + } + }, + "confirm": "Confirm", + "description": "The desk for custodians: open custody cases, and the people invited to answer them.", + "invited": { + "description": "Custodians invited but not yet signed in.", + "done": "Signed in", + "heading": "Invited custodians" + }, + "invites": { + "custodians": { + "button": "Invite custodian", + "description": "Give someone an account and a one-time link to join as a custodian.", + "form_title": "Invite a custodian", + "heading": "Bring in another custodian", + "labels": { + "email": "Email", + "name": "Name" + } + } + }, + "links": {}, + "question": "What is waiting on the custodians?" + }, + "questions/decide/commission.yaml": { + "description": "", + "moves": { + "declined": { + "button": "Declined", + "description": "", + "heading": "Declined" + } + }, + "question": "What would you like to do?" + }, + "questions/decide/custody.yaml": { + "description": "", + "moves": { + "resolved": { + "button": "Resolved", + "description": "", + "heading": "Resolved" + } + }, + "question": "What would you like to do?" + }, + "questions/decide/subscribe.yaml": { + "description": "You're on our list. Change your mind whenever you like.", + "moves": { + "unsubscribed": { + "button": "Unsubscribe", + "description": "You'll stop hearing from us. Nothing else changes.", + "heading": "Stop getting notes from us" + } + }, + "question": "Do you want to keep hearing from us?" + }, + "questions/index.yaml": { + "description": "UHHM builds software for organisations that can say what problem they have, and keeps the redoal network underneath.", + "doors": {}, + "needs": { + "collaborate": { + "button": "Get in touch", + "description": "A developer, a designer, a student: say what you would want to build with us, and we read it as a person and invite you in if there is a fit.", + "encouragement": "A person reads this, not a form filter — worth the ten minutes.", + "form_description": "Tell us who you are and what kind of work you're after.", + "form_title": "Say hello", + "heading": "Work with us", + "hints": { + "email": "you@example.com", + "interest": "Backend work, or something design-heavy", + "name": "Your name", + "note": "A bit about what you'd want to work on, or a link to your work" + }, + "icon": "handshake", + "labels": { + "email": "Email", + "interest": "What kind of work", + "name": "Name", + "note": "Tell us more" + }, + "road_description": "We read what you send and get back to you. If there's a fit, we invite you in and you start working with us — and if things ever change, that's fine too.", + "road_icon": "route", + "road_title": "What happens next", + "who_description": "One of the owners reads this directly — for anything urgent, write to bl@uhhm.no.", + "who_icon": "user-check", + "who_title": "Who reads this" + }, + "commission": { + "button": "Send the brief", + "description": "You know the problem and want it solved, whether it is infrastructure, a tool, or the first version of a product. Write it up for people who read the whole thing.", + "encouragement": "Someone here reads every brief in full before writing back.", + "form_description": "The more of the problem you put in, the better the reply.", + "form_title": "Tell us the problem", + "heading": "Have us build it: send the brief", + "hints": { + "email": "sara@company.com", + "name": "Sara Nilsen", + "org_contact": "Sara Nilsen, ops manager", + "organization": "Nilsen Transport AS", + "project": "Our drivers log hours on paper and it takes a day to get them into payroll." + }, + "icon": "briefcase", + "labels": { + "email": "Your email", + "name": "Your name", + "org_contact": "Who we should talk to", + "organization": "Your organization", + "project": "The problem you want solved" + }, + "road_description": "We read your brief and either take it on or tell you honestly if it's not a fit.", + "road_icon": "route", + "road_title": "What happens next", + "who_description": "One of the owners reads it; write to bl@uhhm.no if you'd rather reach us directly.", + "who_icon": "user-check", + "who_title": "Who reads this" + }, + "custody": { + "button": "Send to a custodian", + "description": "UHHM hosts the redoal network's first node and answers for what it keeps. Write here if you run a node, build on the network, or want something it holds about you looked at.", + "encouragement": "A custodian reads every message that comes in here.", + "form_description": "Say which of the four it is, and what you need, in a few lines.", + "form_title": "Reach a custodian", + "heading": "You are on the redoal network: a node, an app, or a recording that concerns you", + "hints": { + "about": "We run our order system on a relay node and it's been dropping messages since Tuesday", + "email": "you@yourcompany.com", + "name": "Your name", + "what": "A relay node is misbehaving" + }, + "icon": "shield", + "labels": { + "about": "What's going on", + "email": "Email", + "name": "Name", + "what": "In short" + }, + "road_description": "A custodian opens a dialogue with you. A node gets its peer, a builder gets an answer, and something the network should not keep gets removed. Either way you hear what was decided.", + "road_icon": "route", + "road_title": "What happens next", + "who_description": "A custodian reads it directly; if it's urgent, write to bl@uhhm.no in the meantime.", + "who_icon": "user-check", + "who_title": "Who reads this" + }, + "propose": { + "button": "Send change", + "description": "You have spotted a page on uhhm.no that should read differently, and you know roughly how.", + "encouragement": "Even a rough version helps — we can tidy the wording ourselves.", + "form_description": "Point us to the page and show us the change.", + "form_title": "Propose a change", + "heading": "Suggest a change to this website", + "hints": { + "email": "you@example.com", + "page": "questions/join/index.yaml", + "proposed_yaml": "heading: \"A clearer way to say this\"", + "rationale": "The current heading doesn't say what you actually get", + "submitted_by": "Your name" + }, + "icon": "pencil", + "labels": { + "email": "Email", + "page": "Which page", + "proposed_yaml": "Your proposed text", + "rationale": "Why this is better", + "submitted_by": "Your name" + }, + "road_description": "Someone here reads your proposal and either makes the change or explains why not. Either way, you'll hear back.", + "road_icon": "route", + "road_title": "What happens next", + "who_description": "An owner reads every proposal before anything changes — reach us at bl@uhhm.no if it's time-sensitive.", + "who_icon": "user-check", + "who_title": "Who reads this" + }, + "subscribe": { + "button": "Sign up", + "description": "You'd rather hear from us now and then than check back on your own.", + "encouragement": "One click unsubscribes you later, no questions asked.", + "form_description": "Just your email, or your name too if you'd like.", + "form_title": "Stay in the loop", + "heading": "Hear from us now and then", + "hints": { + "email": "you@example.com", + "name": "Your name" + }, + "icon": "mail", + "labels": { + "email": "Email", + "name": "Name" + }, + "road_description": "You're on the list. We write when there's something worth saying, and you can leave the list whenever you like.", + "road_icon": "bell", + "road_title": "What happens next", + "who_description": "An owner sends these notes directly — write to bl@uhhm.no if you'd rather ask something first.", + "who_icon": "user-check", + "who_title": "Who reads this" + }, + "trial": { + "button": "Start the draft", + "description": "Describe how requests, approvals and handovers move through your business today. We approve it by hand and build a working draft of a site for your own roles, for you to click through.", + "encouragement": "A person looks at what you send before anything gets built.", + "form_description": "Answer in your own words - there's no wrong way to describe your business.", + "form_title": "Describe your business", + "heading": "See your own business as a site, before you buy anything", + "hints": { + "business": "Nilsen Transport AS", + "email": "sara@company.com", + "what_slows_us_down": "Approvals sit in someone's inbox for days before anyone acts on them.", + "what_we_do": "We move freight for local businesses and handle the paperwork for them.", + "what_we_keep_track_of": "Bookings, driver hours, and which loads are still waiting on a signature.", + "who_comes_to_us": "Local businesses that need something moved on short notice.", + "who_is_involved": "Drivers, dispatchers, and the customers waiting on their delivery." + }, + "icon": "layers", + "labels": { + "business": "Your business", + "email": "Your email", + "what_slows_us_down": "What slows you down", + "what_we_do": "What you do", + "what_we_keep_track_of": "What you keep track of", + "who_comes_to_us": "Who comes to you", + "who_is_involved": "Who's involved" + }, + "road_description": "We look at what you sent and, if it's a fit, build a draft from your own roles and words for you to see before anything moves further.", + "road_icon": "route", + "road_title": "What happens next", + "who_description": "An owner looks at what you send; write to bl@uhhm.no if you'd rather reach us directly.", + "who_icon": "user-check", + "who_title": "Who reads this" + } + }, + "opener": { + "description": "Two things, both built here and both running.", + "features": { + "redoal": { + "description": "UHHM builds and carries the redoal network: the gesture math, the relay, the first node, and the portal this page runs on. Run a node, build on it, or have a recording removed, and you say when it is resolved.", + "heading": "A network that answers to you", + "icon": "waypoints" + }, + "software": { + "description": "Infrastructure, tools and products for organizations that can say what problem they have. Bring the brief, or first see your own way of working as a working site, before you pay for anything. The brief stays yours: you can withdraw it yourself.", + "heading": "A considered reply to your brief, and software that fits the argument", + "icon": "layers" + } + }, + "heading": "What UHHM does" + }, + "question": "What is UHHM, and what can you get here?", + "shopping": { + "description": "Nothing to fill in here. What is already out in the world, and the network as it runs right now.", + "heading": "Have a look around first", + "items": { + "built": { + "description": "A few things already out in the world.", + "heading": "What we have built", + "icon": "hammer" + }, + "voices": { + "description": "Straight from the relay, the first node of the network.", + "heading": "The redoal network, live", + "icon": "activity" + } + } + } + }, + "questions/owners/index.yaml": { + "buckets": { + "applicants": { + "description": "People who've asked to build with us, waiting on a decision or already working alongside us.", + "heading": "People who want to build with us", + "moves": { + "active->departed": "Mark departed", + "invited->active": "Confirm active", + "invited->declined": "Withdraw the invite", + "open->declined": "Decline applicant", + "open->invited": "Send invite" + } + }, + "custody_requests": { + "description": "Questions and issues raised with the people who keep the first node - custodians handle these, but you can see where each one stands.", + "heading": "What's been raised with custodians", + "moves": {} + }, + "development_proposals": { + "description": "Changes visitors have proposed for pages on this site, waiting on a yes or no.", + "heading": "Proposed changes to the site", + "moves": { + "open->approved": "Approve change", + "open->rejected": "Reject change" + } + }, + "organizations": { + "description": "Organizations you've met, tracked from first contact through to client and beyond.", + "heading": "Organizations you're tracking", + "moves": { + "client->past_client": "Mark past client", + "prospect->client": "Mark as client", + "prospect->past_client": "Archive as past client" + } + }, + "projects": { + "description": "Briefs sent in by organizations with a problem they want solved.", + "heading": "Briefs waiting on a reply", + "moves": { + "open->accepted": "Accept brief", + "open->declined": "Decline brief" + } + }, + "subscribers": { + "description": "People who want to hear from you now and then.", + "heading": "Who's hearing from you", + "moves": { + "open->unsubscribed": "Unsubscribe them" + } + }, + "trials": { + "description": "Businesses who want to see their own workflow as a working site before committing to anything.", + "heading": "Trial sites in progress", + "moves": { + "approved->declined": "Decline trial", + "approved->previewed": "Mark previewed", + "open->approved": "Approve trial", + "open->declined": "Decline trial" + } + } + }, + "confirm": "Confirm", + "description": "Everything waiting on you: briefs, trials, applicants, subscribers, and proposals, all in one place.", + "invited": { + "description": "People you've invited in, and whether they've taken it up yet.", + "done": "Taken up", + "heading": "Invites you've sent" + }, + "invites": { + "custodians": { + "button": "Send invite", + "description": "Bring someone in to help keep the first node and answer for the network.", + "form_title": "Invite a custodian", + "heading": "Bring in a custodian", + "labels": { + "email": "Their email", + "name": "Their name" + } + }, + "owners": { + "button": "Send invite", + "description": "Bring someone in to work this desk alongside you.", + "form_title": "Invite an owner", + "heading": "Bring in another owner", + "labels": { + "email": "Their email", + "name": "Their name" + } + } + }, + "links": { + "prospect": { + "button": "Add prospect", + "description": "Write down an organization worth following up, and track it from first contact onward.", + "heading": "Track a new organization" + } + }, + "question": "What's waiting on me today?" + }, + "questions/owners/prospect-sent.yaml": { + "back": "Back to site", + "description": "Thanks — we've got your prospect written down, and it now moves through the desk with everything else we're tracking.", + "next_description": "An owner walks it from prospect to client, and on to past client, as the relationship moves.", + "next_heading": "It's on the desk now", + "question": "What happens to this now?" + }, + "questions/owners/prospect.yaml": { + "button": "Add to prospects", + "description": "One line per organization worth watching, moved through the stages as things develop.", + "encouragement": "Takes a minute, and it's yours to update later.", + "form_description": "Name the organization and where things stand.", + "form_title": "New prospect", + "heading": "Keep an organization on your radar", + "hints": { + "contact": "met at the bakers' conference, [email protected]", + "name": "Nordvik Bakery", + "note": "wants a booking flow, follow up after harvest season" + }, + "icon": "briefcase", + "labels": { + "contact": "Contact", + "name": "Organization", + "note": "Note" + }, + "page_description": "Write down an organization worth following up, and move it through client and past client as things develop.", + "question": "Is there an organization I should be keeping track of?", + "road_description": "It sits as a prospect until something moves - then you mark it client, and later past client if the work ends.", + "road_icon": "route", + "road_title": "Moves as you update it", + "who_description": "Only you see this, so keep it wherever you check next.", + "who_icon": "user", + "who_title": "Just for you" + }, + "questions/received/collaborate.yaml": { + "back": "Back to site", + "description": "Your note is in. An owner reads every one and will get back to you if there's a fit worth exploring.", + "next_description": "If it looks like a fit, we'll reach out to talk about where you could help.", + "next_heading": "We'll write if there's a fit", + "question": "What happens to what I just sent?" + }, + "questions/received/commission.yaml": { + "back": "Back to home", + "description": "Your brief is in. An owner reads every commission end to end before replying.", + "next_description": "Expect a reply within a few working days, either way, straight to your inbox.", + "next_heading": "A real reply from someone who read it", + "question": "What happens now that we've sent our brief?" + }, + "questions/received/custody.yaml": { + "back": "Back to the site", + "description": "A custodian reads every message about the redoal network and what it keeps.", + "next_description": "Expect a reply once your report has been looked at and the network checked.", + "next_heading": "A custodian is on it", + "question": "Who looks after what the network keeps?" + }, + "questions/received/propose.yaml": { + "back": "Back home", + "description": "Your proposal is in. Someone here will read it and decide whether it fits before anything changes on the page.", + "next_description": "We'll write back once it's been read — approved and made live, or turned down with a reason.", + "next_heading": "A read, then a decision", + "question": "What happens to my proposal now?" + }, + "questions/received/subscribe.yaml": { + "back": "Back to site", + "description": "You'll hear from us when there's something worth saying, not on a schedule.", + "next_description": "You're on the list. Every note has an unsubscribe link if it stops being useful.", + "next_heading": "You're on the list", + "question": "What happens now that I've subscribed?" + }, + "questions/received/trial.yaml": { + "back": "Back to site", + "description": "We read every trial request ourselves before anything gets built.", + "next_description": "If it looks like a fit, we'll draft your site from your own words and send it back for your say before anything goes live.", + "next_heading": "A first draft, built from your own words", + "question": "What happens now that you've sent this?" + } +} \ No newline at end of file diff --git a/src/build.rs b/src/build.rs index c974cd2..a5bdd82 100644 --- a/src/build.rs +++ b/src/build.rs @@ -171,6 +171,11 @@ pub struct PlanNeed { /// were complete). #[serde(default)] pub skippable: Vec, + /// The unfinished stages a case may still be turned down from; + /// empty means every one. An applicant is declined before they + /// start and not after, where they depart instead. + #[serde(default)] + pub turned_down_from: Vec, /// Who presses the button that moves a case INTO a stage, where it /// is not `handled_by`: another group, several groups, or /// `submitter` - the person who sent the form, through their own @@ -351,6 +356,11 @@ impl Plan { if need.watched_by.iter().any(|g| g == PUBLIC) && need.enters_as.is_some() { bail!(at("a public view is for what the public sent; an internal need has its group's desk")); } + for state in &need.turned_down_from { + if need.done_when.contains(state) || !need.stages.contains(state) { + bail!(at(&format!("turned_down_from names {state:?}, which is not one of its unfinished stages"))); + } + } for state in need.done_when.iter().chain(&need.skippable) { if !need.stages.contains(state) { bail!(at(&format!("{state:?} is not one of its stages"))); @@ -441,6 +451,7 @@ impl Plan { || other.attended_by != first.attended_by || other.mails != first.mails || other.stages_text != first.stages_text + || other.turned_down_from != first.turned_down_from { bail!("needs {:?} and {:?} both land in {bucket:?} and must agree on stages, done_when, skippable, events, attended_by, mails and who moves and watches it", first.id, other.id); } @@ -516,7 +527,9 @@ pub fn machine(need: &PlanNeed) -> BTreeMap> { } } } - to.extend(ends_badly.iter().map(|s| (*s).clone())); + if need.turned_down_from.is_empty() || need.turned_down_from.contains(stage) { + to.extend(ends_badly.iter().map(|s| (*s).clone())); + } moves.insert((*stage).clone(), to); } moves @@ -1642,7 +1655,7 @@ mod tests { lands_in: "b".into(), handled_by: "g".into(), stages: v(stages), done_when: v(done), success: v(success), skippable: v(skippable), moves_by: BTreeMap::new(), watched_by: vec![], - events: BTreeMap::new(), attended_by: None, mails: BTreeMap::new(), stages_text: BTreeMap::new(), + events: BTreeMap::new(), attended_by: None, mails: BTreeMap::new(), stages_text: BTreeMap::new(), turned_down_from: vec![], collects: vec![], max_fields: 3, } } @@ -1720,6 +1733,16 @@ mod tests { assert!(!m.contains_key("won")); } + #[test] + fn a_case_is_turned_down_only_where_the_plan_says() { + let mut n = need(&["open", "invited", "active", "departed", "declined"], &["departed", "declined"], &["departed"], &[]); + n.turned_down_from = vec!["open".into(), "invited".into()]; + let m = machine(&n); + assert_eq!(m["open"], ["invited", "declined"]); + assert_eq!(m["invited"], ["active", "declined"]); + assert_eq!(m["active"], ["departed"]); + } + #[test] fn a_skippable_stage_can_be_passed_over() { let m = machine(&need(&["open", "awaiting_papers", "approved", "declined"], &["approved", "declined"], &["approved"], &["awaiting_papers"])); diff --git a/src/plan.rs b/src/plan.rs index f90ee3a..8424453 100644 --- a/src/plan.rs +++ b/src/plan.rs @@ -70,6 +70,10 @@ needs: done_when: [, ] # every stage that counts as finished, good or bad success: [] # the finished stages that are a good outcome for the business skippable: [] # stages a case may pass over (papers already complete) + turned_down_from: [open, ] + # the unfinished stages a case can still be turned down from; + # omit for every one. An applicant is declined before they + # start, not after - after, they depart moves_by: { : [, ...] } # only where someone other than handled_by moves a case INTO a # stage: another group, or `submitter` (the person who sent the