plresearch-org · edit-ai-opportunity-spaces-r3 · round 3

Round 3: generalize to all 4 areas + array-field editing

@daviddao

Follow-up to r2's remaining work items. All 15 opportunity-space records across all four focus areas (AI & Robotics, Digital Human Rights, Neurotech, Economies & Governance) now have working admin editors that cover both prose and array fields, backed by a single shared <OpportunitySpaceEditor> component.

Date: 2026-04-20 · Target: neural-augmentation (Neurotech) · Previous: r2 (pass) · pass


Headline result

4 / 4
Focus areas editable
15 / 15
Opportunity-space records with a working Edit button
5
Array fields now editable per record
1
UX bug found & fixed mid-run (remove buttons)

Headline. R2 shipped the editing loop only for AI & Robotics. R3 generalises it: a single <OpportunitySpaceEditor> client component now powers editing for every opportunity space across the four focus areas. Array fields (subfields, tippingSignals, keyAssumptions, observations, fieldSignals{kpi,measurement}) are editable with per-item add/remove. End-to-end verified on Neurotech: added a new tipping signal, confirmed it reached the PDS, confirmed the public detail page rendered it. Mid-run caught and fixed a real usability bug: the per-item remove controls were opacity-0 until hover, which hid them from keyboard and programmatic users.

What changed (the fix)

Two commits: the main generalisation, plus a one-line fix for the opacity bug discovered during testing.

