- type: password on a settings form binds a lagoon.Encrypted column as a
write-only secret (any other column fails boot naming the field): the
GET omits it from data and reports stored, env or empty per field in
meta.secrets; on PUT an absent key or "" keeps the value, null clears
it, a non-string is a 422; the answer never carries a value
- cabana.SecretFallbacks (field to config key) gives the env state;
cabana.SettingsMeta, SecretStored/SecretEnv/SecretEmpty exported
- settings forms accept richeditor: the Put sanitizes through seaglass
like a controller save and returns meta.notices; repeater and
dependsOn stay refused (settingsFormOnly next to controllerFormOnly)
- backend::lang secret.* phrases in en and pl
- admin SPA: PasswordField secret status line (stored with Remove stored
value, env, empty, pending clear with Undo), SettingsFormView tabs with
error-tab activation and the secrets/notices meta, settings payload
that never sends an untouched secret; regenerated OpenAPI and TS
types; rebuilt dist
- vault fixture, TestSettingsSecretCompile, Docker TestSettingsSecretSmoke
and TestSettingsRichEditorSmoke, conform settings fixture with a
password field; settings.md sections, forms.md notes, cabana README
- columns.yaml type: money with currency or currencyFrom (exactly one),
never searchable, not sortable by default; every list row carries the
currencyFrom column's value under its own key; the schema serves
currency and currencyFrom on the column
- pact.AdminRecordAction.Danger, served as danger on cabana.RecordAction
(absent when false); RecordActions.vue passes it to the confirm dialog
- CellValue money kind through formatMoney with the row's code, the em
dash when empty and the amount alone without a code; DataTable aligns
money headers and cells to the right
- PreviewView renders Edit only when a registered value field allows
update (F6)
- main.css .summer-table* and .summer-stat__note kit classes (F7) over
--c-* variables; cabana README kit rows
- fixture record actions void (danger) and resend; TestMoneyListCompile,
TestMoneyListSmoke and TestRecordActionDangerSmoke; regenerated OpenAPI
and TS types; rebuilt dist; lists-and-filters and admin-controllers docs
- type: money on fields.yaml with currency or currencyFrom, scale (2..4,
default 4) and max; boot fails naming the field on two sources, none,
a bad scale or max, a column that is not a string or a Scanner/Valuer,
or a currencyFrom that is not a string column
- a save answers 422 money.invalid, money.too_precise or money.too_large
on the field and fills the accepted decimal string unchanged; the same
check runs on controller, settings and relation child saves
- backend::lang money.* phrases in en and pl
- admin SPA: money.ts (parseMoneyInput, trimMoneyDisplay, formatMoney over
Intl with the string itself), MoneyField.vue with the currency suffix,
blur validation and the read-only box, preview through the control,
the field scope on PreviewView; regenerated OpenAPI and TS types,
rebuilt modules/boardwalk/dist
- acme.payments fixture with TestMoneyFieldCompile and the Docker
TestMoneyFieldSmoke; forms.md Money section and cabana README
A settings link to a singleton controller only worked on a plain left
click; a new tab landed on the list route, which answers 404, and every
non-singleton link paid an extra /singleton request. The settings index
now links like any controller link, and the list view opens the
controller's one record when its list answers 404 and the singleton
route answers an id.
A move made while a save runs is queued and sent after it settles, so
out-of-order completion can no longer leave the database on an older tree
than the screen. A failure that a waiting save supersedes keeps the later
moves, and a response tied to an earlier load or partition leaves the
current tree and its last saved state alone.
signpost.Registry.Pattern now takes an item override only when it starts
with a single "/" and holds no surrounding whitespace or control
characters (signpost.ValidItemPattern); a javascript: URL or a
protocol-relative //host falls through to the next layer.
- form-action 'self': injected markup cannot post a native form off-origin
- frame-src 'none': no framed content; a sandboxed srcdoc preview is not
fetched and still renders
- header tests, README and admin-spa docs name the directives
- the reorder route renders ReorderView with a ReorderBranch per level
- ReorderBranch renders nodes from the REORDER_PAGE context and moves
through it
- line-exact, path-bound T-17-10 raw-HTML exceptions for the RichEditorField
read-only display and the inert template parse in lossy.ts
- dist-origin allow-list adds the never-requested literals
https://prosemirror.net and https://admin.invalid
- self-test plants: the display line in another file, a template parse
elsewhere, a foreign origin in the dist JS
- --spa also runs the Vitest browser suite, fail-closed
- check-phase17: browser-suite required names in the admin stage, Phase 10
hygiene in the docs stage, asserted by its self-test
- displayHtml uses a dedicated DOMPurify 3.4.16 instance: EDITOR_TAGS, href
only on <a> through isAllowedLink, DROPPED elements go with their content
- string in, string out: parsed into DOMPurify's inert document, nothing
adopted into the live document before binding
- fails closed (empty string) unless isSupported and a fixed canary hold
- Vitest browser mode in Playwright Chromium (npm run test:browser) covers
the clobbering vectors, off-origin form, iframe, meta refresh, links and
the inert parse; happy-dom keeps engine-independent assertions
The plugins stage runs the Docker-free Journal, sitemap, menu, FAQ and
host tests by name per package; the postgres stage adds TestMenuItemTypes,
TestImportWinter, TestMenuEntryBeforeSave, TestMenuAPI, TestMenuImport,
TestFaqAPI and TestFaqImport.
Two first requests to GET .../singleton both missed the record; the
loser's insert hit the unique index and the route answered 500. A
unique violation from SingletonRecord now reruns the transaction once,
which finds the winner's record. TestSingleton fires six concurrent
first requests and requires 200 with the same id from each.
- signpost: activation refusals, host overrides, D-02 pattern layers
incl. PatternFrom, ReferenceOptions depths
- seaglass: removal report, bluemonday bypass corpus, Check
- pact Option.Depth omitempty and the menu item type contracts; party
activates menu item types after Register and before the first Boot
- cabana: repeater compile and decode, dependsOn compile and recheck,
richeditor keys and notices, reorder and singleton boot checks
(Docker-free); repeater save, dependent recheck, richeditor save,
reorder and singleton routes on Postgres; conformance cases for the
documented 404, 409 and 422 answers of the new routes
- admin: richeditor value contract, link popover, notices and chunk
failure; repeater bounds, remove and reorder, collapsed rows;
dependent dropdown states and last request wins; reorder
announcements, partition switch and tree rules; SingletonForm spec
- gate: required names in the go, admin and postgres stages
- scripts/check-phase17.sh: stages go, plugins, admin, layers, docs and
postgres across the framework, four plugin repositories, the host and
both layers; go test -json, vitest JSON and TAP detectors, required
layer test files, --self-test, --all with NOT RUN postgres and
PHASE17_REQUIRE_POSTGRES
- TestRegistryDuplicateKey: a duplicate key fails Activate naming both
plugin IDs, nothing is published
- TestSanitizeByteStable: clean editor HTML comes back byte for byte