pi-simocracy 0.5.1 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +51 -201
- package/docs/SIM_AUTHORED_COMMENTS.md +197 -0
- package/docs/SIM_AUTHORED_PROPOSALS.md +198 -0
- package/package.json +2 -1
- package/src/index.ts +882 -11
- package/src/lookup.ts +537 -0
- package/src/writes.ts +237 -0
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
# Sim-authored proposals
|
|
2
|
+
|
|
3
|
+
How pi-simocracy attributes a funding proposal to a sim *without*
|
|
4
|
+
extending the `org.hypercerts.claim.activity` lexicon — and what
|
|
5
|
+
[simocracy-v2](https://github.com/GainForest/simocracy-v2) needs to
|
|
6
|
+
do to render the attribution. Same pattern as
|
|
7
|
+
[sim-authored comments](./SIM_AUTHORED_COMMENTS.md), different
|
|
8
|
+
subject collection.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## TL;DR
|
|
13
|
+
|
|
14
|
+
When pi submits a proposal on behalf of a loaded sim, it writes
|
|
15
|
+
**two** records to the user's PDS:
|
|
16
|
+
|
|
17
|
+
1. **`org.hypercerts.claim.activity`** — the proposal itself, in the
|
|
18
|
+
exact shape simocracy.org's `ProposalFormDialog` already writes
|
|
19
|
+
today (`title`, `shortDescription`, optional `description` /
|
|
20
|
+
`workScope` / `contributors` / `image`, `createdAt`). Old readers
|
|
21
|
+
(Hyperindexer, the existing webapp) see this as a regular
|
|
22
|
+
user-authored proposal — graceful degradation.
|
|
23
|
+
2. **`org.simocracy.history`** — sidecar record with `type:
|
|
24
|
+
"proposal"`, `subjectUri` pointing at the proposal we just wrote,
|
|
25
|
+
`simUris[]` / `simNames[]` declaring which sim spoke. New `type`
|
|
26
|
+
value, but the lexicon's `type` field is free-form string and the
|
|
27
|
+
indexer already accepts new event types as they appear.
|
|
28
|
+
|
|
29
|
+
Renderers that understand the join (simocracy.org, when the planned
|
|
30
|
+
change lands) will display a sim badge on the proposal card;
|
|
31
|
+
renderers that don't keep showing it as a regular user proposal.
|
|
32
|
+
**Zero hypercerts lexicon changes. Zero new Simocracy lexicons.**
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Why no lexicon change
|
|
37
|
+
|
|
38
|
+
The `org.hypercerts.*` namespace is owned by the GainForest
|
|
39
|
+
hyperindexer project, not Simocracy — extending
|
|
40
|
+
`org.hypercerts.claim.activity` with a `sim` StrongRef field would
|
|
41
|
+
couple two independent release cycles together for one cross-app
|
|
42
|
+
feature, and the same argument made for comments
|
|
43
|
+
([`SIM_AUTHORED_COMMENTS.md`](./SIM_AUTHORED_COMMENTS.md)) applies
|
|
44
|
+
verbatim here.
|
|
45
|
+
|
|
46
|
+
The `org.simocracy.history` lexicon already has every field we need:
|
|
47
|
+
|
|
48
|
+
| Field | Used for sim-authored proposals |
|
|
49
|
+
|--------------------|--------------------------------------------------------------|
|
|
50
|
+
| `type` | `"proposal"` (new value — appended like other event types) |
|
|
51
|
+
| `actorDid` | The human who submitted on the sim's behalf |
|
|
52
|
+
| `simNames[]` | Display name(s) of the sim(s) credited as author |
|
|
53
|
+
| `simUris[]` | AT-URI(s) of the sim(s) — the sim-attribution key |
|
|
54
|
+
| `subjectUri` | AT-URI of the proposal record this attribution applies to |
|
|
55
|
+
| `subjectCollection`| `"org.hypercerts.claim.activity"` |
|
|
56
|
+
| `subjectName` | Proposal title (denormalized for the timeline) |
|
|
57
|
+
| `proposalTitle` | Same as `subjectName` — kept parallel to comment sidecars |
|
|
58
|
+
| `content` | Denormalized description (so the indexer doesn't have to join across PDSs to display the timeline) |
|
|
59
|
+
| `createdAt` | ISO timestamp |
|
|
60
|
+
|
|
61
|
+
Use it as-is.
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## Write path (pi-simocracy)
|
|
66
|
+
|
|
67
|
+
Implemented by `simocracy_post_proposal` in `src/index.ts`:
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
// 1. The proposal — same shape as ProposalFormDialog writes today.
|
|
71
|
+
const proposal = await createProposal({
|
|
72
|
+
agent, did,
|
|
73
|
+
title,
|
|
74
|
+
shortDescription,
|
|
75
|
+
description: finalDescription, // user body + appended budget block, if any
|
|
76
|
+
workScope,
|
|
77
|
+
contributors: contributors.map((c) => ({ contributorIdentity: c })),
|
|
78
|
+
image: { $type: "org.hypercerts.defs#uri", uri: imageUri ?? DEFAULT_BANNER },
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
// 2. The sim-attribution sidecar — required, since attribution is the whole
|
|
82
|
+
// point of this tool.
|
|
83
|
+
await createProposalHistory({
|
|
84
|
+
agent, did,
|
|
85
|
+
proposalUri: proposal.uri,
|
|
86
|
+
proposalTitle: title,
|
|
87
|
+
simUri: loadedSim.uri,
|
|
88
|
+
simName: loadedSim.name,
|
|
89
|
+
content: finalDescription || shortDescription,
|
|
90
|
+
});
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Both writes go to the **user's** PDS via their OAuth session — same
|
|
94
|
+
auth path that already powers `simocracy_post_comment` and
|
|
95
|
+
`simocracy_update_sim`. The write is gated on `/sim login` plus sim
|
|
96
|
+
ownership (the sim must live in the signed-in DID's repo) — the
|
|
97
|
+
sidecar uses `assertRepoOwnsSimUri` as defense-in-depth, identical
|
|
98
|
+
to the comment path.
|
|
99
|
+
|
|
100
|
+
If the sidecar write fails after the proposal succeeds, **the
|
|
101
|
+
proposal is not rolled back** — it just shows up unattributed until
|
|
102
|
+
the user retries. We don't roll back, because rolling back leaves an
|
|
103
|
+
orphaned tombstone in the user's repo that's harder to reason about
|
|
104
|
+
than a missing badge. The tool surfaces a `sidecarWarning` in the
|
|
105
|
+
result so the LLM can decide whether to retry.
|
|
106
|
+
|
|
107
|
+
### What we deliberately don't do
|
|
108
|
+
|
|
109
|
+
- **Image upload from disk.** The webapp uploads to `/api/upload-blob`;
|
|
110
|
+
pi-simocracy has no equivalent and we deliberately stay
|
|
111
|
+
read-mostly on blobs. The tool accepts an https `imageUri` only,
|
|
112
|
+
with a default that mirrors the webapp's banner fallback.
|
|
113
|
+
- **Adding the proposal to a floor / collection.** That's a separate
|
|
114
|
+
`org.hypercerts.claim.collection` write the webapp does via
|
|
115
|
+
`/api/ftc-sf/add-to-collection`. Out of scope for this tool; a
|
|
116
|
+
follow-up tool can chain it after the fact.
|
|
117
|
+
- **Editing existing proposals.** Create-only for now.
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## Read path (proposed simocracy-v2 changes)
|
|
122
|
+
|
|
123
|
+
Mirrors the comment renderer change in shape, applied to the
|
|
124
|
+
proposal list / detail views.
|
|
125
|
+
|
|
126
|
+
### 1. Proposal list query — pull history records in parallel
|
|
127
|
+
|
|
128
|
+
After fetching the proposals for a floor / collection, fetch all
|
|
129
|
+
`org.simocracy.history` records (capped, like notifications does)
|
|
130
|
+
and build a `Map<proposalUri, HistoryRecord>` keyed on `subjectUri`.
|
|
131
|
+
Filter to `type === "proposal"` and `subjectCollection ===
|
|
132
|
+
"org.hypercerts.claim.activity"`. Attach `simUri`, `simName`, and a
|
|
133
|
+
resolved `simAvatarUrl` to each proposal in the response that has a
|
|
134
|
+
match. Sim avatar resolution can reuse `fetchAllSimsWithMeta()` —
|
|
135
|
+
no extra round-trips per proposal.
|
|
136
|
+
|
|
137
|
+
### 2. Extend the proposal type
|
|
138
|
+
|
|
139
|
+
```ts
|
|
140
|
+
export interface ProposalRecord {
|
|
141
|
+
// …existing fields…
|
|
142
|
+
simUri?: string
|
|
143
|
+
simName?: string
|
|
144
|
+
simAvatarUrl?: string
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
No change to `ProposalFormDialog` — that path stays for human
|
|
149
|
+
authors. Sim-authored proposals come from the CLI today, and a
|
|
150
|
+
future "submit as sim" button in the modal would bundle both writes
|
|
151
|
+
the same way pi-simocracy does.
|
|
152
|
+
|
|
153
|
+
### 3. Proposal card — sim badge
|
|
154
|
+
|
|
155
|
+
In the proposal card component, when `proposal.simUri` is set:
|
|
156
|
+
|
|
157
|
+
- Replace the author avatar with the sim's sprite (32×32 walk-1 frame).
|
|
158
|
+
- Render the byline as `🐾 {simName} · drafted by @{userHandle}` so
|
|
159
|
+
attribution stays unambiguous (the sim "drafted" it; the human
|
|
160
|
+
submitted and owns the record).
|
|
161
|
+
- Add a `[sim]` mono-uppercase badge alongside the existing meta
|
|
162
|
+
pills.
|
|
163
|
+
- Link the sim name to `/sims/{did}/{rkey}` via the existing slug
|
|
164
|
+
resolver.
|
|
165
|
+
|
|
166
|
+
Proposals without `simUri` keep rendering exactly as today — no
|
|
167
|
+
regression for human-authored proposals.
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## Querying sim-authored proposals
|
|
172
|
+
|
|
173
|
+
For "show me everything my sim has proposed":
|
|
174
|
+
|
|
175
|
+
```ts
|
|
176
|
+
const histories = await fetchHistory() // existing helper
|
|
177
|
+
const mySimProposals = histories.filter(h =>
|
|
178
|
+
h.event.type === "proposal" &&
|
|
179
|
+
h.event.simUris?.includes(mySimUri)
|
|
180
|
+
)
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
Each result has `subjectUri` (the proposal URI) and `content`
|
|
184
|
+
(denormalized description). Resolve the proposal URI for the full
|
|
185
|
+
record. Same query shape the notifications system already uses for
|
|
186
|
+
chat / hearing / sprocess events — no new indexer queries needed.
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## Status
|
|
191
|
+
|
|
192
|
+
- ✅ Implemented in pi-simocracy `simocracy_post_proposal` (this repo)
|
|
193
|
+
- 🟡 Renderer changes pending in simocracy-v2
|
|
194
|
+
- 🟢 Lexicons unchanged — both repos can ship the change independently
|
|
195
|
+
|
|
196
|
+
The proposal + history pair is being written today. As soon as
|
|
197
|
+
simocracy-v2 lands the renderer change, every existing pi-authored
|
|
198
|
+
sim proposal retro-actively gets the sim badge — no migration.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-simocracy",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"description": "Pi extension: load a Simocracy sim into your chat — see its pixel-art sprite render inline in the terminal and roleplay with it.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"author": "David Dao <david@gainforest.earth> (https://github.com/daviddao)",
|
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
},
|
|
33
33
|
"files": [
|
|
34
34
|
"src/",
|
|
35
|
+
"docs/",
|
|
35
36
|
"README.md",
|
|
36
37
|
"LICENSE"
|
|
37
38
|
],
|