A host reboot on 2026-08-30 left the instance down: deploys only ever
started it. enable is best-effort until the host's polkit rule grants
manage-unit-files to deploy-runner.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Desk/receipt titles become questions (What's been proposed? / What
happens to your proposal? / What came in? / Which proposal is this?),
Where to send it and Record a prospect explain why before the field,
lucide icons on input-bearing features, README's alternatives rule
reworded (draw people in with a real path, not necessarily a slogan)
and its stale /develop-proposal + followup references fixed.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
develop/ holds the whole proposal flow (index = owners desk,
proposal = public form, proposed = chain-gated receipt) with relative
actions; review/ gains _section.yaml (one owners gate for the
directory) and a [record].yaml dynamic page - /review/<chain-hash>
shows a single proposal. Top-level files drop their now-derived id:
and fossil route: fields. URLs /develop-proposal and /proposed become
/develop/proposal and /develop/proposed (no automation references
them - n8n filters checked).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A private starred repo used to link visitors straight to a 404. The
link now uses the repo's Website setting when set, falls back to the
repo url only for public repos, and renders private repos without a
website as unlinked cards. Also: Gitea serializes the star count as
stars_count, not GitHub's stargazers_count - the stars chip had been
silently null and dropped.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
proposed_yaml binds to the file select: the selected file's content
fetches through Gitea's contents API (base64-decoded by the jq
filter) and lands in the editor. On-site contributions no longer
start from a blank box.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
A linked card straight from Gitea's repo info - proposers can read
what exists before proposing against it.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
target_path becomes a select whose options are the live listing of
questions/ from Gitea's contents API (the engine's existing
select-from-resource mechanism - no code change), with a free path
field kept for proposals that create a new file. No more hand-typed,
typo-able paths for existing pages.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The automation fences commits to questions/*.yaml and aggregates.yaml;
the page and README now say so, instead of promising "any file" and
silently failing after approval.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
It was a worked example of the empathic pattern, not a feature: every
alternative should be empathic, informative, and helpful - information
that gives an answer, not necessarily a path to choose. The pattern
stays (voice rules, README); the investor pages, aggregate, review
alternative, and front-page gateway go. The investors KV bucket and
its test records linger in NATS unreferenced - purge at leisure.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The title is the only question; alternatives are bold statements
argued against each other; explain why input is needed, then hand
over the field; never assume the visitor's role - give the concern
its own page and let the question nav surface it.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- The page title is the only question anywhere; alternative and
feature names are now statements in our voice. Where we need input
we say why (the reply is personal, software lands somewhere, a
proposal is a stance), then hand over the field.
- The opening question's alternatives become the statements we'd like
visitors to get behind: "Good software begins with a clear
argument", "Attention is earned", "Capital needs reasons", "Work
happens through dialogue, not tickets".
- followup: true on the five post-submission pages keeps them out of
the question nav until the visitor actually carries a chain.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
"I want to invest" on the front page presumed the visitor's intent.
/invest now asks it from their side - "How do we invest in uhhm?" -
and speaks to what a capital manager is actually accountable for:
reasons. The front page keeps only a light gateway; the question nav
surfaces /invest (like every other qualifying question) from anywhere,
so no concern depends on front-page space.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Replaces the long-stale schema notes (pre-aggregates, pre-resources,
pre-proposal-loop) with what the repo actually is now: declare a state
graph, give it a way in (submission), a way through (review
transitions), let automations react, and change the system through
itself.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
It existed to prove the round-trip (proposed -> approved -> PR ->
lint -> merge -> live) and it did. Its job is done.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
End-to-end verification of the proposal loop - this page is a harmless demo and can be deleted after the round-trip is confirmed.
Proposed-by: Verification Bot
Approved-by: bl@id.uhhm.no
A development-proposal PR previously got no check at all (the workflow
only fired on push to main) - so branch protection's required status
check, the thing that makes the automation's merge_when_checks_succeed
an actual lint gate, had nothing to require. Lint now runs on both
events; the content-reload NATS publish stays push-only.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- 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 <noreply@anthropic.com>
Confirmed it renders correctly (icon + accent border, banner image) -
reverting since which features/alternatives actually get these is an
editorial choice, not mine to make.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Matches the pattern Subscribers already used (action: /review +
consequence). Portal's per-row Confirm button is going away in favor
of one shared, content-labeled button per alternative that confirms
every selected row at once - see the paired portal change.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Portal's aggregate state machines used to be compiled Rust, duplicated
across four files plus the bucket-name wiring that dispatched to them.
This is now the single source of truth for what states exist, what
event-type string represents each, and what transitions are legal -
portal loads and validates it at boot/reload (see the paired portal
change). Adding a new aggregate, or reshaping an existing one, is now
a content-only change.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
lint.sh only ever checked shape (missing id/name, duplicate ids, bad
requirement types) - it never validated transition targets against the
real state machines. question_lint runs portal's actual validation
logic (content::validate_questions) with no portal build required in
this repo's CI, since portal's deploy job now publishes it to a stable
path on the same runner/host.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
applied.yaml and index.yaml still described review in the passive
third person ("someone here will read this", "taken on by someone
who reads") after project.yaml and the rest of applied.yaml's own
features had already been reworked to a direct first-person "we"
voice centered on the visitor's value, not on the fact that a person
reads it.