Commits87a6a0f (generalise) · 65b659e (opacity fix) Diff11 files changed, +713/-228 — net gain driven by the new shared editor and three new thin edit-route wrappers
FileChange
src/components/OpportunitySpaceEditor.tsxNew. Client component that accepts areaSlug + areaLabel + slug. Fetches the record via the API route, renders an inline editor covering all 13 fields, and PUTs on save. Replaces 200+ lines of duplicated editor code.
src/app/areas/{ai-robotics,digital-human-rights,neurotech,economies-governance}/opportunity-spaces/[slug]/edit/page.tsxAll four are now thin 10-line wrappers that forward params.slug and their areaSlug/areaLabel to the shared editor.
src/app/areas/{dhr,neuro,eg}/opportunity-spaces/page.tsxList pages for the three remaining areas switched to fetchOpportunitySpaces(areaSlug) with the static JSON as a build-time fallback (mirrors r2's AI change).
src/app/areas/{dhr,neuro,eg}/opportunity-spaces/[slug]/page.tsxDetail pages for the three remaining areas switched to fetchOpportunitySpace(rkey) + static fallback, and render <EditPageButton/> pointing at the per-area edit route.
src/components/OpportunitySpaceEditor.tsx (commit 2)Remove buttons for string-array items and field-signal cards no longer rely on opacity-0 group-hover:opacity-100; they are now always visible in a faint gray that darkens on hover.

Walkthrough

Captured on production, signed in as satyam2.climateai.org. To exercise a different area than r2, the primary test target is Neurotech / Neural Augmentation (BCI) rather than AI & Robotics. Full flow: list page → detail page → edit button → editor → save → PDS → indexer → public page.

Neurotech opportunity spaces list, server-fetched from the indexer
01/areas/neurotech/opportunity-spaces/ now server-fetches its 3 cards from the indexer on build/revalidate (with the static JSON as fallback). Confirms the list-page generalisation landed.
Neurotech detail page with Edit button
02Detail page for Neural Augmentation (BCI) now shows the “Edit page” button for admins — parity with AI & Robotics shipped in r2.
Editor — hero fields
03Editor top. Title, tagline, description load as in r2.
Editor — tipping signals array
04New in r3: the tipping signals array is editable as a list of textboxes with per-item add & remove. Same pattern applies to subfields, context, friction.
Editor — Context (keyAssumptions) and Friction (observations) side-by-side
05Context (keyAssumptions[]) and Friction (observations[]) render as a two-column block matching the public page layout, each an editable array of paragraph-sized textareas.
Editor — Field Signals (KPI + measurement pairs)
06Field Signals (fieldSignals[{kpi, measurement}]) get their own card editor with “+ Add field signal” and per-card remove. Completes the 5-array field coverage.
After save — tagline updated, new signal present
07Edited the tagline and clicked “+ Add item” in Tipping Signals to insert “Added via pi-eval r3 test — verifying array-field editing works”. Clicked Save; bar returned to idle. updatedAt on the PDS advanced to 20:07:25Z.
Public detail page renders the newly added tipping signal pill
08Hard-reload of the public detail page shows the new tipping-signal pill alongside the original five — full loop (UI → PUT → PDS → indexer → revalidateTag("indexer") → ISR) working for array fields, not just prose.
After opacity fix: remove buttons visible by default
09Mid-run fix: the per-item “remove” controls were previously opacity-0 group-hover:opacity-100, so programmatic clicks (agent-browser) and keyboard navigation couldn’t reach them. After commit 65b659e they render as faint text-gray-300 by default and darken on hover. With this, the test was able to remove the 6th tipping signal — the clean revert confirmed the full edit → save → revert cycle works.
Digital Human Rights editor loads cleanly
10Digital Human Rights / Verifiable Public Knowledge & Provenance editor loads via the same shared component; breadcrumbs update to the correct area label.
Economies & Governance editor loads cleanly
11Economies & Governance / Sovereign Digital Public Infrastructure editor loads cleanly. All four areas render through the same <OpportunitySpaceEditor>.
E&G detail page still shows its bespoke Dependency Graph link alongside the new Edit button
12The E&G detail page is the one most extended from the shared template (has its own “Dependency Graph” sub-link, kept intact). The Edit button sits alongside the existing UI without conflicts.

PDS verification (xrpc)

After the add-signal save, the record on plresearch.org’s PDS shows the new 6th entry:

$ curl -sG "https://leccinum.us-west.host.bsky.network/xrpc/com.atproto.repo.getRecord" \
    --data-urlencode "repo=did:plc:pgwr6hkosgznfl5nz7egajei" \
    --data-urlencode "collection=org.plresearch.opportunitySpace" \
    --data-urlencode "rkey=neuro--neural-augmentation" | jq '.value | {tagline, tippingSignals, updatedAt}'
{
  "tagline": "… [edited via pi-eval r3]",
  "tippingSignals": [
    "FDA clearance of a standardized API/software layer for a commercial BCI device",
    "Successful launch and adoption of the first third-party app for a BCI device",
    "Off-label BCI implants commencing for non-medical consumer use",
    "Non-invasive or minimally invasive devices proven safe, effective, and scalable",
    "Robotic surgery enabling 20-minute outpatient BCI implantation procedures",
    "Added via pi-eval r3 test — verifying array-field editing works"
  ],
  "updatedAt": "2026-04-20T20:07:25.824Z"
}

After the revert (remove 6th signal & restore tagline):

{
  "tagline": "Low-cost, scalable, high-bandwidth bidirectional interfaces …",
  "tippingSignals": [… 5 items, original content …],
  "updatedAt": "2026-04-20T20:14:09.603Z"
}

Findings

P1 · All 4 areas are now editable end-to-end

Admin Edit buttons + working inline editors exist for every opportunity-space page across AI & Robotics, Digital Human Rights, Neurotech, and Economies & Governance. 15 records, same pattern.

P2 · Array fields save correctly end-to-end

Edited a string-array (tippingSignals) on Neurotech: save → PDS → indexer → ISR all reflected the new entry within seconds. PUT payload includes every array (empty strings filtered out by the client before submit), so subfields, keyAssumptions, observations, and fieldSignals all write through the same path.

P3 · Single-component architecture

The editor logic lives in one file; per-area edit routes are 10-line wrappers. Adding a fifth area (if ever) is effectively a 3-file copy-paste: one edit-route wrapper, one list patch, one detail patch.

FIX1 · Per-item remove buttons were invisible by default

The initial implementation used opacity-0 group-hover:opacity-100 for both the StringArrayEditor remove button and the fieldSignal card remove. This pattern hides the control from:

Replaced with an always-visible faint gray-300 that darkens to red on hover (commit 65b659e). Verified the fix works by removing the 6th tipping signal via the restored control.

I1 · Can't create new opportunity-space records from the UI yet

Editing existing records works, but there’s no “New opportunity space” flow. PUT /api/opportunity-spaces/[rkey] would accept a never-before-seen rkey because ATProto’s putRecord is idempotent, but the UI has no create form. Low priority — existing records can be duplicated by manual xrpc for now, and the 15-record set is unlikely to grow fast.

I2 · image field isn’t editable from the UI

The editor surface excludes image (stock photo URL). PUT still accepts whatever the record has, so the value round-trips untouched, but changing the image requires editing the JSON directly or calling the xrpc route. Consider a URL input + preview in a later round.

Reproducing

URLhttps://www.plresearch.org/admin Handlesatyam2.climateai.org Passwordtest password — redacted Target edit page/areas/neurotech/opportunity-spaces/neural-augmentation/edit Other areas verified/areas/digital-human-rights/opportunity-spaces/verifiable-public-knowledge/edit
/areas/economies-governance/opportunity-spaces/sovereign-dpi/edit
Toolagent-browser (snapshot-driven) PDS verifycurl -sG .../xrpc/com.atproto.repo.getRecord --data-urlencode collection=org.plresearch.opportunitySpace --data-urlencode rkey=neuro--neural-augmentation Previous roundsr1 (fail) · r2 (pass) Screenshotsassets/01-*.pngassets/12-*.png