docs(14.2.1-06): complete lift ML maps on relation-child saves plan

Record WR-02 close-out, D-06/D-17 coverage, and last-plan gate evidence for phase verification.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Jakub Zych
2026-10-06 16:30:03 +02:00
parent ef03016314
commit 9a7c15608c
3 changed files with 240 additions and 11 deletions

View File

@@ -843,7 +843,7 @@ Plans:
3. Cabana `markdown`/`mltext`/`mlmarkdown` compose; nested locale writes are not dropped; docs, OpenAPI, TS types and `boardwalk` `dist/` update in the same change.
4. Proof host `sm-grzybyfunkcjonalne-app` boots with user+translate; unit tests are the last plan.
**Plans:** 5/6 plans executed
**Plans:** 6/6 plans executed
Plans:
@@ -863,7 +863,7 @@ Plans:
- [x] 14.2.1-05-PLAN.md — Hydrate enabled locales on admin ML forms (CR-01)
**Wave 6** *(gap closure, blocked on Wave 5 completion)*
- [ ] 14.2.1-06-PLAN.md — Lift ML maps on relation-child saves (WR-02); named tests last
- [x] 14.2.1-06-PLAN.md — Lift ML maps on relation-child saves (WR-02); named tests last
**Cross-cutting constraints:**
- Nested locale writes are not dropped on the admin form path and on relation-child saves

View File

@@ -4,16 +4,16 @@ milestone: v1.0
current_phase: 14.2.1
current_phase_name: Translate plugin (INSERTED)
status: executing
stopped_at: Completed 14.2.1-05-PLAN.md
last_updated: "2026-10-06T13:44:21.673Z"
stopped_at: Completed 14.2.1-06-PLAN.md
last_updated: "2026-10-06T14:29:39.010Z"
last_activity: 2026-10-06
last_activity_desc: Phase 14.2.1 execution started
state_head: 424fe9ccc06d34436e148add6334d1c2206723c2
state_head: ef0301631448e7e287c4f68ea3f16eb7ae2004c1
progress:
total_phases: 26
completed_phases: 12
total_plans: 131
completed_plans: 130
completed_plans: 131
milestone_name: milestone
---
@@ -29,9 +29,9 @@ See: .planning/PROJECT.md (updated 2026-09-16)
## Current Position
Phase: 14.2.1 (Translate plugin (INSERTED)) — EXECUTING
Plan: 5 of 6 complete
Status: Ready to execute 14.2.1-06
Last activity: 2026-10-06 — Completed 14.2.1-05-PLAN.md
Plan: 6 of 6 complete
Status: Ready for phase verification
Last activity: 2026-10-06 — Completed 14.2.1-06-PLAN.md
Progress: [██████████] 100%
@@ -185,6 +185,7 @@ Progress: [██████████] 100%
| Phase 14.2.1 P03 | 5 min | 3 tasks | 40 files |
| Phase 14.2.1 P04 | 51 min | 3 tasks | 22 files |
| Phase 14.2.1 P05 | 11 | 3 tasks | 24 files |
| Phase 14.2.1 P06 | 41min | 3 tasks | 15 files |
## Accumulated Context
@@ -586,6 +587,7 @@ Recent decisions affecting current work:
- [Phase 14.2.1]: Task 2 locked grzyby-submodules: proof host is sm-grzybyfunkcjonalne-app with plugins/golem15/user and plugins/golem15/translate; host go.work replace points at ../summercms.go.
- [Phase 14.2.1]: 14.2.1-04 security review was executor-self-performed (no gsd-security-auditor in this Cursor session); every cited TestName was re-run. Full cabana `-race` needs `-timeout 30m`. WhereIndex falls back to the host column when no index row matches (PHP transWhere).
- [Phase 14.2.1]: writer-exact: add TranslatedExact to cabana.TranslationWriter; AdminWriter delegates to classes.TranslatedExact
- [Phase 14.2.1]: RelationService.writer stays unexported; relations() Lookup matches crud(); no new HTTP route — WR-02 closes on existing child routes; cabana must not export a plugin-facing writer field
### Pending Todos
@@ -638,6 +640,6 @@ Items acknowledged and carried forward from previous milestone close:
## Session Continuity
Last session: 2026-10-06T13:44:20.876Z
Stopped at: Completed 14.2.1-05-PLAN.md
Last session: 2026-10-06T14:29:32.238Z
Stopped at: Completed 14.2.1-06-PLAN.md
Resume file: None

