6.1 KiB
Phase 10.1: Runtime admin extension point - Discussion Log
Audit trail only. Do not use as input to planning, research, or execution agents. Decisions are captured in CONTEXT.md — this log preserves the alternatives considered.
Date: 2026-09-28 Phase: 10.1-runtime-admin-extension-point Areas discussed: Acceptance target, Widget contract, Partials and custom toolbar actions, Asset load and CSP
Acceptance target
| Option | Description | Selected |
|---|---|---|
| Fixture plugin | Framework test plugin ships widget + partial + custom button | |
| Wait for a real plugin | Seams only; first consumer is user/media | |
| Fixture now, real consumer later | Fixture proves contract; real plugin is a later port | |
| Other: fonoteka statistics + Discogs widget | Real Albums list stats strip and Albums form Discogs widget | ✓ |
User's choice: Add a statistics partial to the fonoteka plugin above the list, and a custom fields.yaml widget that is a button to load data from Discogs (stub until Phase 14).
Notes: “Above the list” is list chrome, not type: partial in fields.yaml. Screens locked to Albums list + Albums form.
| Option | Description | Selected |
|---|---|---|
| Click hits a stub endpoint | Enabled button, POST, Phase 14 replaces stub | ✓ |
| Visible but disabled | No request until Phase 14 | |
| Click only runs widget JS | No new backend action |
User's choice: Stub endpoint.
| Option | Description | Selected |
|---|---|---|
| Albums list + Albums form | One controller owns both proofs | ✓ |
| Collections list + Albums form | Two controllers load different assets | |
| You decide | Planner picks screens |
User's choice: Albums list + Albums form.
| Option | Description | Selected |
|---|---|---|
| Defer custom toolbar | create/delete only until a real third action | |
| Add one Albums list action now | Third button, stub POST | ✓ |
| Fixture-only custom action | No Płytarium toolbar change |
User's choice: Add one Albums list action now.
Widget contract
| Option | Description | Selected |
|---|---|---|
| SPA owns HTTP | CustomEvent; FieldRenderer POSTs with CSRF | ✓ |
| Tiny same-origin helper | SummerAdmin.request() | |
| Widget fetch() itself | Widget must remember X-Requested-With |
User's choice: SPA owns HTTP.
| Option | Description | Selected |
|---|---|---|
| Patch declared fields | YAML fill keys; fixture payload allowed |
✓ |
| Toast only | Form unchanged | |
| Only this field’s value | Widget bound as one field |
User's choice: Patch declared fields.
| Option | Description | Selected |
|---|---|---|
| Winter-shaped type: widget | tag/path, action, fill; unknown keys fail boot | ✓ |
| type + path only | Action and fill live in Go | |
| You decide | Planner picks keys |
User's choice: Winter-shaped type: widget.
| Option | Description | Selected |
|---|---|---|
| Attributes + fill snapshot | record-id, field, locale, current fill values | ✓ |
| record-id only | Widget cannot see current name/year | |
| You decide | Planner picks attributes |
User's choice: Attributes + fill snapshot.
Partials and custom toolbar actions
| Option | Description | Selected |
|---|---|---|
| List-header only | Leave form type: partial as a boot error |
|
| List-header and form type: partial | Both in this phase | ✓ |
| You decide | Planner scopes it |
User's choice: Both.
| Option | Description | Selected |
|---|---|---|
| Curated view model | Typed struct from controller; auto-escaped | ✓ |
| Record map + extras | More Winter-like; leak risk | |
| You decide | Planner picks data shape |
User's choice: Curated view model.
| Option | Description | Selected |
|---|---|---|
| config_list.yaml slot | e.g. headerPartial names the template | ✓ |
| Controller Go API only | No YAML key | |
| You decide | Planner picks declaration |
User's choice: YAML slot.
| Option | Description | Selected |
|---|---|---|
| Named action + stub POST | toolbar.buttons string list; controller registers extras | ✓ |
| Inline map in YAML | strings or {action, label, confirm} | |
| You decide | Planner picks YAML |
User's choice: Named action + stub POST.
Asset load and CSP
| Option | Description | Selected |
|---|---|---|
| On controller open | Winter addJs/addCss timing | ✓ |
| All registered assets at login | Simpler, more JS in the admin origin | |
| Per widget/partial only | Finest grain, define() timing issues |
User's choice: On controller open.
| Option | Description | Selected |
|---|---|---|
| Embed only | air / summer watch rebuilds; no disk-in-prod | ✓ |
| Dev-mode disk override | Original 10.1 note; rejected | |
| You decide | Planner picks |
User's choice: Embed only.
| Option | Description | Selected |
|---|---|---|
| Under admin prefix, script-src 'self' | No unsafe-inline, no extra hosts | ✓ |
| Allow nonce inline for widgets | Weaker than current hygiene | |
| You decide | Planner picks URL layout |
User's choice: Prefix + script-src 'self'.
| Option | Description | Selected |
|---|---|---|
| Go method on the controller | addJs/addCss; new interface name | ✓ |
| YAML asset list | js:/css: in config | |
| You decide | Planner picks Go vs YAML |
User's choice: Go method.
the agent's Discretion
- Exact YAML key names, JS/CSS interface name, stub payload/toast copy, stats numbers, form-partial proof vehicle, custom-element tag naming, create vs update for the widget, asset URL layout, PartialHost vs T-10-16, toolbar action identifier.
Deferred Ideas
- Phase 14: real Discogs client and non-stub payloads
- Dev-mode disk override (rejected for v1)
- WASM extension API (v2)
- Phase 10 leftovers: Ctrl+K, badge columns, Playwright, user/media nav