docs(14.2.1): re-verify after CR-01 and WR-02 gap closure
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
302
.planning/phases/14.2.1-translate-plugin/14.2.1-VERIFICATION.md
Normal file
302
.planning/phases/14.2.1-translate-plugin/14.2.1-VERIFICATION.md
Normal file
@@ -0,0 +1,302 @@
|
|||||||
|
---
|
||||||
|
phase: 14.2.1-translate-plugin
|
||||||
|
verified: 2026-10-06T14:40:00Z
|
||||||
|
status: human_needed
|
||||||
|
score: 16/16 must-haves verified
|
||||||
|
covered_files:
|
||||||
|
- .planning/phases/14.2.1-translate-plugin/14.2.1-01-PLAN.md
|
||||||
|
- .planning/phases/14.2.1-translate-plugin/14.2.1-01-SUMMARY.md
|
||||||
|
- .planning/phases/14.2.1-translate-plugin/14.2.1-02-PLAN.md
|
||||||
|
- .planning/phases/14.2.1-translate-plugin/14.2.1-02-SUMMARY.md
|
||||||
|
- .planning/phases/14.2.1-translate-plugin/14.2.1-03-PLAN.md
|
||||||
|
- .planning/phases/14.2.1-translate-plugin/14.2.1-03-SUMMARY.md
|
||||||
|
- .planning/phases/14.2.1-translate-plugin/14.2.1-04-PLAN.md
|
||||||
|
- .planning/phases/14.2.1-translate-plugin/14.2.1-04-SUMMARY.md
|
||||||
|
- .planning/phases/14.2.1-translate-plugin/14.2.1-05-PLAN.md
|
||||||
|
- .planning/phases/14.2.1-translate-plugin/14.2.1-05-SUMMARY.md
|
||||||
|
- .planning/phases/14.2.1-translate-plugin/14.2.1-06-PLAN.md
|
||||||
|
- .planning/phases/14.2.1-translate-plugin/14.2.1-06-SUMMARY.md
|
||||||
|
- admin/src/api/schema.d.ts
|
||||||
|
- admin/src/components/form/fields/MLMarkdownField.vue
|
||||||
|
- admin/src/components/form/fields/MLTextField.vue
|
||||||
|
- admin/src/components/form/formContext.ts
|
||||||
|
- admin/src/components/form/formState.ts
|
||||||
|
- admin/src/components/form/mlLocale.ts
|
||||||
|
- admin/src/components/form/registry.ts
|
||||||
|
- admin/src/components/relation/RelationChildModal.vue
|
||||||
|
- admin/src/views/FormView.vue
|
||||||
|
- admin/tests/form/MLFields.test.ts
|
||||||
|
- admin/tests/form/formState.test.ts
|
||||||
|
- docs/backend/admin-controllers.md
|
||||||
|
- docs/backend/forms.md
|
||||||
|
- modules/cabana/README.md
|
||||||
|
- modules/cabana/crud.go
|
||||||
|
- modules/cabana/field_markdown.go
|
||||||
|
- modules/cabana/field_ml.go
|
||||||
|
- modules/cabana/form_schema.go
|
||||||
|
- modules/cabana/http.go
|
||||||
|
- modules/cabana/ml_smoke_test.go
|
||||||
|
- modules/cabana/ml_test.go
|
||||||
|
- modules/cabana/openapi_conformance_test.go
|
||||||
|
- modules/cabana/relation.go
|
||||||
|
- modules/cabana/relation_child.go
|
||||||
|
- modules/cabana/relation_child_ml_test.go
|
||||||
|
- modules/cabana/schema_types.go
|
||||||
|
- modules/surf/locale_from_principal.go
|
||||||
|
- modules/surf/locale_resolver.go
|
||||||
|
- modules/surf/router.go
|
||||||
|
- scripts/check-phase14.2.1.sh
|
||||||
|
covered_digest: "v2:sha256:e8c9c72cd5252f44d6193fa658ea95663432905c4a061fd228887f46a07c4402"
|
||||||
|
covered_files_note: "verification.fingerprint covers only paths under the summercms.go root. Sibling implementation read this pass: sm-translate-plugin b3e0e26 (plugin.go, Locale/Attribute/Index models, five golem15_translate_* migrations, Translator, Translatable, TranslatedExact, Locales admin, AdminWriter, integration/admin/migration tests); sm-grzybyfunkcjonalne-app 1860ad6 (summer.yaml, plugins.gen.go, go.work, gitlinks, boot_test.go). Host translate gitlink is b3e0e26. PHP pin /media/nvme/dev/golem15/fonoteka/plugins/golem15/translate HEAD 725d547ec839f02b5fdc0f0a6faaed601a414d50, clean tree, not edited."
|
||||||
|
behavior_unverified: 0
|
||||||
|
overrides_applied: 0
|
||||||
|
re_verification:
|
||||||
|
previous_status: gaps_found
|
||||||
|
previous_score: 14/16
|
||||||
|
gaps_closed:
|
||||||
|
- "Cabana markdown/mltext/mlmarkdown compose; nested locale writes are not dropped"
|
||||||
|
- "The SPA exposes one locale selector per ML field, switches all ML controls together, supports copy-from-locale, and sends every locale as Record<string,string>"
|
||||||
|
gaps_remaining: []
|
||||||
|
regressions: []
|
||||||
|
advisory: []
|
||||||
|
human_verification:
|
||||||
|
- test: "Boot the proof host and open Locales in the admin SPA"
|
||||||
|
expected: "Sign in as an administrator holding golem15.translate.manage_locales; English then Polski appear in sort_order; name/enabled can be edited; a user without the permission cannot open the controller"
|
||||||
|
why_human: "Needs a running host, admin login, and visual confirmation of the Locales screen. Harvested from 14.2.1-04-PLAN.md and 14.2.1-06-PLAN.md human-checks. Automated tests cover HTTP 403/list order, not the SPA chrome."
|
||||||
|
- test: "With the proof host and admin SPA, open a Journal-shaped form with mltext when one is available"
|
||||||
|
expected: "Create lists en and pl (not a single English box); one locale selector per ML field; switching one selector switches the others; save/reload still shows both locales"
|
||||||
|
why_human: "Harvested from 14.2.1-06-PLAN.md. Vitest proves seed/selector/broadcast/copy-from against provided ['en','pl'], not a running SPA against schema meta from the live writer. The proof host has no production mltext YAML (only test-harness fields); do not invent a pass. Relation-child ML UAT can wait for Phase 15 if this host has no child ML form."
|
||||||
|
---
|
||||||
|
|
||||||
|
# Phase 14.2.1: Translate plugin Verification Report
|
||||||
|
|
||||||
|
**Phase Goal:** Golem15.Translate is ported to Go as `sm-translate-plugin` so Journal (Phase 15) can keep translatable fields. Lean core only: Locale model and Locales admin, Translatable API, cabana `mltext`/`mlmarkdown`, and PHP Translator locale resolution (URL prefix / session / cookie / default).
|
||||||
|
**Verified:** 2026-10-06T14:40:00Z
|
||||||
|
**Status:** human_needed
|
||||||
|
**Re-verification:** Yes — after gap closure (plans 05 CR-01 and 06 WR-02)
|
||||||
|
|
||||||
|
**MVP note:** ROADMAP does not mark this phase `mode: mvp`. User Flow Coverage is derived from ROADMAP success criteria and CONTEXT D-17.
|
||||||
|
|
||||||
|
Prior report (2026-10-06T12:48:00Z) was `gaps_found` 14/16. CR-01 and WR-02 are closed in source. All 16 must-have truths are now VERIFIED. Status is `human_needed` because harvested SPA UAT remains; it is not a pass.
|
||||||
|
|
||||||
|
## User Flow Coverage
|
||||||
|
|
||||||
|
| Step | Expected | Evidence | Status |
|
||||||
|
|------|----------|----------|--------|
|
||||||
|
| Proof host boots user+translate | `party.Activate` loads `golem15.user` then `golem15.translate`; Locales controller and `manage_locales` are registered; submodules are gitlinks | `sm-grzybyfunkcjonalne-app/plugins.gen.go`, `summer.yaml`, gitlink `b3e0e26`; `TestBootUserTranslate` exists | ✓ |
|
||||||
|
| Operators manage locales | YAML CRUD gated by exactly `golem15.translate.manage_locales`; seed en then pl; no Messages admin | `controllers/locales.go` `RequiredPermissions`; production Permissions() is only `manage_locales` | ✓ API; SPA list/edit is human |
|
||||||
|
| Fixture saves and reads en+pl through Translatable / WithLocale | Default on host columns; pl in `golem15_translate_attributes`; missing pl falls back | `classes/translatable.go`; `Translated` still does D-11; `TranslatedExact` does not | ✓ API |
|
||||||
|
| Journal-shaped admin form is one screen with a locale switch | Enabled locales on create/load/save; nested `{en,pl}` posted and rehydrated | `FormMeta.EnabledLocales`; `hydrateMLRecord` + `TranslatedExact`; SPA `FORM_ENABLED_LOCALES`; `TestMLHydration` / Vitest create+GET; live SPA UAT still human | ✓ code; ⏳ SPA UAT |
|
||||||
|
|
||||||
|
## Goal Achievement
|
||||||
|
|
||||||
|
### Observable Truths
|
||||||
|
|
||||||
|
| # | Truth | Status | Evidence |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| 1 | Plugin repo exists with `golem15_translate_*` schema (locales, attributes, indexes, empty messages table), Locale model, en/pl seed, and context-safe Translator | ✓ VERIFIED | Module `git.golem15.com/golem15/sm-translate-plugin` HEAD `b3e0e26`, ID `golem15.translate`. Five gormigrate files create `golem15_translate_locales\|attributes\|indexes\|messages`. `Locale.TableName()` is `golem15_translate_locales`. `--php` / `--layout` / `--forbidden` PASS this pass. `Translator.Locale` reads `towel.Locale(ctx)` only. |
|
||||||
|
| 2 | Translatable API (`Translatable()`, `WithLocale`, get/set, default-locale fallback) and permissioned Locales admin work; a fixture model saves and reads en+pl | ✓ VERIFIED | `classes.Translatable` plus `Translated` / `SetTranslated` / `WithLocale`. Locales permission is exactly `golem15.translate.manage_locales`. `Translated` still applies D-11; admin hydration uses `TranslatedExact`. |
|
||||||
|
| 3 | Cabana `markdown` / `mltext` / `mlmarkdown` compose | ✓ VERIFIED | `formFieldTypes` includes all three (`form_schema.go:29`). `MLMarkdownField.vue` renders `MarkdownField`. `TestMLFieldTypes` PASS this pass (`go test ./modules/cabana -count=1 -run 'TestMLFieldTypes$'`). Registry tests register the three types. |
|
||||||
|
| 4 | Nested locale writes are not dropped | ✓ VERIFIED | CR-01/WR-02 closed. Host `CRUDService.save` still `liftMLValues` then `applyMLTranslations` then `hydrateMLRecord` (`crud.go:600`, `:688`, `:709`). `CreateChild`/`UpdateChild` lift on `in.Body` **before** `fillChild` (`relation_child.go:168-172`, `:330-334`) and apply after PK (`:183`, `:345`). `ShowChild` hydrates (`:296`). `TestMLNestedSave` PASS; `TestMLHydration` PASS (create/show `{en,pl}`; english-only `pl: ""`); `TestRelationChildMLNestedSave` PASS (create/update/show + `de` 422 with no insert). SPA create seeds `{[code]: ""}`; `mergeMLValue` keeps siblings on a GET string. |
|
||||||
|
| 5 | Docs, OpenAPI, TS types and `boardwalk` `dist/` update in the same change | ✓ VERIFIED | `docs/backend/forms.md`, `docs/backend/admin-controllers.md`, `modules/cabana/README.md` document `EnabledLocales`, `TranslatedExact`, `hydrateMLRecord`, and child lift. `schema.d.ts` has `enabledLocales?: string[]`. `boardwalk/dist/assets/index-B08bxLq5.js` contains `mltext`/`mlmarkdown`. Gate `--forbidden` found no consuming-application names. |
|
||||||
|
| 6 | Proof host `sm-grzybyfunkcjonalne-app` boots with user+translate; unit tests are the last plan | ✓ VERIFIED | Host HEAD `1860ad6`. `summer.yaml` lists user then translate; gitlink `plugins/golem15/translate` → `b3e0e26`. Plan 06 is the dedicated named-test/gate close of the gap round; plan 04 remains the original last-of-phase test plan. `--layout` PASS this pass. |
|
||||||
|
| 7 | D-01/D-02/D-03/D-04: implementation is derived only from the read-only PHP tree at SHA `725d547ec839f02b5fdc0f0a6faaed601a414d50`; no PHP file changes | ✓ VERIFIED | `bash scripts/check-phase14.2.1.sh --php` this pass: `phase14.2.1 php passed (725d547…)`. Porcelain empty. |
|
||||||
|
| 8 | D-07/D-12: resolver selects URL prefix, valid user preferred_locale, remembered `golem15.translate.locale`, cookie-gated Accept-Language, then default; surf stores only a validated code on context | ✓ VERIFIED | `Translator.Resolve` order still URL → preferred → remembered → AL (unless manual flag) → default (`translator.go:75-103`). Surf `router.go:712-714` writes `towel.WithLocale` from `resolver.Resolve`. |
|
||||||
|
| 9 | KERN-07: no package-level mutable current locale; `Translator.Locale(ctx)` and `towel.WithLocale` carry request state | ✓ VERIFIED | No package `currentLocale`. `Translator.Locale` reads context then `defaultCode`. `Rewrite` clones the request. |
|
||||||
|
| 10 | D-15/D-16: module is `git.golem15.com/golem15/sm-translate-plugin`, package `translate`, plugin ID `golem15.translate`, sibling checkout | ✓ VERIFIED | `Plugin.ID()`; remote `git@git.golem15.com:golem15/sm-translate-plugin.git`; path `/media/nvme/dev/golem15/summercms.io/summercms/sm-translate-plugin`. Host submodule `plugins/golem15/translate` mode `160000`. |
|
||||||
|
| 11 | D-10: default-locale values remain in host columns; each non-default locale is one JSON object row in `golem15_translate_attributes`; indexed values are mirrored to `golem15_translate_indexes` | ✓ VERIFIED | `SetTranslated` still writes default via host `Update`; non-default upserts one attribute JSON object. `hydrateMLRecord` does not change that write path. |
|
||||||
|
| 12 | D-05: Locales is ordinary cabana CRUD, permission-gated by exactly `golem15.translate.manage_locales`; no Messages controller, permission, or navigation | ✓ VERIFIED | `RequiredPermissions` returns only `PermissionManageLocales`. `Permissions()` is only `manage_locales`. `--forbidden` PASS (no production `manage_messages`). |
|
||||||
|
| 13 | Locale form writes only code/name/is_enabled; `is_default` and `sort_order` cannot be mass-assigned; permissioned make-default preserves disabled/default lifecycle guards | ✓ VERIFIED | `Fillable` is `code,name,is_enabled`. WR-01 concurrent two-default race remains untested (advisory, not a gap). |
|
||||||
|
| 14 | The SPA exposes one locale selector per ML field, switches all ML controls together, supports copy-from-locale, and sends every locale as `Record<string,string>` | ✓ VERIFIED | CR-01 closed. `MLTextField`/`MLMarkdownField` inject `FORM_ENABLED_LOCALES` and list those codes (`locales` computed is no longer `Object.keys` / `['en']`). `FormView` provides `schemaEnabledLocales(schema.meta)`; `RelationChildModal` re-provides the parent inject. Create `initialValues(fields, enabledLocales)` seeds `{[code]: ""}`. `adopt` uses `mergeMLValue`. `editablePayload` sends `localeRecord`. Vitest this pass: `npx vitest run tests/form/MLFields.test.ts tests/form/formState.test.ts` — 42 passed, including create seed listing en+pl, GET-string merge keeping `pl`, one selector per field, broadcast switch, copy-from, empty-pl payload. Live SPA UAT is still human (below). |
|
||||||
|
| 15 | Markdown preview uses goldmark without unsafe HTML and cannot execute translated raw HTML/script/event-handler/javascript content | ✓ VERIFIED | `RenderMarkdown` uses `goldmark.New()`; no `html.WithUnsafe`. SPA preview is text interpolation, no `v-html=`. |
|
||||||
|
| 16 | Nested locale maps are lifted before `ProjectWritableFields` drops maps; default locale fills the host field and non-default locales reach the translate writer inside the host save transaction | ✓ VERIFIED | Host path unchanged (`crud.go:600` then `:688` inside `s.transaction`). Child path now mirrors it on `tx` (`relation_child.go`). `TestMLNestedSave` and `TestRelationChildMLNestedSave` both assert unlifted maps empty at projection, English on host, pl via writer, `de` rejected. |
|
||||||
|
|
||||||
|
**Score:** 16/16 truths verified (0 present, behavior-unverified)
|
||||||
|
|
||||||
|
### Advisory (New Scope, Unevidenced)
|
||||||
|
|
||||||
|
None. WR-01 (makeDefault race), WR-03 (enabled `backend` prefix), and IN-02/IN-03/IN-04 were out of the gap-closure contract, were not in the prior `gaps:` list, and were not re-opened. Evidence gate: not blocking.
|
||||||
|
|
||||||
|
### Required Artifacts
|
||||||
|
|
||||||
|
gsd-tools `verify.artifacts` still does not emit per-file JSON for sibling `../sm-translate-plugin/...` paths. Manual three-level check:
|
||||||
|
|
||||||
|
| Artifact | Expected | Status | Details |
|
||||||
|
| -------- | -------- | ------ | ------- |
|
||||||
|
| `../sm-translate-plugin/plugin.go` | Compiled plugin, Resolver + TranslationWriter publish | ✓ EXISTS + SUBSTANTIVE + WIRED | Boot publishes `surf.LocaleResolver` and `cabana.TranslationWriter`. |
|
||||||
|
| `../sm-translate-plugin/updates/202610060001_create_golem15_translate_locales.go` | Squashed Locale schema | ✓ EXISTS + SUBSTANTIVE | `golem15_translate_locales`. |
|
||||||
|
| `../sm-translate-plugin/updates/202610060004_create_golem15_translate_messages.go` | Empty compatibility Messages table | ✓ EXISTS + SUBSTANTIVE | Created; no admin. |
|
||||||
|
| `../sm-translate-plugin/classes/translator.go` | Context-only Translator | ✓ EXISTS + SUBSTANTIVE + WIRED | Published from Boot; surf stores result on context. |
|
||||||
|
| `../sm-translate-plugin/classes/translatable.go` | Translatable contracts | ✓ EXISTS + SUBSTANTIVE + WIRED | `Translated` (D-11) and `TranslatedExact` (no fallback). |
|
||||||
|
| `../sm-translate-plugin/classes/admin_writer.go` | Plugin adapter including TranslatedExact | ✓ EXISTS + SUBSTANTIVE + WIRED | `AdminWriter.TranslatedExact` delegates to `classes.TranslatedExact`; `var _ cabana.TranslationWriter`. |
|
||||||
|
| `../sm-translate-plugin/controllers/locales.go` | Permissioned Locales admin | ✓ EXISTS + SUBSTANTIVE + WIRED | `RequiredPermissions`; registered via `admin.go`. |
|
||||||
|
| `modules/surf/locale_resolver.go` | Optional resolver contract | ✓ EXISTS + SUBSTANTIVE + WIRED | Used in `router.go`. |
|
||||||
|
| `modules/cabana/schema_types.go` | `FormMeta.EnabledLocales` | ✓ EXISTS + SUBSTANTIVE + WIRED | `json:"enabledLocales,omitempty"`. |
|
||||||
|
| `modules/cabana/field_ml.go` | Lift + hydrate + TranslationWriter | ✓ EXISTS + SUBSTANTIVE + WIRED | `hydrateMLRecord` writes `""` when `TranslatedExact` `ok` is false. Wired from CRUD Show/save and relation-child create/update/show. Not used from list projection. |
|
||||||
|
| `modules/cabana/relation.go` | `RelationService.writer` | ✓ EXISTS + SUBSTANTIVE + WIRED | Same unexported Lookup as `CRUDService`. |
|
||||||
|
| `modules/cabana/relation_child.go` | lift before fillChild, apply after PK, hydrate | ✓ EXISTS + SUBSTANTIVE + WIRED | WR-02 closed. |
|
||||||
|
| `modules/cabana/relation_child_ml_test.go` | Named child nested-ML proof | ✓ EXISTS + SUBSTANTIVE | `TestRelationChildMLNestedSave` PASS this pass. |
|
||||||
|
| `admin/src/components/form/formContext.ts` | `FORM_ENABLED_LOCALES` | ✓ EXISTS + SUBSTANTIVE + WIRED | Injected by `FormView`; re-provided by `RelationChildModal`. |
|
||||||
|
| `admin/src/components/form/fields/MLMarkdownField.vue` | Locale-aware markdown editor | ✓ EXISTS + SUBSTANTIVE + WIRED | Options from schema inject, not value keys. |
|
||||||
|
| `admin/src/components/form/fields/MLTextField.vue` | Locale-aware text editor | ✓ EXISTS + SUBSTANTIVE + WIRED | Same. |
|
||||||
|
| `admin/src/views/FormView.vue` | adopt merges hydrated maps | ✓ EXISTS + SUBSTANTIVE + WIRED | `mergeMLValue`; create seeds via `initialValues`. |
|
||||||
|
| `docs/backend/forms.md` | Field-type docs | ✓ EXISTS + SUBSTANTIVE | Documents EnabledLocales, exact hydration, child lift. |
|
||||||
|
| `../sm-grzybyfunkcjonalne-app/summer.yaml` | user+translate plugin list | ✓ EXISTS + SUBSTANTIVE + WIRED | Generates `plugins.gen.go`. |
|
||||||
|
| `scripts/check-phase14.2.1.sh` | Fail-closed phase gate | ✓ EXISTS + SUBSTANTIVE | `FRAMEWORK_REQUIRE` includes `TestMLHydration` and `TestRelationChildMLNestedSave`. Echoes `Phase 14.2.1 gate passed`. Cheap stages PASS this pass. |
|
||||||
|
| `.planning/phases/14.2.1-translate-plugin/14.2.1-SECURITY-REVIEW.md` | ASVS L1 threat evidence | ✓ EXISTS + SUBSTANTIVE | T-14.2.1-19/22/23 mapped to named tests. |
|
||||||
|
|
||||||
|
**Artifacts:** fully verified at exists + substantive + wired. Prior hollow SPA locale options are gone.
|
||||||
|
|
||||||
|
### Key Link Verification
|
||||||
|
|
||||||
|
| From | To | Via | Status | Details |
|
||||||
|
| ---- | --- | --- | ------ | ------- |
|
||||||
|
| `plugin.go` Boot | `modules/surf/locale_resolver.go` | `Publish[surf.LocaleResolver]` | ✓ WIRED | Translator implements the interface. |
|
||||||
|
| `modules/surf/router.go` | `modules/towel` | `towel.WithLocale(resolver.Resolve(...))` | ✓ WIRED | Lines 712-714. |
|
||||||
|
| `translator.go` | `models/locale.go` | `is_enabled` query in `enabledCodes` | ✓ WIRED | Candidates must match enabled rows. |
|
||||||
|
| `translatable.go` | `golem15_translate_attributes` | `SetTranslated` upsert JSON | ✓ WIRED | `attribute_data`. |
|
||||||
|
| `translatable.go` | `golem15_translate_indexes` | indexed upsert | ✓ WIRED | `TranslatableIndexes`. |
|
||||||
|
| `controllers/locales.go` | `models/locale.go` | cabana CRUD + hooks | ✓ WIRED | `RequiredPermissions`. |
|
||||||
|
| `modules/cabana/http.go` | `modules/cabana/schema_types.go` | `enabledContentLocales` → `FormMeta.EnabledLocales` | ✓ WIRED | `formSchema` copies codes onto `view.Meta` and envelope; `relationSchema` envelope meta; list schemas do not call the helper. |
|
||||||
|
| `modules/cabana/crud.go` | `modules/cabana/field_ml.go` | `liftMLValues` / `hydrateMLRecord` | ✓ WIRED | ShowRecord and save. |
|
||||||
|
| `modules/cabana/http.go` | `modules/cabana/relation.go` | `relations()` `Lookup[TranslationWriter]` | ✓ WIRED | Matches `crud()`. |
|
||||||
|
| `modules/cabana/relation_child.go` | `modules/cabana/field_ml.go` | `liftMLValues` then `applyMLTranslations` then `hydrateMLRecord` | ✓ WIRED | WR-02. |
|
||||||
|
| `classes/admin_writer.go` | `classes/translatable.go` | `TranslatedExact` / `SetTranslated` | ✓ WIRED | Exact path never calls `Translated` (D-11). |
|
||||||
|
| `admin/src/views/FormView.vue` | ML field components | `FORM_ENABLED_LOCALES` | ✓ WIRED | Inject drives selector options. |
|
||||||
|
| `FormView.adopt` / `RelationChildModal.adopt` | nested ML maps | `mergeMLValue` | ✓ WIRED | Map overlays seed; host string becomes first enabled code and keeps siblings. |
|
||||||
|
| `summer.yaml` | `plugins.gen.go` | `summer build` blank imports | ✓ WIRED | Both submodule modules. |
|
||||||
|
|
||||||
|
**Wiring:** 14/14 connections verified (prior 5 NOT WIRED links are now WIRED).
|
||||||
|
|
||||||
|
### Data-Flow Trace (Level 4)
|
||||||
|
|
||||||
|
| Artifact | Data Variable | Source | Produces Real Data | Status |
|
||||||
|
| -------- | ------------- | ------ | ------------------ | ------ |
|
||||||
|
| Locales list/form | locale rows | GORM `golem15_translate_locales` via cabana CRUD | Yes | ✓ FLOWING |
|
||||||
|
| Translator.Resolve | request locale | enabled Locale rows + URL/cookie/AL | Yes, validated codes | ✓ FLOWING |
|
||||||
|
| `Translated` / `SetTranslated` | field text | host column or `attribute_data` JSON | Yes | ✓ FLOWING |
|
||||||
|
| Cabana ML save (HTTP) | nested locale map | request body → lift → host scalar + writer | Yes | ✓ FLOWING |
|
||||||
|
| Cabana GET/Show ML field | `data[field]` | `hydrateMLRecord` after `projectFullRecord`: default from host column, others from `TranslatedExact` | Locale map; missing pl is `""` | ✓ FLOWING |
|
||||||
|
| Relation-child create/update/show | child ML field | same lift/apply/hydrate on `tx` | Yes (`TestRelationChildMLNestedSave`) | ✓ FLOWING |
|
||||||
|
| Form schema meta | `enabledLocales` | `TranslationWriter.EnabledLocales` | Enabled codes when writer published | ✓ FLOWING |
|
||||||
|
| SPA ML locale `<select>` | `locales` | `FORM_ENABLED_LOCALES` from schema meta | Schema codes, not value keys | ✓ FLOWING |
|
||||||
|
| SPA create ML value | `initialValues` | `{[code]: ""}` for every enabled locale | Seeded from schema | ✓ FLOWING |
|
||||||
|
| Markdown preview | preview pane | interpolated source text | Real source; not `RenderMarkdown` HTML | ✓ FLOWING (text) |
|
||||||
|
|
||||||
|
### Behavioral Spot-Checks
|
||||||
|
|
||||||
|
| Behavior | Command | Result | Status |
|
||||||
|
| -------- | ------- | ------ | ------ |
|
||||||
|
| PHP pin SHA + clean tree | `bash scripts/check-phase14.2.1.sh --php` | `phase14.2.1 php passed (725d547…)` | ✓ PASS |
|
||||||
|
| Host/plugin layout | `--layout` | `phase14.2.1 layout passed` | ✓ PASS |
|
||||||
|
| Forbidden Winter names / AutoMigrate / v-html / app names | `--forbidden` | `phase14.2.1 forbidden passed` | ✓ PASS |
|
||||||
|
| Gate detector fail-closed | `--self-test` | `phase14.2.1 self-test passed` | ✓ PASS |
|
||||||
|
| Security review IDs | `--security` | `phase14.2.1 security passed` | ✓ PASS |
|
||||||
|
| Cabana ML types | `go test ./modules/cabana -count=1 -run 'TestMLFieldTypes$'` | PASS 0.086s | ✓ PASS |
|
||||||
|
| Nested host save | `go test ./modules/cabana -count=1 -run 'TestMLNestedSave$'` | PASS 4.371s | ✓ PASS |
|
||||||
|
| Hydration without D-11 | `go test ./modules/cabana -count=1 -run 'TestMLHydration$'` | PASS 4.586s; english-only `pl: ""` | ✓ PASS |
|
||||||
|
| Relation-child nested ML | `go test ./modules/cabana -count=1 -run 'TestRelationChildMLNestedSave$'` | PASS 4.301s | ✓ PASS |
|
||||||
|
| SPA ML create/GET/selector | `npx vitest run tests/form/MLFields.test.ts tests/form/formState.test.ts` | 2 files, 42 tests passed | ✓ PASS |
|
||||||
|
| Full gate `--all` | not re-run (cabana `-race` ~30m) | Script still ends with `Phase 14.2.1 gate passed`; `FRAMEWORK_REQUIRE` includes the two named tests that passed this pass. Plan 06 SUMMARY claimed `--all` printed that line. | ? SKIP |
|
||||||
|
|
||||||
|
### Probe Execution
|
||||||
|
|
||||||
|
No `scripts/*/tests/probe-*.sh`. The phase gate is `scripts/check-phase14.2.1.sh`. Cheap stages PASS this pass (table above). `--plugin` / `--framework` / `--admin` / `--host` / `--all` were not re-executed here; named tests that the gate requires for CR-01/WR-02 passed in this process.
|
||||||
|
|
||||||
|
### Requirements Coverage
|
||||||
|
|
||||||
|
No REQUIREMENTS.md IDs map to this phase (`Requirements: TBD` in ROADMAP; grep of REQUIREMENTS.md for `Phase 14.2.1` is empty). CONTEXT D-01..D-17 are the contract. Plans 01–04 declare D-01..D-17; plans 05–06 cite D-06 and D-17 for gap closure. Every ID is accounted for.
|
||||||
|
|
||||||
|
| Requirement | Source Plan | Description | Status | Evidence |
|
||||||
|
| ----------- | ---------- | ----------- | ------ | -------- |
|
||||||
|
| D-01 | 01, 04 | PHP pin `725d547` | ✓ SATISFIED | `--php` PASS |
|
||||||
|
| D-02 | 01, 04 | Freeze at that SHA | ✓ SATISFIED | Gate compares HEAD to the pin |
|
||||||
|
| D-03 | 01, 04 | Read frozen tree at fonoteka path | ✓ SATISFIED | Path exists, SHA matches |
|
||||||
|
| D-04 | 01, 04 | Do not edit PHP | ✓ SATISFIED | Clean porcelain |
|
||||||
|
| D-05 | 02, 04 | Lean Locale + Locales admin only | ✓ SATISFIED | No Messages controller/permission/nav |
|
||||||
|
| D-06 | 03, 04, 05, 06 | `mltext`/`mlmarkdown`; Journal form stays one screen with a locale switch | ✓ SATISFIED (code) | Field types compile; schema `EnabledLocales`; SPA inject; child lift. Live SPA UAT remains human. |
|
||||||
|
| D-07 | 01, 04 | URL / session / cookie / default, not header-only | ✓ SATISFIED | `Translator.Resolve` order |
|
||||||
|
| D-08 | 01, 02, 04 | Seed en+pl, not de | ✓ SATISFIED | Seed SQL |
|
||||||
|
| D-09 | 02, 03, 04 | `Translatable() []string` | ✓ SATISFIED | Interface + fixture models |
|
||||||
|
| D-10 | 01, 02, 04 | Go tables `golem15_translate_*` | ✓ SATISFIED | Production DDL; `--forbidden` refuses Winter names |
|
||||||
|
| D-11 | 02, 04 | Missing translation falls back to default | ✓ SATISFIED | `Translated` still falls back. Admin GET uses `TranslatedExact` and does **not** apply D-11 (`hydrateMLRecord` writes `""` when `ok` is false; `TestMLHydration` english-only `pl: ""`). |
|
||||||
|
| D-12 | 01, 02, 03, 04 | Min API: WithLocale, get/set, Translator current locale | ✓ SATISFIED | Exported funcs + context Locale |
|
||||||
|
| D-13 | 03, 04 | Host is `sm-grzybyfunkcjonalne-app` with user+translate | ✓ SATISFIED | `plugins.gen.go` |
|
||||||
|
| D-14 | 03, 04 | Local host checkout path | ✓ SATISFIED | Sibling directory exists |
|
||||||
|
| D-15 | 01, 03, 04 | Public Gitea remote + module path | ✓ SATISFIED | `git remote -v` |
|
||||||
|
| D-16 | 01, 03, 04 | Sibling plugin checkout; host submodule + go.work replace | ✓ SATISFIED | gitlink 160000 `b3e0e26` |
|
||||||
|
| D-17 | 02, 03, 04, 05, 06 | App boots; Locales admin works; fixture saves/reads en+pl through ML fields and WithLocale | ✓ SATISFIED (code) | Boot + API fixture + permissioned Locales HTTP + hydrated admin maps + relation-child nested save. SPA one-screen UAT is human. |
|
||||||
|
|
||||||
|
**Coverage:** 17/17 requirements satisfied in code (D-06/D-17 SPA chrome still needs human).
|
||||||
|
|
||||||
|
### Decision Coverage
|
||||||
|
|
||||||
|
gsd-tools `check.decision-coverage-verify`: `{ honoured: 17, total: 17, not_honored: [] }` — “All trackable CONTEXT.md decisions are honored by shipped artifacts.” Non-blocking substring gate. D-06 is now honored as a working one-screen switch in source (selectors read schema locales), not merely as artifact presence.
|
||||||
|
|
||||||
|
### Test Quality Audit
|
||||||
|
|
||||||
|
| Test File | Linked Req | Active | Skipped | Circular | Assertion Level | Verdict |
|
||||||
|
|-----------|-----------|--------|---------|----------|-----------------|---------|
|
||||||
|
| `updates/migrations_test.go` | D-08/D-10 | yes | skip only without Docker | no | value | OK |
|
||||||
|
| `classes/translator_resolve_test.go` | D-07 | yes | no | no | behavioral | OK |
|
||||||
|
| `classes/translatable_test.go` | D-09/D-11/D-12 | yes | no | no | value | OK |
|
||||||
|
| `locales_admin_test.go` | D-05 | yes | no | no | behavioral | OK |
|
||||||
|
| `integration_test.go` | D-17 API | yes | no | no | behavioral HTTP | OK |
|
||||||
|
| `modules/cabana/ml_test.go` | D-06 types / nested lift / hydration | yes | no | no | behavioral | OK — `TestMLHydration` proves missing pl is empty |
|
||||||
|
| `modules/cabana/relation_child_ml_test.go` | D-06/D-17 child | yes | no | no | behavioral | OK |
|
||||||
|
| `admin/tests/form/MLFields.test.ts` | D-06 SPA | yes | no | no | behavioral on create seed, GET string, and maps | OK (prior INSUFFICIENT closed) |
|
||||||
|
| `admin/tests/form/formState.test.ts` | D-06 seed/adopt | yes | no | no | value | OK |
|
||||||
|
|
||||||
|
**Disabled tests on requirements:** 0.
|
||||||
|
**Circular patterns detected:** 0.
|
||||||
|
**Insufficient assertions:** 0 (create `{}` / GET string coverage now present).
|
||||||
|
|
||||||
|
### Anti-Patterns Found
|
||||||
|
|
||||||
|
| File | Line | Pattern | Severity | Impact |
|
||||||
|
| ---- | ---- | ------- | -------- | ------ |
|
||||||
|
| (none in gap-closure files) | — | TBD/FIXME/XXX | — | Debt-marker scan clean |
|
||||||
|
| `../sm-translate-plugin/controllers/locales.go` | makeDefault | Two unordered Updates | 📋 Advisory | WR-01; out of this closure; sequential guards hold |
|
||||||
|
| `../sm-translate-plugin/models/locale.go` | code index | Not UNIQUE | 📋 Advisory | WR-03; out of this closure |
|
||||||
|
|
||||||
|
**Anti-patterns:** prior CR-01/WR-02 blockers are gone. Remaining notes are advisory, not blockers (evidence gate).
|
||||||
|
|
||||||
|
Debt-marker scan on phase-touched production files this pass: no `TBD`/`FIXME`/`XXX`.
|
||||||
|
|
||||||
|
### Human Verification Required
|
||||||
|
|
||||||
|
Automated CR-01/WR-02 gaps are closed. SPA UAT is not invented as a pass.
|
||||||
|
|
||||||
|
### 1. Locales admin in the proof-host SPA
|
||||||
|
|
||||||
|
**Test:** Boot `sm-grzybyfunkcjonalne-app`; sign in as an administrator holding `golem15.translate.manage_locales`; open Locales; confirm English then Polski; edit name/enabled; confirm a user without the permission cannot open the controller.
|
||||||
|
**Expected:** List order en then pl; permitted fields save; forbidden user is 403/hidden.
|
||||||
|
**Why human:** Needs running host + admin login. Harvested from 14.2.1-04-PLAN.md and 14.2.1-06-PLAN.md.
|
||||||
|
|
||||||
|
### 2. Journal-shaped mltext form (when available)
|
||||||
|
|
||||||
|
**Test:** With the executor-started proof host and admin SPA, when a Journal-shaped form with mltext is available, confirm one locale selector per ML field listing en and pl on create (not a single English box), that switching one selector switches the others, and that save/reload still shows both locales.
|
||||||
|
**Expected:** Create lists en and pl; selectors switch together; save/reload keeps both locales.
|
||||||
|
**Why human:** Harvested from 14.2.1-06-PLAN.md. Vitest mounts with injected `['en','pl']`; it does not boot the SPA against live schema meta. The proof host has **no production mltext YAML** (only `admin_harness_test.go` fixture fields). Do not invent a pass. Relation-child ML UAT can wait for Phase 15 if this host has no child ML form.
|
||||||
|
|
||||||
|
## Gaps Summary
|
||||||
|
|
||||||
|
No blocking gaps. Prior CR-01 (admin ML locale switch) and WR-02 (relation-child nested ML maps) are closed in source with named tests that passed this pass.
|
||||||
|
|
||||||
|
Human verification items remain; overall status is `human_needed`, not `passed`.
|
||||||
|
|
||||||
|
## Verification Metadata
|
||||||
|
|
||||||
|
**Verification approach:** Goal-backward re-verification (prior must-haves reused; failed items full 3-level; passed items existence + sanity). SUMMARY.md used only as a file-list hint.
|
||||||
|
**Must-haves source:** Prior VERIFICATION.md (ROADMAP Phase 14.2.1 Success Criteria + 14.2.1-01..04 PLAN frontmatter; 05/06 restated the two failed truths)
|
||||||
|
**Automated checks:** cheap gate stages 5 passed / 0 failed; `TestMLFieldTypes` PASS; `TestMLNestedSave` PASS; `TestMLHydration` PASS; `TestRelationChildMLNestedSave` PASS; Vitest 42/42 PASS
|
||||||
|
**Human checks required:** 2 (Locales SPA; Journal-shaped mltext when available — relation-child UAT waits for Phase 15)
|
||||||
|
**Total verification time:** ~25 min
|
||||||
|
**CR-01 / WR-02:** independently re-read in source; REVIEW.md (status: clean) not rubber-stamped
|
||||||
|
**winter_translate_* in Go production DDL:** absent
|
||||||
|
**Phase gate phrase:** `scripts/check-phase14.2.1.sh` still prints `Phase 14.2.1 gate passed`; `--all` not re-run this pass
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
_Verified: 2026-10-06T14:40:00Z_
|
||||||
|
_Verifier: the agent (gsd-verifier)_
|
||||||
Reference in New Issue
Block a user