docs(33-01): complete framework seams, phase gate and release ledger plan

This commit is contained in:
Jakub Zych
2026-11-04 08:50:35 +01:00
parent 21aa4e575f
commit 03fc292c8b

View File

@@ -0,0 +1,254 @@
---
phase: 33-seo-output-audit-and-content
plan: 01
subsystem: framework
tags: [pact, signpost, cabana, content-descriptor, field-types, gate-script, release-ledger]
requires:
- phase: 32-seo-foundation
provides: pact.ContentDescriptor, signpost content registry, plugin field types, form extensions, check-phase32.sh engine
provides:
- pact.ContentDescriptor.Kind and Tools with ContentKind*/ContentTool* constants
- pact.ContentRecord.PublishedAt, Parents, Authors, TopHeading
- pact.ContentLocale.Images, Videos, Headings and the value types ContentRef, ContentPerson, ContentImage, ContentVideo, ContentHeading
- pact.FormFieldType.RequestOptions merged into served typeOptions per schema request
- scripts/check-phase33.sh (eleven stages plus --all)
- 33-release-log.md (v0.6.1 planned contents and release order)
affects: [33-02, 33-03, 33-04, 33-05, 33-06, 33-07, 33-08, 33-09, 33-10, 33-11, 33-12, 33-13, 33-14]
actuals:
tokens: 24700
tasks: 4
commits: 4
plan_head_before: 399efed845bc7dc7e6a1dbd26ed74d78172684e4
plan_head_after: 21aa4e5
tech-stack:
added: []
patterns:
- "Optional descriptor facts: new slices are nil-or-empty alike; signpost hands records through untouched"
- "Per-request field options: computed once per type per schema request, merged into a copy, fields.yaml wins, errors fail open with one WARN"
key-files:
created:
- modules/signpost/content_fields_smoke_test.go
- modules/cabana/field_request_options_smoke_test.go
- scripts/check-phase33.sh
- .planning/phases/33-seo-output-audit-and-content/33-release-log.md
modified:
- modules/pact/content.go
- modules/pact/capabilities.go
- modules/cabana/field_type.go
- modules/cabana/http.go
- modules/cabana/schema_types.go
- modules/cabana/admin_openapi.go
- modules/signpost/example_content_test.go
- modules/cabana/example_field_type_test.go
- admin/openapi/admin.json
- admin/src/api/schema.d.ts
- docs/plugins/menu-item-types.md
- docs/backend/field-types.md
- modules/pact/README.md
- modules/signpost/README.md
- modules/cabana/README.md
key-decisions:
- "Task 1 Decision A (Jakub 2026-11-04): as-planned; P33-01 descriptor fields/constants/value types and P33-02 FormFieldType.RequestOptions exactly as the plan names them"
- "Task 1 Decision B (Jakub 2026-11-04): WR-02 accepted; pact.RecordSaved.Locale stays the primary tag of the request locale (released in v0.5.2)"
- "Task 1 Decision C (Jakub 2026-11-04): Phase 33 delivers SummerCMS v0.6.1 (patch, additive); additive and marker stages compare with v0.6.0; plans reading v0.5.1/v0.5.2 mean v0.6.0/v0.6.1"
- "RequestOptions receives the application database bound to the request context, nil when none is configured"
patterns-established:
- "Content facts: a content type may set Kind/Tools and per-record PublishedAt/Parents/Authors/TopHeading/Images/Videos/Headings; consumers read them through signpost without importing the content plugin"
- "Phase gate: check-phase33.sh stage engine; a missing repository fails with 'missing <path>'"
requirements-completed: [SC-2, SC-3, D-93, D-90, D-106, D-43, D-86, D-31, D-85, D-50, D-51, D-96, D-10]
coverage:
- id: D1
description: "Additive content descriptor fields and value types, handed through signpost.Describe and signpost.Records unchanged; a type without them describes as before"
requirement: "D-93"
verification:
- kind: unit
ref: "modules/signpost/content_fields_smoke_test.go#TestContentDescriptorFields"
status: pass
- kind: unit
ref: "modules/signpost/example_content_test.go#ExampleRegistry_MatchPath"
status: pass
human_judgment: false
- id: D2
description: "pact.FormFieldType.RequestOptions merged into served typeOptions (every screen, fields.yaml wins, once per type per request, error fails open with one warning, unchanged schema without it, form extension fields, authenticated handler only)"
requirement: "SC-3"
verification:
- kind: unit
ref: "modules/cabana/field_request_options_smoke_test.go#TestFieldTypeRequestOptions"
status: pass
- kind: other
ref: "scripts/check-admin-openapi.sh --check"
status: pass
human_judgment: false
- id: D3
description: "Framework API strictly additive against v0.6.0 and no framework line names SEO, a sitemap, JSON-LD or an application"
requirement: "D-106"
verification:
- kind: other
ref: "bash scripts/check-phase33.sh --go --docs --marker --additive"
status: pass
- kind: other
ref: "bash scripts/check-phase33.sh --compat"
status: pass
human_judgment: false
- id: D4
description: "check-phase33.sh with eleven stages; self-test detects an API removal, an interface method, a marker hit, a failing go test and a missing repository"
verification:
- kind: other
ref: "bash scripts/check-phase33.sh --self-test"
status: pass
human_judgment: false
- id: D5
description: "33-release-log.md records v0.6.1 planned contents, the six Phase 32 fixes as already released in v0.5.2, plugin/layer tag state and the release order"
verification: []
human_judgment: true
rationale: "A planning ledger; its accuracy and the release order are Jakub's call before 33-14 tags anything"
duration: 22min
completed: 2026-11-04
status: complete
---
# Phase 33 Plan 01: Framework seams, phase gate and release ledger Summary
**Optional content facts on pact.ContentDescriptor/Record/Locale (kind, MCP tools, first publication, parents, authors, top heading, images, videos, heading outline), per-request plugin field options through pact.FormFieldType.RequestOptions, the eleven-stage check-phase33.sh gate and the v0.6.1 release ledger**
## Task 1 answers (Jakub, 2026-11-04)
Later plans (33-02 to 33-14) use these:
1. **Decision A: as-planned.** P33-01 and P33-02 are adopted exactly as written, no rename:
- `pact.ContentDescriptor.Kind string` with `ContentKindArticle = "article"`, `ContentKindCollection = "collection"`, `ContentKindProfile = "profile"`, `ContentKindPage = "page"`;
- `pact.ContentDescriptor.Tools map[string]string` with `ContentToolEdit = "edit"`, `ContentToolHeadings = "headings"`, `ContentToolImageAlt = "image_alt"` (values are full MCP tool names);
- `pact.ContentRecord.PublishedAt *time.Time`, `Parents []ContentRef`, `Authors []ContentPerson`, `TopHeading int`;
- `pact.ContentLocale.Images []ContentImage`, `Videos []ContentVideo`, `Headings []ContentHeading`;
- `ContentRef{Type, ID string}`, `ContentPerson{Name string; Ref ContentRef}`, `ContentImage{URL, Alt string; Decorative bool; Width, Height int}`, `ContentVideo{Provider, ID string}`, `ContentHeading{Level int; Text string}`;
- `pact.FormFieldType.RequestOptions func(ctx context.Context, db *gorm.DB) (map[string]any, error)` with `json:"-"`.
2. **Decision B: WR-02 accepted.** `pact.RecordSaved.Locale` stays the primary tag of the request locale, as released in v0.5.2 (commit 1583651). 32-UAT.md is left to verify-work.
3. **Decision C: version base.** Tags v0.5.2, v0.5.3 and v0.6.0 already exist and contain all six Phase 32 fixes (676ca53, 5471b66, d660cd0, 468af06, 1583651, 0e187cf). This phase delivers **SummerCMS v0.6.1** (patch, additive per D-106). `check-phase33.sh --additive` compares against the newest tag not containing HEAD (computed, currently v0.6.0); `--marker` diffs from v0.6.0 (`PHASE33_BASE`). **Where a Phase 33 plan says v0.5.1 (base) or v0.5.2 (target), read v0.6.0 and v0.6.1.** Nothing is pushed or tagged before 33-14.
## Performance
- **Duration:** 22 min (continuation; Task 1 answered before this run)
- **Started:** 2026-11-04T07:26:44Z
- **Completed:** 2026-11-04T07:49:00Z
- **Tasks:** 4 (Task 1 decision, Tasks 2-4 executed)
- **Files modified:** 19
## Accomplishments
- Content types can describe kind, fixing MCP tools, first publication, ordered parents, authors, top heading level, images (with alt and a decorative flag), videos and the heading outline; signpost hands them through, and a type without them is unaffected.
- A plugin field type can serve per-request options to its element through the existing `typeOptions` attribute; the compiled schema is never mutated and errors fail open.
- `scripts/check-phase33.sh` gates the phase: `--self-test`, `--go`, `--docs`, `--marker`, `--additive`, `--admin`, `--plugins` and `--compat` all pass on this host.
- `33-release-log.md` records the v0.6.1 contents and the release order 33-14 follows.
## Task Commits
1. **Task 1: Confirm descriptor fields, RequestOptions, RecordSaved.Locale meaning**: no commit (decision, answers above)
2. **Task 2: Content descriptor fields (tracer)**: `561a56c` (feat)
3. **Task 3: Per-request options for plugin field types**: `4cd35c9` (feat)
4. **Task 4: Phase gate script and release log**: `6ea43bb` (test, group A), `21aa4e5` (docs, group B)
**Plan metadata:** this SUMMARY commit (docs)
## Files Created/Modified
- `modules/pact/content.go`: Kind, Tools, the kind and tool constants, the record and locale fields and the five value types.
- `modules/pact/capabilities.go`: `FormFieldType.RequestOptions` with its doc comment (no secrets, fails open).
- `modules/cabana/field_type.go`: `mergeRequestOptions` (once per type, copy-merge, fields.yaml wins, one WARN on error).
- `modules/cabana/http.go`: form schema route calls it on the request's own field slice; `requestDB` helper.
- `modules/cabana/schema_types.go`, `modules/cabana/admin_openapi.go`, `admin/openapi/admin.json`, `admin/src/api/schema.d.ts`: typeOptions description now names per-request options.
- `modules/signpost/content_fields_smoke_test.go`: `TestContentDescriptorFields` (full type, plain type, nil vs empty slices).
- `modules/cabana/field_request_options_smoke_test.go`: `TestFieldTypeRequestOptions`, one subtest per behaviour line plus the authenticated-handler check (T-33-01).
- `modules/signpost/example_content_test.go`, `modules/cabana/example_field_type_test.go`: runnable examples that the docs embed.
- `docs/plugins/menu-item-types.md`, `docs/backend/field-types.md`, `modules/pact/README.md`, `modules/signpost/README.md`, `modules/cabana/README.md`: documentation of every new identifier.
- `scripts/check-phase33.sh`: phase gate.
- `.planning/phases/33-seo-output-audit-and-content/33-release-log.md`: release ledger.
## Decisions Made
- The Task 1 answers above.
- `RequestOptions` gets the application database bound to the request context, or nil when the application has none. The test service has no database, and a type that needs one can check for nil.
- The compat stage reads the sitemap and Journal plugins at their releases before the phase (v0.1.2, v0.3.1) and sm-demo-app at its HEAD when 33-01 ran (da481c9). It uses read-only snapshots, not worktrees in the sibling repos.
## Deviations from Plan
### Auto-fixed Issues
**1. [Rule 3 - Blocking] Version base moved from v0.5.1/v0.5.2 to v0.6.0/v0.6.1 (Jakub's ruling, Decision C)**
- **Found during:** Task 1 (checkpoint), applied in Task 4
- **Issue:** The plan was written before v0.5.2, v0.5.3 and v0.6.0 were tagged, so the six Phase 32 fixes are already released.
- **Fix:** The additive stage still computes the newest tag that does not contain HEAD (v0.6.0). The marker base is `PHASE33_BASE=v0.6.0`. The release log lists the fixes as "already released in v0.5.2" and plans v0.6.1. The commit subject of group B is `docs(33-01): release log for v0.6.1`, not `... v0.5.2`.
- **Files modified:** scripts/check-phase33.sh, 33-release-log.md
- **Committed in:** 6ea43bb, 21aa4e5
**2. [Rule 3 - Blocking] Plugin tags moved past the plan's ranges**
- **Found during:** Task 4
- **Issue:** The plan pasted `sm-seo-plugin v0.1.0..HEAD` and `sm-journal-plugin v0.2.5..HEAD` as unreleased fixes. Those commits are now released in sm-seo-plugin v0.1.1 and sm-journal-plugin v0.2.6 to v0.3.1, and no plugin or layer has unreleased commits.
- **Fix:** The release log has a table of the newest tag per repository with "none" unreleased. Versions are still read from `git tag` in 33-14.
- **Committed in:** 21aa4e5
**3. [Rule 3 - Blocking] Docs checker requires src= snippets for go code blocks**
- **Found during:** Task 3
- **Issue:** The docs checker refuses a hand-written go snippet in docs/backend/field-types.md.
- **Fix:** Added a runnable `headingLevels` func and `ExampleCompileFormWithTypes_requestOptions` to modules/cabana/example_field_type_test.go. The page embeds the func through `src=`.
- **Committed in:** 4cd35c9
**4. [Rule 2 - Marker] pact README addition moved to a new bullet**
- **Found during:** Task 2
- **Issue:** Editing the existing descriptor bullet re-added its pre-existing word "sitemaps" as a changed line, which the D-90 marker stage would flag.
- **Fix:** The new facts are described in a separate "Content facts" bullet, and the original line is unchanged.
- **Committed in:** 561a56c
**5. [TDD] Task 3 RED evidence not committed separately**
- **Found during:** Task 3
- **Issue:** The plan's commit-group table gives Task 3 one commit (`feat(cabana): ...`), while tdd.md's cycle commits `test(...)` first. The plan is `type: execute`, not `type: tdd`.
- **Fix:** I followed the plan's single commit. RED was recorded before implementing: TestFieldTypeRequestOptions failed on 4 behaviour subtests (`typeOptions=map[rows:4]`, `calls=0`, no warning logged), and `check tdd-red-evidence` returned RED_EVIDENCE_OK. GREEN then passed all 8 subtests.
---
**Total deviations:** 5 (3 blocking, 1 marker-safety, 1 TDD commit-shape note)
**Impact on plan:** The API shape and behaviour are exactly as planned. Only version numbers, the ledger contents and the doc mechanics changed.
## Issues Encountered
- The compat stage reports sm-feedback-plugin, sm-presentations-plugin and sm-quizzes-plugin as "skipped (fails at v0.6.0 too)": they do not resolve the framework through a scratch workspace at either revision. These failures predate this plan and are not caused by it.
- shellcheck warns SC2034 (`type` unused) in the copied `snapshot_submodules`. check-phase32.sh has the same warning, so I left it as is.
## Verification run
- `go vet ./... && go test -short ./...`: green after every commit.
- `go test ./modules/signpost -run 'TestContentDescriptorFields|Example' -v`: PASS (5 subtests, 3 examples).
- `go test ./modules/cabana -run 'TestFieldTypeRequestOptions|TestFormExtensionUnextendedSchemaUnchanged' -v`: PASS (8 subtests).
- `scripts/check-admin-openapi.sh --check`: exit 0. `check-phase33.sh --admin` (openapi + dist): passed.
- `go test ./cmd/summer -run TestDocsTree` and `summer docs:build --check`: no problems.
- `bash scripts/check-phase33.sh --self-test`: passed (37 checks). Without an argument it exits 2 and prints the usage.
- `bash scripts/check-phase33.sh --go --docs --marker --additive`: PASS all four; additive: cabana +0, pact +35, signpost +0 lines against v0.6.0.
- `bash scripts/check-phase33.sh --plugins`: passed (sm-seo-plugin 77 and sm-journal-plugin 232 vitest tests).
- `bash scripts/check-phase33.sh --compat`: passed.
- Not run here: `--layers` (vue-seo-layer `testing/guard-check.mjs` arrives in 33-08), `--consumers`, `--docker`.
## User Setup Required
None. No external service configuration is required.
## Next Phase Readiness
- 33-02 (Blog Editor) can use `RequestOptions` for `headingLevels` and `genericAnchors`, and 33-03 onward can fill and read the content facts.
- 33-14 tags framework **v0.6.1** and follows 33-release-log.md.
## Self-Check: PASSED
- FOUND: modules/pact/content.go, modules/pact/capabilities.go, modules/signpost/content_fields_smoke_test.go, modules/cabana/field_request_options_smoke_test.go, scripts/check-phase33.sh, 33-release-log.md
- FOUND commits: 561a56c, 4cd35c9, 6ea43bb, 21aa4e5
---
*Phase: 33-seo-output-audit-and-content*
*Completed: 2026-11-04*