From 8d10e997264e0c5d64244fb9aa21319196ace1c3 Mon Sep 17 00:00:00 2001 From: Bendik Aagaard Lynghaug Date: Wed, 12 Aug 2026 22:04:11 +0200 Subject: [PATCH] Actor state machines: employee lifecycle, investors, organizations wired, development proposals - applicants grows past the one decision: invited -> active (onboarded) -> departed, one continuous graph per person. - investors: open -> in_dialogue -> committed -> divested, with decline edges; submission via a new "I want to invest" alternative on /. - organizations (prospect -> client -> past_client) finally gets pages: a review listing with its transitions and a record-a-prospect form. - development_proposals: the question architecture dogfooding its own development - /develop-proposal takes proposals from anyone (human today, an LLM later through the same public form), /develop lets an owner approve or reject, and approval hands off to the automation that opens the PR (see infrastructure's development-commit workflow). The repo's own lint CI gates the merge, same as any human commit. Co-Authored-By: Claude Sonnet 5 --- aggregates.yaml | 34 ++++++++++++++ questions/develop-proposal.yaml | 41 +++++++++++++++++ questions/develop.yaml | 26 +++++++++++ questions/index.yaml | 26 +++++++++++ questions/invested.yaml | 16 +++++++ questions/proposed.yaml | 17 +++++++ questions/review.yaml | 79 +++++++++++++++++++++++++++++++++ 7 files changed, 239 insertions(+) create mode 100644 questions/develop-proposal.yaml create mode 100644 questions/develop.yaml create mode 100644 questions/invested.yaml create mode 100644 questions/proposed.yaml diff --git a/aggregates.yaml b/aggregates.yaml index d871199..e607fb6 100644 --- a/aggregates.yaml +++ b/aggregates.yaml @@ -10,14 +10,22 @@ # the graph itself. Add a new aggregate here alone - no portal code # change needed. aggregates: +# One continuous graph per person, applicant through employee - the +# bucket name stays "applicants" even as a record progresses past the +# applying stage (a deliberate trade: one chain of events per person, +# no identity-linking between separate buckets). - bucket: applicants initial: open states: open: { event: applied } invited: { event: invited } declined: { event: declined } + active: { event: onboarded } + departed: { event: departed } transitions: open: [invited, declined] + invited: [active, declined] + active: [departed] - bucket: subscribers initial: open @@ -45,3 +53,29 @@ aggregates: transitions: prospect: [client, past_client] client: [past_client] + + - bucket: investors + initial: open + states: + open: { event: expressed_interest } + in_dialogue: { event: entered_dialogue } + committed: { event: committed } + declined: { event: declined } + divested: { event: divested } + transitions: + open: [in_dialogue, declined] + in_dialogue: [committed, declined] + committed: [divested] + +# Proposals to change this very repo - the question architecture +# dogfooding its own development. Approval hands off to an n8n +# automation that opens a PR against this repo (see the infrastructure +# repo's development-commit workflow); the lint CI gates the merge. + - bucket: development_proposals + initial: open + states: + open: { event: proposed } + approved: { event: approved } + rejected: { event: rejected } + transitions: + open: [approved, rejected] diff --git a/questions/develop-proposal.yaml b/questions/develop-proposal.yaml new file mode 100644 index 0000000..0b8e49b --- /dev/null +++ b/questions/develop-proposal.yaml @@ -0,0 +1,41 @@ +id: /develop-proposal +route: ^/develop-proposal +name: Propose a change +description: > + This site is built on the same question architecture you're using + right now — and changes to it are proposed through it. Describe what + should change and why; an owner reviews every proposal, and approved + ones become real commits. +alternatives: + - name: What should change? + description: > + The proposed content replaces (or creates) one file in the + questions repo, verbatim — so it has to be complete, valid YAML + for that file, not a diff. + action: /proposed + consequence: [Propose it] + record_as: development_proposals + encouragements: + - Every proposal gets read by a person before anything moves. + features: + - name: Who's proposing? + description: "" + requirements: + - name: submitted_by + label: Name (or what to call you) + - name: email + label: Email + type: email + optional: true + - name: The change + description: "" + requirements: + - name: target_path + label: File path + placeholder: questions/example.yaml + - name: rationale + label: Why this change? + type: textarea + - name: proposed_yaml + label: Proposed file content (complete YAML) + type: textarea diff --git a/questions/develop.yaml b/questions/develop.yaml new file mode 100644 index 0000000..6427c52 --- /dev/null +++ b/questions/develop.yaml @@ -0,0 +1,26 @@ +id: /develop +route: ^/develop +name: Development proposals +qualifies: owners +description: > + Proposed changes to the questions repo, awaiting a decision. + Approval hands off to the automation that opens the pull request — + lint gates the merge, not this page. +alternatives: + - name: Proposals + description: "" + action: /develop + consequence: [Confirm] + features: + - name: "" + description: "" + resource: + source: + kind: kv + bucket: development_proposals + requires_group: owners + transitions: + - to: approved + label: Approve + - to: rejected + label: Reject diff --git a/questions/index.yaml b/questions/index.yaml index 8b324d4..d37838d 100644 --- a/questions/index.yaml +++ b/questions/index.yaml @@ -64,6 +64,32 @@ alternatives: label: Email type: email + - name: I want to invest + description: > + We grow deliberately — distributed communication architecture, + built to last. If that's where you want your capital working, + let's talk. + action: /invested + consequence: [Open the conversation] + record_as: investors + encouragements: + - Serious inquiries get a serious answer. + features: + - name: Who are you? + description: "" + requirements: + - name: name + label: Name + - name: email + label: Email + type: email + - name: What brings you here? + description: "" + requirements: + - name: motivation + label: Why redoal, and what are you looking for? + type: textarea + - name: I want in description: > We onboard collaborators the same deliberate way we build — diff --git a/questions/invested.yaml b/questions/invested.yaml new file mode 100644 index 0000000..3bea5df --- /dev/null +++ b/questions/invested.yaml @@ -0,0 +1,16 @@ +id: /invested +route: ^/invested +name: What happens now? +description: > + Your interest is on its way to a real inbox. Expect a considered, + personal reply — not a pitch deck on autopilot. +alternatives: + - name: In short + description: "" + features: + - name: We read it + description: In full, before we write back. + - name: Dialogue before commitment + description: > + We'll want to understand each other properly first — what + you're looking for, and whether we're actually it. diff --git a/questions/proposed.yaml b/questions/proposed.yaml new file mode 100644 index 0000000..058254a --- /dev/null +++ b/questions/proposed.yaml @@ -0,0 +1,17 @@ +id: /proposed +route: ^/proposed +name: Proposal received +description: > + It's in the queue. An owner reads every proposal in full — approved + ones open a real pull request, and the same checks every human + commit passes gate the merge. +alternatives: + - name: What happens now + description: "" + features: + - name: A person decides + description: Nothing merges on autopilot — approval is a deliberate act. + - name: The linter has no favorites + description: > + Approved or not, your YAML faces the same validation as + everything else in the repo. diff --git a/questions/review.yaml b/questions/review.yaml index e1bbfd1..77df850 100644 --- a/questions/review.yaml +++ b/questions/review.yaml @@ -22,6 +22,85 @@ alternatives: label: Invite - to: declined label: Decline + - from: invited + to: active + label: Onboard + - from: invited + to: declined + label: Decline + - from: active + to: departed + label: Depart + + - name: Investors + description: "" + action: /review + consequence: [Confirm] + features: + - name: "" + description: "" + resource: + source: + kind: kv + bucket: investors + requires_group: owners + transitions: + - to: in_dialogue + label: Open dialogue + - to: declined + label: Decline + - from: in_dialogue + to: committed + label: Commit + - from: in_dialogue + to: declined + label: Decline + - from: committed + to: divested + label: Divest + + - name: Organizations + description: > + Client relationships as tracked state — advanced as the + relationship becomes real. + action: /review + consequence: [Confirm] + features: + - name: "" + description: "" + resource: + source: + kind: kv + bucket: organizations + requires_group: owners + transitions: + - from: prospect + to: client + label: Becomes client + - from: prospect + to: past_client + label: Archive + - from: client + to: past_client + label: Churn + + - name: Record a prospect + description: "" + action: /review + consequence: [Record] + record_as: organizations + features: + - name: "" + description: "" + requirements: + - name: name + label: Organization + - name: contact + label: Contact + - name: note + label: Anything worth remembering + type: textarea + optional: true - name: Projects description: ""