From c1a65c9f227c75368ea91188df05bbd8ebc195cd Mon Sep 17 00:00:00 2001 From: Jakub Zych Date: Wed, 14 Oct 2026 21:13:47 +0200 Subject: [PATCH] docs(18.1-06): complete phase 18.1 tests, gate and release plan (push-all) --- .../18.1-06-SUMMARY.md | 403 ++++++++++++++++++ 1 file changed, 403 insertions(+) create mode 100644 .planning/phases/18.1-payment-gateway-subscriptions/18.1-06-SUMMARY.md diff --git a/.planning/phases/18.1-payment-gateway-subscriptions/18.1-06-SUMMARY.md b/.planning/phases/18.1-payment-gateway-subscriptions/18.1-06-SUMMARY.md new file mode 100644 index 0000000..d629b62 --- /dev/null +++ b/.planning/phases/18.1-payment-gateway-subscriptions/18.1-06-SUMMARY.md @@ -0,0 +1,403 @@ +--- +phase: 18.1-payment-gateway-subscriptions +plan: 06 +subsystem: testing +tags: [subscriptions, stripe, cabana, taglist, reorder, gate, testcontainers, vitest, node-test, release] + +# Dependency graph +requires: + - phase: 18.1-01 + provides: cabana taglist field and flat reorder (tag v0.1.26 was held) + - phase: 18.1-02 + provides: pgsub core (models, contracts, classes.Service, baseline) + - phase: 18.1-03 + provides: golem15.pgstripesubscriptions (gateway, webhook, job, plan sync) and the subscription secrets + - phase: 18.1-04 + provides: pgsub admin screens and customer API ("api-research" contract) + - phase: 18.1-05 + provides: vue-paymentgateway-layer subscription pieces (tag v0.2.0 was held) +provides: + - "scripts/check-phase18.1.sh: fail-closed gate over four repositories (go, plugins, admin, layers, docs, postgres, --self-test, --all, PHASE181_REQUIRE_POSTGRES)" + - "unit and Postgres coverage of every behaviour plans 01 to 05 added, and the nine-row PHP test map" + - "fix: the localized list schema keeps reorder.flat" + - "validated 18.1-VALIDATION.md (nyquist_compliant)" + - "release: framework v0.1.26, layer v0.2.0, plugin requires on v0.1.26, all four repositories pushed" +affects: [consuming applications' subscription cutover, phase 20 import, /msd-verify-work 18.1] + +# Actuals (#2632): chars/4 over the added lines of the four repositories (planning docs excluded) +actuals: + tokens: 60749 + tasks: 5 + commits: 11 +commits: 11 +plan_head_before: "summercms.go dbf8aaac74d6f94c5307ff86afda32d852fb3891; sm-paymentgatewaysubscriptions-plugin b72876253a33932109003fe211c228c5c89fcb44; sm-pgstripe-plugin 592b4741dedec2e7376ba7f2a94f8032cd04c3dc; vue-paymentgateway-layer 3dea9cd8cf82d46a9317e4f120c7544384c68ca3" +plan_head_after: "summercms.go 5c2b0e1d8a1929fa8154c262b288937690e69bce; sm-paymentgatewaysubscriptions-plugin 472b75bb420675d6a0e547622e9f28383a7092bc; sm-pgstripe-plugin baf3c55aa0cba87ae80babbb9b7e0711b9f6e86d; vue-paymentgateway-layer 30046f52590d69f3e6a396ac93b37bb425aa0894" + +tech-stack: + added: [] + patterns: + - "Phase gate requires tests by name per repository and package; the TAP detector also requires a minimum count of tests by name prefix" + - "A test-only export_test.go wrapper exposes an unexported helper to the external test package" + - "Concurrency proofs: two goroutines in overlapping transactions, exactly one claim or one fired event" + - "Open-transaction probe: pg_stat_activity 'idle in transaction' checked from a gateway fake at each call" + - "Golden schema transcribed from the PHP dump, not derived from the migration" + +key-files: + created: + - scripts/check-phase18.1.sh + - ../sm-paymentgatewaysubscriptions-plugin/models/subscription_test.go + - ../sm-paymentgatewaysubscriptions-plugin/models/subscription_plan_test.go + - ../sm-paymentgatewaysubscriptions-plugin/models/feature_list_test.go + - ../sm-paymentgatewaysubscriptions-plugin/contracts/registry_test.go + - ../sm-paymentgatewaysubscriptions-plugin/lang_parity_test.go + - ../sm-paymentgatewaysubscriptions-plugin/apply_events_test.go + - ../sm-paymentgatewaysubscriptions-plugin/user_subscribable_test.go + - ../sm-paymentgatewaysubscriptions-plugin/baseline_test.go + - ../sm-paymentgatewaysubscriptions-plugin/service_api_test.go + - ../sm-paymentgatewaysubscriptions-plugin/admin_actions_test.go + - ../sm-paymentgatewaysubscriptions-plugin/customer_api_authz_test.go + - ../sm-pgstripe-plugin/subscriptions/decode_test.go + - ../sm-pgstripe-plugin/subscriptions/job_test.go + - ../sm-pgstripe-plugin/subscriptions/sync_plan_test.go + - ../sm-pgstripe-plugin/subscriptions/gateway_test.go + - ../sm-pgstripe-plugin/subscriptions/php_map_test.go + - ../sm-pgstripe-plugin/subscription_secrets_test.go + modified: + - modules/cabana/list_schema.go + - modules/cabana/export_test.go + - modules/cabana/taglist_field_test.go + - modules/cabana/reorder_flat_test.go + - modules/cabana/catalog_smoke_test.go + - modules/cabana/README.md + - admin/tests/form/TaglistField.test.ts + - admin/tests/views/ReorderView.test.ts + - .planning/phases/18.1-payment-gateway-subscriptions/18.1-VALIDATION.md + - .planning/phases/18.1-payment-gateway-subscriptions/deferred-items.md + - ../sm-paymentgatewaysubscriptions-plugin/admin_smoke_test.go + - ../sm-paymentgatewaysubscriptions-plugin/README.md + - ../sm-paymentgatewaysubscriptions-plugin/go.mod + - ../sm-pgstripe-plugin/subscriptions/stripefake_test.go + - ../sm-pgstripe-plugin/README.md + - ../sm-pgstripe-plugin/subscriptions/README.md + - ../sm-pgstripe-plugin/go.mod + - ../vue-paymentgateway-layer/tests/subscriptions.test.ts + - ../vue-paymentgateway-layer/tests/subscribe.test.ts + - ../vue-paymentgateway-layer/tests/subscriptionComponents.test.ts + - ../vue-paymentgateway-layer/README.md + +key-decisions: + - "Final push (D-22): human reply \"push-all\"; framework master and tag v0.1.26, pgsub and pgstripe main with summercms v0.1.26 required, layer main and tag v0.2.0 pushed; nothing force-pushed" + - "The localized list schema now carries reorder.flat (framework fix 0f09586, part of v0.1.26)" + - "The layer's check-git-install.sh stays open: no gate or release step runs it" + - "The gate never installs packages; a pnpm store mismatch fails the layer stage with the offline recovery command" + +patterns-established: + - "Phase gate per phase: required names per repository and package, fail on skip, miss, todo, not ok or no tests, NOT RUN postgres loud" + +requirements-completed: [SC-1, SC-2, SC-3, SC-4, SC-5, D-01, D-03, D-04, D-05, D-08, D-09, D-11, D-12, D-13, D-15, D-16, D-17, D-18, D-19, D-21, D-22] + +coverage: + - id: D1 + description: "Fail-closed phase gate over four repositories with a self-test of every detector" + requirement: SC-5 + verification: + - kind: other + ref: "PHASE181_REQUIRE_POSTGRES=1 bash scripts/check-phase18.1.sh --all (all seven stages PASS)" + status: pass + human_judgment: false + - id: D2 + description: "Framework taglist and flat reorder matrices, the localized reorder.flat fix, admin specs" + requirement: D-17 + verification: + - kind: unit + ref: "modules/cabana/taglist_field_test.go#TestTaglistFieldValidate, #TestTaglistFieldHydrate; reorder_flat_test.go#TestReorderFlatNodes, #TestReorderFlatCompile" + status: pass + - kind: integration + ref: "modules/cabana/catalog_smoke_test.go#TestReorderFlatSmoke (partitioned subtest)" + status: pass + - kind: unit + ref: "admin/tests/form/TaglistField.test.ts; admin/tests/views/ReorderView.test.ts" + status: pass + human_judgment: false + - id: D3 + description: "pgsub models, registries, event matrix, concurrent claim, user subscriber, golden baseline, service API, admin actions, customer API authorization, lang parity" + requirement: SC-1 + verification: + - kind: unit + ref: "sm-paymentgatewaysubscriptions-plugin: TestSubscriptionChecks, TestPlanPrices, TestFeatureList, TestRegistry, TestLangParity" + status: pass + - kind: integration + ref: "sm-paymentgatewaysubscriptions-plugin: TestApplyEvents, TestClaimEventConcurrent, TestUserSubscribable, TestBaselineSchema, TestServiceAPI, TestAdminSyncActions, TestCustomerAPIAuthz" + status: pass + human_judgment: false + - id: D4 + description: "pgstripe decode, job (STRIPE-006/007, duplicate, concurrent), plan sync, gateway, PHP map, subscription secrets" + requirement: SC-2 + verification: + - kind: unit + ref: "sm-pgstripe-plugin/subscriptions: TestDecodeSubscription, TestDecodeInvoice, TestJobArgsMinimal" + status: pass + - kind: integration + ref: "sm-pgstripe-plugin/subscriptions: TestSubscriptionJob, TestSyncPlan, TestSubscriptionGateway, TestStripeSubscriptionReliability, TestSubscriptionAuthentication; root TestStripeSubscriptionSecrets" + status: pass + human_judgment: false + - id: D5 + description: "Layer subscription client, flows and component specs (36 'subscriptions:' tests)" + requirement: D-14 + verification: + - kind: unit + ref: "vue-paymentgateway-layer tests/subscriptions.test.ts, subscribe.test.ts, subscriptionComponents.test.ts" + status: pass + human_judgment: false + - id: D6 + description: "Release: four repositories pushed, v0.1.26 and v0.2.0 tags on origin, plugin requires on v0.1.26" + requirement: D-22 + verification: + - kind: other + ref: "git rev-parse == origin/ in all four repositories; git ls-remote --tags origin v0.1.26 / v0.2.0" + status: pass + human_judgment: false + - id: D7 + description: "Live Stripe test-mode checkout, the portal cancel_at question (D-21) and the admin and layer screens in a real browser" + verification: [] + human_judgment: true + rationale: "Needs a real Stripe test account, a public webhook URL and a browser; listed as manual-only rows in 18.1-VALIDATION.md" + +duration: 50min +completed: 2026-10-14 +status: complete +--- + +# Phase 18.1 Plan 06: Tests, gate and release Summary + +**Every behaviour of plans 01 to 05 now has a unit or Postgres test across the framework, pgsub, pgstripe and the layer. The nine PHP pgstripe tests map to named Go cases. `scripts/check-phase18.1.sh --all` is green with Postgres required. The tests exposed one framework bug (the localized list schema dropped `reorder.flat`), which is now fixed. On the human's "push-all" the phase was published as framework v0.1.26 and layer v0.2.0, and both plugins now require v0.1.26.** + +## Performance + +- **Duration:** about 50 min. Tasks 1 to 4 ran from 18:24:41Z to 19:09Z, then the checkpoint, then the release and close-out from 19:10Z to about 19:15Z. +- **Tasks:** 5 of 5. +- **Files:** 39 across four repositories, plus the planning docs. + +## Task Commits + +| Task | Repo | Commit | Message | +|------|------|--------|---------| +| 1 | summercms.go | `3cc4a5f` | test: fail-closed phase 18.1 gate with detector self-test | +| 2 | summercms.go | `0f09586` | fix: keep reorder.flat in the localized list schema | +| 2 | summercms.go | `323b6d6` | test: taglist and flat reorder matrices, partitioned flat smoke, admin specs | +| 2 | vue-paymentgateway-layer | `30046f5` | test: subscription client, flow and component coverage | +| 3 | sm-paymentgatewaysubscriptions-plugin | `1da437f` | test: pgsub unit and Postgres coverage | +| 3 | summercms.go | `6f71cd1` | test: require the pgsub tests in the gate | +| 4 | sm-pgstripe-plugin | `88f9125` | test: decode, job, plan sync, gateway, PHP map and secret coverage | +| 4 | summercms.go | `7790434` | test: require the pgstripe tests in the gate | +| 4 | summercms.go | `5c2b0e1` | docs: validated VALIDATION map and deferred items | +| 5 | sm-paymentgatewaysubscriptions-plugin | `472b75b` | chore: require summercms v0.1.26 | +| 5 | sm-pgstripe-plugin | `baf3c55` | chore: require summercms v0.1.26 | + +**Plan metadata:** the docs commits that add this SUMMARY and the STATE/ROADMAP update, pushed after the tag. The tag is not moved. + +## Task 5: release decision + +**Reply (verbatim):** "push-all" + +This is what was done, in the order of the push sheet. Nothing was force-pushed, and every repository was 0 commits behind its origin before its push. + +**Framework** +- master pushed: `a377953..5c2b0e1`. +- Annotated tag `v0.1.26` created on `5c2b0e1` (tag object `03c33dd`) and pushed. + +**pgsub** +- Commit `472b75b` raises the require to `git.golem15.com/golem15/summercms v0.1.26`; the replace onto `../summercms.go` is unchanged. +- `go mod tidy` resolved through the replace, so no proxy fetch was needed (default GOPROXY, no GONOSUMDB) and go.sum is unchanged. +- vet and the `-short` tests pass. +- main pushed: `aad4647..472b75b`. + +**pgstripe** +- Commit `baf3c55` makes the same bump, with the same tidy, vet and `-short` results. +- main pushed: `0313820..baf3c55`. + +**Layer** +- main pushed: `ac2b960..30046f5`. +- Annotated tag `v0.2.0` created on `30046f5` (tag object `f1107fa`) and pushed. + +**Check:** after the pushes, each local branch equals its origin branch: + +| Repository | Branch | Hash | +|------------|--------|------| +| summercms.go | master | `5c2b0e1` (before this SUMMARY's docs commits, which are pushed afterwards) | +| pgsub | main | `472b75b` | +| pgstripe | main | `baf3c55` | +| layer | main | `30046f5` | + +`git ls-remote --tags` shows `v0.1.26` on the framework origin and `v0.2.0` on the layer origin. + +## Tests added + +**Framework (cabana, admin)** +- Docker-free tests: + - `TestTaglistFieldValidate`: 19 accepted and 17 refused cases, both modes, the locale, multiple fields. + - `TestTaglistFieldHydrate`: 12 stored shapes. + - `TestReorderFlatNodes`: flat parent 422, duplicate and zero id 422, missing, extra or swapped node 409, a 200-node flat list, and the tree contrast. + - `TestReorderFlatCompile` now also checks the localized list schema. +- Postgres test: the subtest `TestReorderFlatSmoke/partitioned`, over the new in-memory `acme.shelf` fixture. +- vitest: + - 9 TaglistField coverage specs: script markup, Backspace, blur, paste, datalist, customTags, comma string mode, array mode, aria. + - 2 flat ReorderView specs: the keyboard and the three drop zones. + +**pgsub** +- Docker-free tests: `TestSubscriptionChecks`, `TestPlanPrices`, `TestFeatureList`, `TestRegistry`, `TestLangParity`. `TestLangParity` checks keys, `:placeholders` and every key the sources name; a planted placeholder mismatch made it fail. +- Postgres tests: + - `TestApplyEvents`: 272 cases (status pairs times cancel flags) against an independent copy of the PHP rule, plus deleted, invoices and refused updates. + - `TestClaimEventConcurrent`: two overlapping claims, five rounds, plus a rollback. + - `TestUserSubscribable`. + - `TestBaselineSchema`: golden names from the PHP dump, jsonb columns, RESTRICT, a re-run, rollback then migrate, the users column only when missing. + - `TestServiceAPI`: a probe gateway checks for open transactions and committed customer ids at each call; a sanity subtest proves the probe sees an open transaction. + - `TestAdminSyncActions`. + - `TestCustomerAPIAuthz`: routes × anonymous, malformed and admin tokens, the owner and another user. It covers the byte-exact none answer and ignored redirect and subscriber fields. + +**pgstripe** +- Docker-free tests: `TestDecodeSubscription`, `TestDecodeInvoice`, `TestJobArgsMinimal` (a fixed key list, no PII). +- Postgres tests: + - `TestSubscriptionJob`: STRIPE-006 rollback through a listener that fails on demand, STRIPE-007 skips, duplicate and concurrent jobs, both shapes. + - `TestSyncPlan`. + - `TestSubscriptionGateway`. + - `TestStripeSubscriptionReliability` and `TestSubscriptionAuthentication` (the PHP map). + - Root `TestStripeSubscriptionSecrets`. +- `TestSDKPin` remains the STRIPE-003 case. + +**Layer:** 9 more `subscriptions:` tests (36 in total): +- refusals passed through unchanged, and the `usePlans` key; +- a retry after a refusal, and the buttons' copy before a click; +- the currency prop; +- the confirmed 404 none answer end to end; +- the Cancel visibility matrix; +- the manage flow with 401, 409, 422, 429 and 502; +- the cancel busy guard. + +## PHP test map (pgstripe 8b47457) + +| PHP | Go | +|-----|----| +| ReliabilityTest `test_stripe_006_idempotency_marker_after_job_success` :33 | `subscriptions.TestStripeSubscriptionReliability/stripe_006_marker_after_job_success` | +| ReliabilityTest `test_stripe_006_idempotency_marker_double_processing_prevented` :99 | `.../stripe_006_double_processing_prevented` | +| DataHandlingTest `test_stripe_001_api_keys_stored_as_plaintext` :28 | `TestStripeSubscriptionSecrets/stripe_001_not_plaintext` | +| DataHandlingTest `test_stripe_001_keys_encrypted_at_rest` :81 | `.../stripe_001_encrypted_at_rest` | +| DataHandlingTest `test_stripe_001_secret_keys_round_trip_encrypted_to_db` :153 | `.../stripe_001_round_trip` | +| DataHandlingTest `test_pay_10_lazy_decrypt_handles_plaintext` :227 | `.../pay_10_import_plaintext_and_encrypted` | +| DataHandlingTest `test_stripe_003_sdk_constraint_pinned` :278 | `TestSDKPin` (unchanged) | +| AuthenticationTest `test_pay_09_..._accepts_valid_sig` :176 | `subscriptions.TestSubscriptionAuthentication/pay_09_accepts_valid` (both URLs) | +| AuthenticationTest `test_pay_09_..._rejects_invalid_sig` :121 | `.../pay_09_rejects_invalid` (both URLs) | +| AuthenticationTest `test_stripe_002_*` :42, :74 | Phase 18 scope: `TestStripeAuthentication` (payment notification) | + +## Gate results + +`PHASE181_REQUIRE_POSTGRES=1 bash scripts/check-phase18.1.sh --all` passed every stage, and the Task 5 verify run (clean trees plus `--all`) printed `final-push-sheet-ok`. + +| Stage | Result | +|-------|--------| +| self-test | PASS | +| go | 5 required framework tests | +| plugins | pgsub 9 named (models 3, contracts 1, root 5); pgstripe 7 named (root 4, subscriptions 3); vet and `-short` green in both repositories | +| admin | vue-tsc; vitest 1401 tests in 92 files | +| layers | 105 TAP tests, 0 failures; 36 named `subscriptions:` (minimum 36) | +| docs | TestDocsTree, docs:build, the OpenAPI check, the dist check and the phase 10 hygiene check | +| postgres | framework 3; pgsub 14; pgstripe 4 in the root and 7 in subscriptions | + +No suite was NOT RUN. + +## VALIDATION + +`18.1-VALIDATION.md` is `status: validated`, `nyquist_compliant: true` and `wave_0_complete: true`. It covers every task of plans 01 to 06 and keeps three manual-only rows: +- the portal `cancel_at` check; +- a live test-mode checkout; +- the screens in a browser. + +## Decisions Made + +- Release per the reply "push-all", in the push sheet order. The tag was set on the code-complete HEAD `5c2b0e1`; the later docs commits are pushed without moving it. +- The STRIPE-002 payment-notification tests stay Phase 18 scope. +- The gate copies the Phase 18 detectors instead of sourcing them, and adds a check for the number of tests by name prefix. + +## Deviations from Plan + +### Auto-fixed Issues + +**1. [Rule 1 - Bug] The localized list schema dropped `reorder.flat`** +- **Found during:** Task 2. This was the deferred item from plan 18.1-04. +- **Issue:** `ListSchema.Localize` copied only the reorder title and partition, so `GET .../schema/list` answered a flat reorder without `flat: true`. +- **Fix:** `Flat` is now copied. The README and the docs already described the flag, so no doc change was needed. +- **Verification:** the RED subtest `TestReorderFlatCompile/the_localized_list_schema_keeps_flat` failed first; its RED evidence was checked as RED_EVIDENCE_OK. It passes after the fix. +- **Committed in:** `0f09586` (fix), then `323b6d6` (test). + +### Adaptations + +1. **Test-only wrappers in `modules/cabana/export_test.go`** (`CheckTaglistValues`, `HydrateTaglistFields`, `CheckReorderNodes`, `IsReorderStale`). The existing tests are in package `cabana_test`, which cannot call the unexported helpers. +2. **The partitioned flat case uses a fixture of its own.** It runs on the in-memory plugin `acme.shelf`, so the catalog fixture is unchanged. +3. **One shared source scan.** `TestAdminLangParity`'s scan moved into the helper `langUsedKeys`, which `TestLangParity` also uses. The behaviour of the existing test is unchanged. +4. **A price failure switch in the package Stripe fake** (`failPrices`), so a test can fail the price step after the product step. +5. **`subscriptions/decode_test.go` is an internal test**, because the decoders are unexported. +6. **The STRIPE-006 failure is injected through a listener** that fails on demand, registered by the test. The failure then happens after Apply saved the row, which proves that the row and the marker roll back together. +7. **The gate's layer stage never installs.** If pnpm aborts on the store mismatch, the stage fails and prints the offline, frozen-lockfile recovery command. +8. **A success-URL case with a fragment was dropped.** Go and PHP both append `?session_id` after a `#fragment`. That is PHP parity, and it is left untested rather than pinned. +9. **Most coverage tasks had no failing test first.** The tdd="true" coverage tasks tested behaviour that already existed, so only the `reorder.flat` defect produced a failing test before the fix. The plan is `type: execute`, so the plan-level TDD gate does not apply. + +**Total deviations:** 1 auto-fixed (Rule 1) and 9 adaptations. +**Impact on plan:** test-side plumbing only, plus one framework bug fix. No scope or dependency was added. + +## Deferred items + +| Item | Status | +|------|--------| +| `reorder.flat` in the localized list schema | resolved by `0f09586` | +| pnpm store-dir mismatch (watch item) | resolved: the gate ran the layer suite green from a clean shell, and the layer stage never installs | +| `vue-paymentgateway-layer/scripts/check-git-install.sh` targets vue-journal-layer | **still open**: no gate or release step runs it | + +Because of the last item, an install check of the published `v0.2.0` tag needs a quick task on the layer first. + +## Issues Encountered + +- **The tool layer unescaped `<` in written test literals.** The affected expectations were rewritten with explicit bytes. +- **An interactive `cp` alias blocked a file restore after a mutation check.** The file was restored with `command cp -f` and confirmed clean. + +## Threat Flags + +None. The plan added tests, a one-line framework fix, two go.mod require bumps and the releases. +- **T-18.1-32:** the gate requires every test by name, and `--self-test` proves its detectors. +- **T-18.1-33:** every Stripe call in the tests goes to the fakes, and the secrets in tests are test-only literals. +- **T-18.1-34:** the full gate ran before the human's reply, and the pushes followed the resolvable order without a force push. +- **T-18.1-SC:** no package was installed. + +## Known Stubs + +None. + +## User Setup Required + +None. + +## Next Phase Readiness + +- The phase is published. + - Applications can require `git.golem15.com/golem15/summercms v0.1.26`. + - They can pin `vue-paymentgateway-layer#v0.2.0`. + - They can build pgsub and pgstripe from main. +- One limitation remains: pgstripe requires `sm-paymentgatewaysubscriptions-plugin v0.0.0` with a replace, and pgsub has no tag. Building from git without the replace needs a pgsub tag or a pseudo-version, the same as the existing sm-paymentgateway-plugin pattern. +- Next: `/msd-verify-work 18.1` with the manual-only rows: a live Stripe test-mode checkout, the portal `cancel_at` check and the browser pass. + +--- +*Phase: 18.1-payment-gateway-subscriptions* +*Completed: 2026-10-14* + +## Self-Check: PASSED + +- Files: the gate script, all 17 new test files and the validated VALIDATION map exist. +- Commits on their origin branches: + +| Repository | Commits | +|------------|---------| +| summercms.go | `3cc4a5f`, `0f09586`, `323b6d6`, `6f71cd1`, `7790434`, `5c2b0e1` | +| pgsub | `1da437f`, `472b75b` | +| pgstripe | `88f9125`, `baf3c55` | +| layer | `30046f5` | + +- Tags: `v0.1.26` is on the framework origin and `v0.2.0` on the layer origin.