View File

@@ -0,0 +1,227 @@
---
phase: 14.2.1-translate-plugin
plan: 06
subsystem: i18n
tags: [translate, cabana, mltext, mlmarkdown, fillChild, RelationService, WR-02, hydrateMLRecord]
requires:
- phase: 14.2.1-05
provides: "hydrateMLRecord, TranslatedExact, FORM_ENABLED_LOCALES, TestMLHydration"
provides:
- "RelationService.writer Lookup matching CRUDService"
- "CreateChild/UpdateChild liftMLValues before fillChild and applyMLTranslations after PK"
- "ShowChild/CreateChild/UpdateChild hydrateMLRecord on child records"
- "TestRelationChildMLNestedSave plus phase gate FRAMEWORK_REQUIRE/HIGH_THREATS T-14.2.1-19..23"
affects: [15-journal-plugin]
actuals:
tokens: 9023
tasks: 3
commits: 3
plan_head_before: f4bea33faf55b6f52faa021ccb51592bcafd20fb
plan_head_after: ef0301631448e7e287c4f68ea3f16eb7ae2004c1
plugin_repo_head_after: b3e0e26069af6a1c05cccdf2aae045fec6d0346d
host_repo_head_after: 1860ad68c5d1de1c077c8accd17bba0cd94e40a9
tech-stack:
added: []
patterns:
- "Relation-child create/update lift nested ML maps before fillChild, apply after child PK, then hydrate like CRUDService.save"
- "RelationService.writer is unexported Lookup[TranslationWriter]; cabana never imports sm-translate-plugin"
key-files:
created:
- modules/cabana/relation_child_ml_test.go
modified:
- modules/cabana/relation.go
- modules/cabana/relation_child.go
- modules/cabana/http.go
- modules/cabana/ml_smoke_test.go
- modules/cabana/README.md
- docs/backend/forms.md
- admin/tests/form/MLFields.test.ts
- admin/tests/form/MarkdownField.test.ts
- scripts/check-phase14.2.1.sh
- .planning/phases/14.2.1-translate-plugin/14.2.1-SECURITY-REVIEW.md
key-decisions:
- "RelationService.writer stays unexported; relations() Lookup matches crud(); no new HTTP route"
- "CreateChild/UpdateChild call liftMLValues on cr.child before fillChild and applyMLTranslations after PK; ShowChild hydrates with op update"
patterns-established:
- "Child records reuse CRUD ML helpers (liftMLValues, applyMLTranslations, hydrateMLRecord) inside the existing child transaction"
- "Host gitlink must implement cabana.TranslationWriter including TranslatedExact; plugin go.mod must not carry a sibling-relative sm-user-plugin replace"
requirements-completed: [D-06, D-17]
coverage:
- id: D1
description: "CreateChild lifts nested mltext maps before fillChild, writes default locale on the host column and Polish through TranslationWriter after PK, hydrates the create response, and rejects undeclared locale de with 422 and no row"
requirement: D-17
verification:
- kind: unit
ref: "modules/cabana#TestRelationChildMLNestedSave"
status: pass
human_judgment: false
- id: D2
description: "UpdateChild persists nested ML maps the same way as CreateChild; ShowChild returns hydrated locale maps for declared ML fields"
requirement: D-06
verification:
- kind: unit
ref: "modules/cabana#TestRelationChildMLNestedSave"
status: pass
- kind: other
ref: "go test ./cmd/summer -run TestDocsTree && go run ./cmd/summer docs:build --check"
status: pass
human_judgment: false
- id: D3
description: "Phase gate requires TestMLHydration and TestRelationChildMLNestedSave; HIGH_THREATS include T-14.2.1-19,22,23; ALL_THREATS also 20,21; SPA sends empty pl and one selector per ML field"
requirement: D-06
verification:
- kind: unit
ref: "modules/cabana#TestMLHydration"
status: pass
- kind: unit
ref: "modules/cabana#TestMLNestedSave"
status: pass
- kind: unit
ref: "modules/cabana#TestRelationChildMLNestedSave"
status: pass
- kind: automated_ui
ref: "admin/tests/form/MLFields.test.ts"
status: pass
- kind: other
ref: "bash scripts/check-phase14.2.1.sh --all"
status: pass
human_judgment: false
- id: D4
description: "Administrator UAT of Locales plus a Journal-shaped mltext form (one selector per ML field, synchronized switch, save/reload both locales)"
verification: []
human_judgment: true
rationale: "Plan-level human-check is harvested at phase verification, not mid-flight"
duration: 41min
completed: 2026-10-06
status: complete
---
# Phase 14.2.1 Plan 06: Lift ML maps on relation-child saves Summary
**Relation-child create/update/show persist and hydrate nested locale maps the same way host CRUD does, closing WR-02**
## Performance
- **Duration:** 41 min
- **Started:** 2026-10-06T13:48:28Z
- **Completed:** 2026-10-06T14:29:04Z
- **Tasks:** 3
- **Files modified:** 15
## Accomplishments
- `RelationService.writer` is the same optional `TranslationWriter` Lookup `crud()` uses. `relations()` assigns it; no new HTTP route.
- `CreateChild` / `UpdateChild` call `liftMLValues` on `cr.child` before `fillChild`, `applyMLTranslations` after the child has a PK, then `hydrateMLRecord` after `projectFullRecord`. Undeclared locale `de` is 422 and inserts no row.
- `ShowChild` hydrates declared ML fields after `projectFullRecord` on `cr.childForm()`. Writer is unexported; cabana never imports sm-translate-plugin.
- `TestRelationChildMLNestedSave` covers create, update, show, and `de` 422. Phase gate `FRAMEWORK_REQUIRE` includes `TestMLHydration` and `TestRelationChildMLNestedSave`; `T-14.2.1-19..23` are mapped. `bash scripts/check-phase14.2.1.sh --all` printed `Phase 14.2.1 gate passed`.
## Task Commits
Each task was committed atomically:
1. **Task 1: Lift one nested mltext map through CreateChild** — `88a3a88` (feat) summercms.go
2. **Task 2: Mirror lift/apply/hydrate on UpdateChild and ShowChild** — `4e37d87` (feat) summercms.go
3. **Task 3: Named unit/Vitest/cabana tests and the phase gate** — `ef03016` (test) summercms.go
Sibling repos (Rule 3, not in the plan file list):
- `b535b2a` (test) sm-translate-plugin — expect hydrated ML maps on fixture create
- `b3e0e26` (fix) sm-translate-plugin — keep user-plugin replace out of submodule go.mod
- `1860ad6` (fix) sm-grzybyfunkcjonalne-app — point translate gitlink at TranslatedExact adapter
**Plan metadata:** this SUMMARY commit
Nothing was pushed. WR-01/WR-03, new migrations, new HTTP routes, and npm pins were not touched. Plan 05 CR-01 hydration was consumed, not redone.
## Files Created/Modified
- `modules/cabana/relation.go` — unexported `writer TranslationWriter`
- `modules/cabana/http.go` — `relations()` Lookup `[TranslationWriter]` matching `crud()`
- `modules/cabana/relation_child.go` — lift/apply/hydrate on CreateChild, UpdateChild, ShowChild
- `modules/cabana/relation_child_ml_test.go` — `TestRelationChildMLNestedSave` (create, update, show, de 422)
- `modules/cabana/ml_smoke_test.go` — `recordingWriter` PK guard used by the child test
- `modules/cabana/README.md`, `docs/backend/forms.md` — child records share the CRUD ML path
- `admin/tests/form/MLFields.test.ts` — empty-pl payload and one selector per ML field
- `admin/tests/form/MarkdownField.test.ts` — provide `FORM_ENABLED_LOCALES` for mlmarkdown composition
- `scripts/check-phase14.2.1.sh` — `TestMLHydration`, `TestRelationChildMLNestedSave`, threats 19–23
- `.planning/phases/14.2.1-translate-plugin/14.2.1-SECURITY-REVIEW.md` — `T-14.2.1-19`..`23`, `threats_total: 24`
- `../sm-translate-plugin/integration_test.go` — decode hydrated title/slug/body maps
- `../sm-translate-plugin/go.mod`, `go.work` — user-plugin replace lives in plugin go.work
- `../sm-grzybyfunkcjonalne-app` gitlink `plugins/golem15/translate` → `b3e0e26`
## Decisions Made
- `RelationService.writer` stays unexported. Document behaviour on `TranslationWriter` / child records, not a new exported type.
- Child Show hydrates with op `"update"` like CRUD Show.
- Plugin sibling-relative `sm-user-plugin` replace belongs in plugin `go.work`, not `go.mod`, so the proof-host workspace `use ./plugins/golem15/user` does not conflict.
## Deviations from Plan
### Auto-fixed Issues
**1. [Rule 3 - Blocking] Plugin TestTranslateEndToEnd after Plan 05 hydration**
- **Found during:** Task 3 verify
- **Issue:** Fixture create now returns locale maps; the plugin test still decoded `title`/`slug`/`body` as strings.
- **Fix:** Decode those fields as `map[string]string`.
- **Files modified:** `../sm-translate-plugin/integration_test.go`
- **Verification:** `TestTranslateEndToEnd` PASS
- **Committed in:** `b535b2a`
**2. [Rule 3 - Blocking] Host compile missing TranslatedExact plus go.mod replace conflict**
- **Found during:** Task 3 `go -C ../sm-grzybyfunkcjonalne-app vet`
- **Issue:** Host gitlink was Plan 03 `a3553b9` (no `TranslatedExact`). Checking out later plugin SHAs pulled a sibling-relative `sm-user-plugin` replace that conflicted with host `use ./plugins/golem15/user`.
- **Fix:** Move that replace into plugin `go.work`; point the host gitlink at `b3e0e26`.
- **Files modified:** `../sm-translate-plugin/go.mod`, `../sm-translate-plugin/go.work`, host gitlink
- **Verification:** `TestBootUserTranslate` PASS; gate `--host` PASS
- **Committed in:** `b3e0e26`, `1860ad6`
**3. [Rule 3 - Blocking] MarkdownField mlmarkdown composition after FORM_ENABLED_LOCALES**
- **Found during:** Task 3 `bash scripts/check-phase14.2.1.sh --all` (`--admin`)
- **Issue:** `MarkdownField.test.ts` mounted `MLMarkdownField` without `FORM_ENABLED_LOCALES`, so locale `pl` never activated and preview stayed English `# Hi`.
- **Fix:** Provide `FORM_ENABLED_LOCALES` `['en','pl']` on that mount.
- **Files modified:** `admin/tests/form/MarkdownField.test.ts`
- **Verification:** admin Vitest 59/59 PASS; `--all` printed `Phase 14.2.1 gate passed`
- **Committed in:** `ef03016`
**4. [Rule 3 - Blocking] Vitest `--run` path vs include glob**
- **Found during:** Task 3 verify
- **Issue:** Plan path `admin/tests/form/MLFields.test.ts` finds no files; include is `tests/**` under `admin/`.
- **Fix:** Ran `tests/form/MLFields.test.ts` (same as Plan 05).
- **Files modified:** none (verify command only)
- **Verification:** 11/11 PASS
- **Committed in:** n/a
---
**Total deviations:** 4 auto-fixed (all Rule 3 blocking tests)
**Impact on plan:** Required for the last-plan gate. No WR-01/WR-03. No new migration, HTTP route, or npm pin (T-14.2.1-SC). Threat IDs 01–18 were not reused.
## Issues Encountered
- `mlJournal` needed `Entries []mlEntry \`gorm:"-"\`` so the hasMany relation compiled (Task 1, in `88a3a88`).
- `requirements.mark-complete D-06 D-17` is expected `not_found`: those IDs are CONTEXT.md decisions, not REQUIREMENTS.md rows. They remain on this SUMMARY's `requirements-completed`.
- Unrelated dirty `.planning/` files from other sessions were left unstaged.
- Plan-level `<human-check>` is harvested at phase verification, not mid-flight.
## User Setup Required
None - no external service configuration required.
## Next Phase Readiness
Phase 14.2.1 production plans are complete: CR-01 and WR-02 are closed with named tests and `Phase 14.2.1 gate passed`. Ready for phase verification / UAT of the plan-level human-check. Journal (Phase 15) can keep translatable fields including relation-child ML writes.
---
*Phase: 14.2.1-translate-plugin*
*Completed: 2026-10-06*
## Self-Check: PASSED