Add an append-only ledger of entitlement set rule changes with per-pool
effect rows, a preview-and-commit rule change flow, and an automatic
drain that settles deferred recomputations. Rules gain a tier reduction
policy, resource keys declare over-limit behavior, and the materializer
now lowers limits when a rule stops applying.
Add entitlement set rule change ledger and preview flow
Add an append-only ledger of entitlement set rule changes with a
preview-and-commit operator flow. Rule writes now go through an enclosed
`core.commit_rule_change` function that files an act row and one
obligation per carrying pool, with a drain workflow settling deferred
recomputations. The preview dry-runs the materializer with a rule
overlay and renders per-pool buckets, reduction-policy disclosures, and
provider over-limit consequences. Materializing transactions take a
shared advisory rendezvous that rule changes hold exclusively, enforced
by a possession assertion. Add History and Entitlement changes surfaces,
a rule-less warning on five product-selection surfaces, and a
`tier_reduction_policy` column that gates FedWiki parking.
Introduce a commercial license option alongside AGPL-3.0-only, require a
CLA for contributors, and document the terms in COMMERCIAL.md and
NOTICE. Add a script to stamp SPDX headers on Go files and apply it
across the tree.
Parse every config value through a single declared type at save, boot,
and validate, and expose the settings seam from the terminal so
operators can list, set, clear, and validate overrides without SQL.
Six review rounds on the September walk's 40 findings, executed as the
acceptance-fixes change (design D1 to D31) and archived as
openspec/changes/archive/2026-09-03-acceptance-fixes/ with its 20
deltas synced into openspec/specs.
Shell and conventions: the location trail on every page rooted at the
surface; click-opened help popovers; buttons by role with the pressed
rule retired and tertiary openers with a rotating plus; the code chip
and white card headers; Remove versus Delete on row actions.
Operator surface: three overview tiles, one Integrations card, the
getting-started banner as the first instance setting
(core.instance_settings, migration 00015); record creation on its own
page for products, entitlement sets, and plan ladders; Visibility as
one Public checkbox; the Stripe provider page; the plan ladder
validation page retired and ranks ascending; org-types default change
with dispositions, Discard, and the settle-cloning fix; the rebuilt
composite billing card; hints instead of placeholders; the person page's
identity-provider glyph on its field labels; non-UUID ids answer 404.
Found by review and fixed: a session now ends when its person no longer
exists (the foreign-key failure on a ladder reorder after a snapshot
rebuild); the CSRF cookie lives as long as the session and its toast
says the page is out of date; htmx's settle delay is 0 app-wide.
Verification: unit suites, browser walkthroughs, the screens baseline
(31 screens, accepted), and Lighthouse at 100 on both widths, recorded
in docs/operator-a11y-baseline.md. Three stale issue entries archived.
Replace the entity slugs on organizations, workspaces, resource pools,
and
plan ladders with nullable `key` columns and add keys to products,
prices,
and entitlement sets. Rename `providers.slug` to `provider` and add
partial
unique indexes for system and org role names.
Assign invoice numbers per billing account from a gapless transactional
counter; Stripe's number moves to the invoice mapping as an external
reference.
Seeds, fixtures, and the operator lookup address rows by key, and the
returning-login resync no longer blanks a display name when the IdP
sends
no `name` claim.
Enforce 10j's verified gaps (schema-hardening change):
- Migration 00010: partial unique indexes for one default pool and one
primary assignment per workspace, plus CHECKs pinning
pool/provider/subscription vocabularies and provider lifecycle
timestamps.
- Workspace creation shares a transactional provisioning function;
extension validates its target pool; last-tier deletion of a defaulted
ladder is guarded; signup completes plan-less on a broken ladder.
- Boot asserts integration slug parity and validates declared config
enums; Stripe invoice amounts are range-checked; domain cancellation
runs a final evidence probe; rule authoring is additive-only.
Back the operator landing surface with live deployment counts and
integration health signals, one sqlc query per owning module.
CountDeliveringGrants joins core.pool_provisions rather than filtering
grants.status: grants.status is an issuance ledger recording what was
written down and whether it was later revoked, not whether service is
flowing. The current-delivery fact lives on pool_provisions.status, and a
grant can sit at status='active' with every provision ended. Counting the
ledger alone would overstate delivery.
CountClaimsByLifecycle and CountOutboxByStatus each return their buckets
in a single row, so the halves that get printed together are read at the
same instant and the landing surface pays one round trip rather than one
per bucket.
List every provider kind with direct settings and admin links, move
FedWiki
under the integrations route, and add in-shell operator 404s.
Report sync health from Temporal schedule executions and clear one-shot
settings feedback parameters after display.
Persist non-secret ConfigSpec overrides in core and apply them at boot
ahead of environment values and defaults. Validate typed and enum
values,
show pending restart state, and remove Stripe's unused provider config
table.
Deliver forum posting entitlements through managed group membership with
identity linkage, periodic reconciliation, webhook handling, and an
operator mapping surface.
Include fake and live test environments, setup documentation,
migrations,
and end-to-end coverage.
Preview affected orgs by position source and require keep or migrate for
default-sourced positions. Commit deletion, renumbering, and holder
reconciliation atomically while preserving other-source delivery.
Add an explicit registry with capability hooks for migrations, routes,
workflows, config, and UI assets. Move FedWiki fully and Stripe's
separable
store, workflow, and webhook pieces under internal/integrations.
Drive startup wiring from declarations, including config validation,
secret
file pairs, CSRF exemptions, UI composition, and workflow startup. Move
integration DB roles and grants into their owning migration streams, and
route outbox writes through a shared enqueue helper.
Squash the pre-production migration history into fresh core, fedwiki,
and stripe baselines and reduce the canonical source list to those
three streams.
Update sqlc configs, generated queries, raw SQL, tests, and docs while
keeping provider tables schema-qualified.
BREAKING: existing local database volumes must be wiped because goose
version history restarts from the new baselines.
Fix HTMX expired-session handling, CSP-blocked form behaviors, reorder
recovery, billing currency display, plan/checkout guards, FedWiki quota
edge cases, and operator/member empty/error states.
Add entitlement uniqueness migrations, canonical migration source
wiring,
and regression coverage for the remediated flows. Update status docs
with
the audit triage and model inventory.
Consume wiki-plugin-farmmanager v0.4.1's reversible site states to implement the
force_reduce read-only downgrade and a reversible-delete (archive) model.
Implements the OpenSpec change fedwiki-lifecycle-states.
- Contract: replace the discrete set_readonly/suspend verbs with a parameterized
set_status verb; providers declare their supported lifecycle states
(integration.provider_states). FedWiki declares active/readonly/archived.
- FedWiki state model: fedwiki.sites gains status, storage_bytes, last_modified_at,
force_reduced_at, archived_at; FarmManagerClient.SetSiteStatus (PATCH) +
storageBytes/lastModified; SetSiteStatusWorkflow saga keeps quota = active sites
(quota-gated reactivation).
- Sync now PROJECTS observed status instead of deleting non-active rows, with an
out-of-band usage-drift backstop.
- force_reduce: ReconcileFedWikiQuotaActivity parks excess sites read-only
(keeping the most-recently-modified active) and reactivates on re-upgrade, run
each sync tick. Member "Keep active" swap with a 30-day per-workspace cooldown.
- Archive: member delete routes to the archived state (recoverable) with restore,
delete-permanently, and a 30-day retention purge.
- Operator FedWiki Sites tab surfaces site status. Docs (contract guide,
FARMMANAGER, wishlist) updated; status/issues force_reduce marked resolved.
Register FedWiki and Stripe providers at boot, persist provider
operations, and stamp owned resource keys.
Rename the FedWiki entitlement key from `sites` to `fedwiki_sites`
and drive the operator integration nav from provisioning providers.
Drop redundant schema prefixes from all sqlc-generated Go types. Since
each module generates into its own package, the package already provides
the namespace — billing.Account is unambiguous without
billing.BillingAccount.
Changes:
- Add rename: blocks to all 6 sqlc.yaml files mapping schema-prefixed
names to clean idiomatic names (e.g. BillingBillingAccount → Account,
IdentityPerson → Person, OrganizationOrganization → Organization)
- Rename billing.billing_accounts → billing.accounts (table name
repeated
the schema; the schema already provides that context)
- Rename integration.integration_outbox → integration.outbox (same
reason)
- Regenerate all sqlc output across billing, identity, organization,
entitlements, stripe, and fedwiki modules
- Update all calling code (server, workflows, provisioning, tests) to
use
the new names
- Add internal/db/sqlc_schemas.sql — sqlc-only schema declarations so
every module can resolve schema-qualified names without including the
full db migrations
- Update docs/database-management.md with the naming convention and
standard sqlc.yaml template
Convention going forward: table names must not repeat the schema name;
generated types carry no schema prefix; the Go package provides the
namespace (like http.Request, not http.HttpRequest).