main
35
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
31ef519889 |
Skip files under testdata directories when stamping license headers
spdx-headers.sh stamped every tracked HTML file under internal/, the golden HTML files under internal/server/testdata among them, so a bare `make spdx-headers` would prepend a template comment to each and fail the tests that compare them byte for byte. It now skips every file under a testdata directory, since a test reads those as written. The Go fixtures under testdata that carry a header keep it, because the script only adds headers. Shown on two git archive exports made outside the working tree, each made a repository of its own so the script finds only the export. On the export of the parent, `make spdx-headers` stamped 98 of 1035 eligible files and left 98 changed paths under internal/server/testdata. On the export of this commit it stamped 0 of 934 eligible files and left no changed path. No Go file changes and no Go test runs the script, so no package tests were run; build, vet, gofmt, lint and the notebook-citations check pass, and the lint output is unchanged. Not probed: the script was not run in the working tree, because it resolves its root through git and would edit tracked files there. |
||
|
|
abb438bc71 |
Check a form declaration through named rule groups
CheckInvariants ran every rule of a form declaration in one function that gocognit scored 139. It now keeps its signature and its problem recorder and calls checkKindAndFamily, checkFamilyScope (which calls checkRowsScope), checkRoutes and checkWayOut, then the no-fields rule, then per field the no-name rule, checkFieldOrder, checkFieldStructure (which calls checkFieldPlacement and checkFieldWidth) and checkFieldCopy (which calls checkEscapeHatch and checkFieldDashes), and finally checkFormDashes. Each takes the recorder as addFunc. Every message and condition is unchanged and the rules run in the order they did; the two checkbox conditions became one, and the Select-or-Radio test is one local. The exclusion rule for CheckInvariants is deleted. Measured scores: CheckInvariants 5, checkFieldStructure 17, checkFamilyScope 13, checkFieldCopy 13, checkWayOut 8, checkRowsScope 7, checkRoutes 7, checkFieldDashes 6, checkKindAndFamily 5, checkFieldWidth 5, checkEscapeHatch 4, checkFieldOrder 3, checkFieldPlacement 3, checkFormDashes 3. Three things differ from the parent, none visible in a registered form: - The two dash checks range over ordered slices. Their maps gave a field's problems in map order, so the slices' order is one of the orders the maps could give, and the registry test's failures now come out in a fixed order. Each test is still strings.Contains(value, "—"). - The escape hatch's keys are checked in sorted order. A field with two refused keys gave its two problems in map order; they now come out in key order. No registered form carries a refused key. - ownedAttrs and its message "the field %q escape hatch carries %q, which the part owns" are deleted. A key reached that branch only after the data-/hx- prefix test, and no key of the map has either prefix, so no input reached it; the prefix rule already refuses all of them. The escape hatch's comment says why the hatch is narrow. The "steps wider than a half" branch of the width rule stays; no control reaches it today. scripts/deadcode-testonly.txt gains 13 entries for the new helpers, which only CheckInvariants calls and only tests call CheckInvariants. TestInvariantsEscapeHatchProblemsComeInKeyOrder is new: it checks, 20 times, that a field whose escape hatch carries style and class gets two problems with the class one first. No output change. Shown so: - go test over ./internal/forms, ./internal/server and ./internal/integrations/... gives 2144 test names and results at the parent, 2145 here; the only difference is the new test. None fail, one is skipped on each side. No golden file changed, so the message golden, the HTML goldens and the parse goldens read the same text. - The new test fails at the parent in 3 of 3 runs, because a two-key map ranges from the key written first most of the time, and passes here in 20 runs of 20 iterations each. - invariants.go's string literals are equal apart from the 21 attribute names and the message of the deleted map, and the import paths "maps" and "slices". - 20 break records (16 on the new side, 15 on the old; four dash and way-out records are written once per side because their text moved, and the sorted-keys record is new side only) are all caught by the existing message golden, and the sorted-keys one by the new test. - go run . lint prints the same line (91 routes, 53 URL refs), the lint snapshot gains and loses nothing, and scripts/deadcode.sh is clean. Not probed: the 46 messages' words beyond what the equal literal set shows; the deleted branch, which no input reached. |
||
|
|
d46a79db17 |
Delete LatestGenerations and its query
LatestGenerations and the LatestLifecycleGenerations query had no production caller: handlers read NextGenerations. Deleted with them: the query's generated method and row type (sqlc regenerated), the error text "latest lifecycle generations: %w", the struct tag `json:"latest_generation"` of the deleted row type (nothing read it), the deadcode list line for LatestGenerations, and the two assertions that used them, in the older-tab test and in the finish subtest of the lifecycle request query test. The NextGenerations check stays. sqlc-unused now counts 449 queries, one fewer, with none unused. Two assertions are NARROWER because their subject is deleted, and no fact is left unprobed beyond them: "LatestGenerations reports the highest generation and omits an instance with no request" and "LatestLifecycleGenerations names the later request's generation". No output changed. The deleted function was called by no code outside tests and took no lock, so no statement of any caller changes. The tests of ./internal/integration and ./internal/integrations/fedwiki/... give the same 302 names and results at the parent and here, each side run after a reset of the test databases. The kept break (the next generation no longer rises above the latest) fails the older-tab test at the parent and here. The lint snapshot differs by no key, and golangci-lint reports 0 issues. |
||
|
|
9e1954bb92 |
Keep in the lifecycle answers test what the answer golden does not hold
TestRecordLifecycleRequestAnswers_DB drops the assertions that TestLifecycleAnswers_DB now holds with whole answers and whole rows, on a fresh instance with its priors: the new request, the repeat while open with reordered keys, the three conflicts and the stored domain, another workspace's address, the busy answer, and the repeat after the finish. It keeps the instance identifier being a UUID, the two lookups, the finish matrix as a table, and the check that no desired-state outbox row is written. Its cognitive complexity goes from 31 to 10, and its allowance leaves the lint configuration. LifecycleAnswer.Accepted is deleted: its only callers were five of the dropped checks, each on a line whose kind comparison already decides the answer. The five checks are narrower than the kind comparison they sat on: the new request, the repeat while open, the conflict check (one line, run over other parameters, another operation and another person), the busy answer, and the repeat after the finish. LifecycleAnswerKind.String moves, body unchanged, to the package's test exports, where the answer golden and the failure messages print kinds through it. Neither is listed as test-only code any more. Tests that print an answer with %+v in failure messages only (the FedWiki package's tests in settle_db_test.go, reconcile_domains_db_test.go and usage_repair_db_test.go, and its web and workflows tests) print the kind's number there now, because String is absent from their test binaries. No result changes. Shown to change no output: the production change deletes two methods and moves one into test code; the answer golden is byte-equal; the test and subtest names and results of the integration package and of the FedWiki packages equal the parent's (299 results each side); all 12 listed breaks of lifecycle.go and its queries fail the old test at the parent and the new one at this commit; the lock key, the transaction wrappers and the content comparison are untouched. The lint snapshot adds and removes nothing. Unprobed: the five narrower Accepted checks above, because their method is deleted; the instance being a UUID (the column is uuid, so no one-line edit returns anything else), no outbox row written (no one-line edit makes recording write one), and accepted not being an outcome (two layers refuse it). |
||
|
|
208e10dd9d |
Replay recorded claim verification and push histories through one replay kit
Add internal/testkit/replay: Run and File replay a package's recorded Temporal histories against the workflows it registers, and Record writes them with stand-in activities. TEMPORAL_REPLAY_RECORD names a temporal CLI binary (the recorder starts a private in-memory dev server from it) or a running server's host:port; TEMPORAL_REPLAY_ONLY, a file-name prefix, records the files it names again. FedWiki's replay test moves onto the kit with its fourteen histories and every subtest name unchanged. Its two variables FEDWIKI_REPLAY_RECORD and FEDWIKI_REPLAY_ONLY are replaced by the two above, and its recorder skip message now reads "TEMPORAL_REPLAY_RECORD not set". The recorder now writes only the histories that do not exist yet, where FedWiki's used to rewrite every file; a recorded history stands for runs a release started, so replacing one takes TEMPORAL_REPLAY_ONLY. Claim verification gets nine recorded histories (activates, polls, check-now, expires, probe-error, mark-refused, record-fails, canceled, rollover) and the push workflow seven (applied, rose, divergent, conflict-then-applied, permanent, unlinked, gone), each replayed by TestWorkflowHistoriesReplay in internal/workflows/domains and internal/workflows/desiredstate. The kit has its own test over a two-step workflow and a recorded history of it. The 17 histories were recorded at the parent's code, from a private dev server started from the temporal CLI (1.5.1); the commands they hold match an earlier independent recording of the same scenarios, apart from the two clamped timers' durations. No file names the recording machine or its user. New tests: the kit's TestTarget, TestRecordsNeverReplaceAHistoryUnasked, TestRunReplaysARecordedHistory (and its two-steps.json subtest), TestFileRefusesAChangedWorkflow, TestEndingNamesWhatTheRunDid and TestRecordTwoSteps (skips); the import guard's subtest for internal/testkit/replay; TestWorkflowHistoriesReplay with its 9 and 7 subtests and TestRecordReplayHistories (skips) in the two workflow packages. The kit is listed in docs/testing.md and in the test-only deadcode list. No output changes: no production file is edited. At the parent and at this commit, the names and results of the section's packages are equal apart from the tests above (FedWiki's 16 results pass or skip as before), the Temporal surface listings (activities, workflows, workflow bodies, payload types) are byte-equal, go run . lint prints the same line, the lint snapshot has no added or removed key, and deadcode and golangci-lint are clean. Breaks: 9 breaks, each caught by the new tests; the 2 FedWiki breaks (a request-driven create and a create started before lifecycle requests that check the quota first) are caught by the old and the new test. Not probed: Histories and Run failing a test (no test can watch its own test fail; every production break above shows Run failing a subtest); connect, runScenario and write against a server, which run only when recording (the recording at the parent is their check). A replay cannot see activity inputs, timer durations, the result, or the ending of a history that ends canceled or failed; later tests pin those. |
||
|
|
11c9911667 |
Move the one-rule commit and the one-pool drain into the package's test exports
RuleChangeCommit and DrainObligation have no caller outside tests: the console commits batches through RuleChangeBatchCommit and drains through DrainChange. Both move, bodies unchanged, from rule_change.go to export_test.go, where each comment says which tests call it, and their two lines leave the test-only deadcode list. One test outside the package called DrainObligation. In TestSettleObligationOnSettledObligationWritesNothing the redispatch is now DrainChange over the change; it asserts the pass settles, fails and skips nothing and that the pool's effect rows are still what they were. This assertion is NARROWER: the old one checked that a drain of that one pool returned Skipped, a branch DrainChange's pending-only work list never reaches from outside the package. That branch stays pinned inside the package by TestRuleChangeCommitRecordsEffects. A comment in TestDeferredCommitHoldsNoPoolLock named RuleChangeCommit, which that package can no longer call; the sentence is dropped (docs correction riding along). The scenario comment of TestSettleObligationOnSettledObligationWritesNothing said a redispatched drain skips the pool; it now says the drain lists no settled obligation and does no work, which is what the rewritten assertion requires. The comment of DrainObligation names both tests that call it. No output changes. The names and results of internal/entitlements and internal/workflows/entitlements are equal at the parent and at this commit after a database reset on each side: 241 pass, 1 skipped, none failing. No golden changed. The lint snapshot differs from the parent's by no added finding and no removed one; the deadcode check passes with the two lines gone. Breaks: 3 records, each caught on the side it runs: the Skipped branch of a drain is caught by the old test outside the package and by the test inside it after the move (two records, one per side); the pending-only work list is caught by the new redispatch assertion alone, since the old Skipped assertion would pass with it dropped. Unprobed: the narrowing named above, because the Skipped branch is reachable only from inside the package. What the batch commit left unprobed is still unprobed, because the one-rule commit is still its one-element wrapper: the missing rendezvous kept in poolRefusal; the deactivation mismatch, the lock wait at the act and the lock wait of the pool listing; and the request id's value, since only its distinctness is tested. |
||
|
|
8cee42f2d3 |
Compare golden files and name a run's ids through one kit package
The server's golden helpers (the comparer, the -update flag and the normaliser that turns a fixture's ids into names) move into internal/testkit/golden, so any package's tests can compare output with a file under testdata. Ordinals is new: it numbers the UUIDs and UTC times an act makes by first appearance, for the ids a fixture cannot name. Normalizer.Add replaces the one place a server test appended to the normaliser's unexported pairs. Eleven server test files use the package; the -update flag keeps its name. docs/testing.md gains the kit row and a bullet, and the kit's import guard and the dead-code list know the package. No output changes. No production file changes, and no file under internal/server/testdata is touched; every server golden test passes without -update and git status is clean under testdata afterwards. The names and results of ./internal/testkit/... and ./internal/server are equal at the parent and at this commit (1452 and 1458 tests and subtests), apart from the five new tests and the import guard's new subtest for the package. No assertion changes, so no assertion map. 13 breaks: 12 caught by the new tests, and the one that renames the normaliser's <today> pair is caught by the golden test at the parent and at this commit. Unprobed: that a name outranks a pair in the server's goldens (their ids are UUIDs and their pairs a date and the suffix, which never start at one position, so the order is invisible there; the kit test probes it); the server copy of the comparer at the parent (a break that makes it pass everything cannot fail the goldens it compares); a migration test that defines its own update flag (a documented rule, not code). |
||
|
|
eedeb54bb5 |
Name the organization page's rows through the page's resolver
The organization page named each row with its own read: a product per delivery, a ladder and a tier per rung, an actor, a ladder and a tier list per tier change, an actor per entitlement change, and a ladder list per product in the Issue grant advisory. The page now makes one resolver after the organization read and every section names its rows through it, so each kind of name is one statement for the page (#10): the panel reads every pool's positions first and wants their products, ladders and tiers; Tier changes fold and page the rows before naming them, so only the window's rows are named; Entitlement changes want the page's actors; the advisory reads the tiers of the held ladders in one statement (productsOnLadders) and flags the products on them. The grants ledger takes the page's resolver in place of its own. The owner is still one GetPersonByID read, as before. GetTier is deleted with its last caller, and the resolver functions that now have a production caller leave the test-only list. One current-shape rule now names tiers here: a dash for a row with no rank, the product at that rank on the ladder as it is now, or "rank N" when no tier holds the rank. It replaces the page's own closure and its two caches. Accepted difference, named: a failed batch read now fails every id of its kind together (every delivery's product name, every ladder name, every rank, every actor), where one id could fail while the others resolved. Only an injected failure reaches it. The failure table's row for a failed product ladder read is NARROWER for it: the advisory's read is one batch over the held ladders, so the partial failure has no row. How it was shown to change no output: every golden under testdata/org_enrollment is byte-identical, and the tests of internal/server and internal/entitlements give the same 1588 names and results at the parent and here (1587 pass, 1 skip). The organization page's read-count row goes from 8 per row to 0. The failure table keeps its names and moves the method each row fails: actors to ListPersonNamesByIDs, products to ListProductNamesByIDs, ladders to ListPlanLadderNamesByIDs, and rank, tier labels and the product ladder row to ListTiersWithProductsByLadderIDs; the owner row still fails GetPersonByID. The operator walkthroughs give 22 equal names, results and skips at the parent and here. loadOrgEnrollmentData is re-pinned at 63, the score golangci-lint printed with a placeholder pin. Breaks: 76 records, 49 names, 51 run per side (26 on both sides, 25 old-only, 25 new-only); all 51 CAUGHT at the parent and all 51 CAUGHT here. Unprobed: which ids each section wants (only the page's rows; a wider want changes the batch's id list, not the statement count or the output); the sorted order of the batch's ids; the guard that skips the advisory's read when no ladder is held (an empty batch answers no rows, the same flags); the removed nil check on the identity querier for entitlement change actors (every test handler has one). |
||
|
|
a638f1145a |
Name grants through the request's name resolver
The grants page and the organization page's ledger drew each row with reads of their own: the organization, the product, the granting person and the floor product, once per row or per distinct id. They now name every id on the request's resolver (#10). wantGrantNames wants what the surface shows, buildGrantViewModels reads nothing per row, and each name keeps its fallback: no organization name, a blank product, "System" for the person, the revoke body's generic sentence for the floor. The grants page wants the organization of each row and the ledger the floor of a row whose revocation the floor would follow, so neither reads what it does not show. The ledger windows the rows of its tab before it names them. With a search typed it first reads the product names of the whole tab in one batch, because the search matches product names before the page is cut, as before. That is the one read beyond the rendered page, and it is one statement whatever the number of rows. OnActiveTab's switch moved to onActiveTab, which the ledger applies to rows before they are drawn. How the commit was shown to change no output: - internal/server and internal/entitlements give the same 1578 test and subtest names and results at the parent and at this commit (1577 pass, 1 skip), and every file under testdata/grants_listing/ and testdata/org_enrollment/ is unchanged. - Four read-count values changed, as intended: grants 5 to 0 per row, grants-ledger 2 to 0, grants-ledger with a search 2 to 0, and the organization page 9 to 8 (the ledger's product read left it). - 13 breaks, each run on both sides and caught on both: the grants page's organization, the granting person, the row's product, the revoke body's floor, a replacing grant outside the rows, a superseded row's replacement, the Active tab's two rules, the ledger search by reason and by product, the ledger's paging, and the two per-row read counts. - The gocognit pin of buildGrantViewModels went from 84 to 33, the score golangci-lint measured on the committed code. The six resolver functions this commit first calls from production left the test-only list. Test change: wantOwnerID looked for one link to the owner on the whole page. The rich fixture's owner also granted the ledger's grants, and the failing person read it injects used to blank that Granted by cell. The ledger now names granters in one batch the injected failure does not reach, so the cell links the owner as well. The check now looks at the Owner field's link. NARROWER than before: the page-wide check also held that a failed person read leaves the ledger's Granted by cells on their fallback, and that fact is no longer asserted here. NARROWER than before: a name read that fails now fails for every id of its kind on the page, where a per-row read failed for its own row alone. The test doubles fail a method by name, and no double fails the batch reads for these handlers, so that behaviour is not probed here. Unprobed: - The ledger's Granted by cells on their fallback when a person read fails: the injected failure fails GetPersonByID alone, the ledger names granters through the batch read, and no double fails that batch for these handlers. - A failed batch read on these two pages (above). How operator pages show a failed read is #207's. - The lineage label's branch that names a replacing grant by its own loaded row: it equals the row's product on every row the console writes, because an extension carries the product of the grant it extends. A later section adds a test that reaches it. - A grant with no organization: the old code skipped the floor read for it, and the resolver answers an empty id as unknown without a read; no fixture holds such a grant. - The old per-person and per-product memos: output-equivalent, since the resolver reads each id once. |
||
|
|
1e9755a8f0 |
Name the set history's actors through the request's resolver
The set's History section read each change's actor person with one statement per row. It now wants every row's actor on the request's name resolver and builds each row from it, so the section reads the names of all its actors in one statement however many changes the page lists. An absent identity querier leaves the actor unnamed as before; the resolver reads nothing through a nil querier. Narrower: a name read that failed for one actor alone, while the others succeeded, can no longer happen; a failed read leaves every actor on the page unnamed, as one failed read left its own row. The error is still discarded and no log line is added. Shown to change no output: 9 breaks, 4 written for the old code and 5 for the new, each caught by the test it names (the person's name, a failed read naming nobody, the absent identity querier, and the read-count row, whose per-row count goes from 1 to 0; the new side adds a break that drops the wanting, caught by the same row). The names and results of internal/server (1398 results) and of internal/entitlements (180) are identical at the parent and at this commit. The walkthroughs give the same 22 results at the parent and at this commit, and the screens match the baseline apart from the Stripe integration page, whose size changes on every run. The set-history test's failed-read case keeps its name and fails the read of people's names in place of the read of one person. Unprobed: a name read that fails for one actor alone, because the new code reads every actor in one statement, which cannot fail for one actor alone, so no test of this commit can produce it; the resolver's own behaviour (one read per kind, ids sorted, empty ids skipped), which the resolver's own tests hold. |
||
|
|
6979bd5647 |
Name the billing lists' and the lookup's organizations through the request's resolver
The accounts, subscriptions, invoices and payments lists, and the lookup's invoice candidates, read one organization per row. Each now wants its rows' organizations from the request's name resolver before the row loop, which reads them in one query, and the loop looks each row's organization up in the result. A page with no rows reads nothing. A failed read names no row, so the lists show the empty name and the lookup shows the organization's id, as a row whose own read failed did. The per-row count of the four lists and of the lookup in TestOperatorPagesReadAFixedNumberOfTimes goes from 1 to 0. The resolver's newOperatorNames, both names methods, WantOrgs, Org, readOrgs and the batch's want, lookup and flush now have a production caller, so their test-only dead-code entries are removed. Shown to change no output: 36 breaks of the organization reads, 16 run on the parent and 21 on this commit (one is run on both), each caught by the test that pins it. The eight golden files of the four lists are unchanged and no -update ran. The names and results of internal/server and internal/testkit (1435 results) are identical at the parent and at this commit. The walkthroughs match the baseline (22 of 22) and the screens match it apart from the Stripe integration page, whose size changes on every run. The lint snapshot differs from the previous one by nothing. Narrower than before: a failure of one row's organization read alone cannot be shown any more, since one query cannot fail for one row. Unprobed: the billing lists' ok test, because their fallback is the empty name, which is also what the resolver answers when not ok; a missing organization querier, which the resolver answers as unknown and which no test of these pages sets. |
||
|
|
3c65fa4e6e |
Read each billing list's Stripe mappings once per page
The accounts, subscriptions, invoices and payments lists read one Stripe mapping per row. Each loader now reads its page's mappings in one query before the row loop (ListCustomerMappingsByBillingAccountIDs, ListSubscriptionMappingsBySubscriptionIDs, ListInvoiceMappingsByInvoiceIDs, ListPaymentMappingsByPaymentIDs) and the loop looks each row up in the result. A page with no rows reads nothing, and the payments list still reads nothing without a Stripe querier. A failed batch keys nothing, so every row shows not mapped, no Stripe id and no badge, as a row whose own read failed did. GetPaymentMappingByPaymentID had no other caller and is deleted. The per-row count of the four lists in TestOperatorPagesReadAFixedNumberOfTimes goes from 2 to 1 (the organization name is still read per row). The name resolver's indexBy now has a production caller, so its test-only dead-code entry is removed. failingMappingsStripeQ overrides the four batch reads in place of the four single-row reads; its subtests are unchanged. Shown to change no output: 39 breaks of the mapping reads, 15 run on the parent and 24 on this commit, each caught by the test that pins it. The eight golden files of the four lists are unchanged and no -update ran. The names and results of cmd, internal/fulfillment, internal/integrations/stripe, internal/server and internal/testkit (1758 results) are identical at the parent and at this commit. The walkthroughs match the baseline (22 of 22) and the screens match it apart from the Stripe integration page, whose size changes on every run. The lint snapshot differs from the previous one by nothing. Narrower than before: a failure of one row's mapping read alone cannot be shown any more, since one query cannot fail for one row. Unprobed: the payments list's empty page, because its batch is guarded on the Stripe querier and the test that checks empty pages sets none; the lines that fill the Stripe id, the sync state and the badge, which this commit does not edit and the golden pins; the demo seed writes no Stripe mapping, so the screens show only the unmapped branch; the payments list's guard on a missing Stripe querier, because no test loads a payments page that has rows and no querier (the start command sets the querier whether or not a Stripe key is configured; a page without one would show every row as not mapped). |
||
|
|
e0f9bc9f1e |
Add the operator pages' request-scoped name resolver and its batch queries
Five sqlc queries read the names one operator page shows in one statement each: people, organizations (with their type), products, plan ladders, and the tiers of several ladders with their products. operatorNames collects the ids a page wants, reads each kind once on the first lookup, and answers (name, ok) so a caller keeps the fallback text it shows today for an id with no row or a failed read. tierLabel is the one current-shape rule for a rank on a ladder. Nothing calls the resolver from production yet, so no page's output, status, header, redirect, write or log line changes; the functions only tests reach are listed in the test-only deadcode file until a page adopts them. Shown by: the generated Querier rows match the single-row reads they batch (ListTiersWithProductsByLadderIDsRow equals ListTiersByLadderWithProductsRow), sqlc-generate run twice leaves no diff, and the packages the commit touches pass on a reset test database. New tests: TestOperatorNamesReadEachKindOnce, TestOperatorNamesAnswerNotOK, TestOperatorNamesTiers, TestOperatorNamesFloor, TestOperatorNamesReadTheDatabase. 25 breaks, each caught by the new tests. Unprobed: the ORDER BY of the tier batch query (callers index by map), the per-id narrowing (one statement cannot fail for one id), every caller's fallback text (each adopting page probes it), and that the resolver logs nothing (it holds no logger). |
||
|
|
619963abff |
Split member_products.go into the five files the layout names
member_plans.go holds the handler, the plan view models, the plans page and the cancel prediction; member_plan_moves.go the switch, keep and cancel handlers; member_entitlements.go the entitlements panel; member_addons.go the add-ons page; price_text.go the price renderers. Every declaration moves with its comment, in its old order. The two section banners that divided the old file are not carried over. Comments that named member_products.go name the file that now holds what they cite. No output changes. The multiset of top-level declarations of package server, each printed with its doc comment, is equal before and after; every line of the old file other than the two banners appears in the new files, and the new files add only headers and imports. gofmt, build, vet, the console lint and the lint snapshot (removed 0, added 0) are clean. The internal/server and fedwiki packages pass on a reset test database. The break list is the last new-side record of each break name from the earlier sections whose text still exists, re-pointed to the destination file: 160 records, all caught on this commit. Five names are dropped because later sections replaced their text: the rung carries its provision, the flagged cancellation's date, a failed attachment read refuses the page, a failed attachment read refuses Checkout, an organization without a pool holds no paid subscription. Two stay out because they were missed in their own section: an unmapped price offers no enabled Checkout, and an organization without a subscription gets no switch confirmation. |
||
|
|
f8f9551ddd |
Build the FedWiki tests' fixtures through the kit
Adds internal/testkit/world (New, Providers, Person, Org, Workspace,
Product, Rule, Confer, Person.SignIn), internal/testkit/authtest
(NewSessionManager, SignIn) and internal/integrations/fedwiki/fedwikitest
(the environment, tenant, limit and usage, operator root, site rows), and
moves the FedWiki fixtures onto them: newReqEnv, setupQuotaFixture,
newReconcileTestEnv, siblingWorkspace, governFedwikiLimit (Product, Rule,
Confer, no materialization), newSiteEnv, newClaimTestDB (its raw provider
insert goes), seedOperatorSites, newMemberWorkspace, seedUnderstatedQuota,
newTestWorkspace, seedCountedWorkspace and addSiblingWorkspace.
newReconcileDomainsDB and setupReconcileRoot had nothing left to move. The
six sessions the FedWiki web tests build go through authtest. The import
guard covers the three packages, and scripts/deadcode-testonly.txt lists
them.
The six hand-written lock-wait loops become dbtest.AwaitLockWait
(lifecycle_db_test.go, registration_db_test.go, invoice_reconcile_test.go,
stamp_db_test.go, and the two record-swap tests in requests_db_test.go and
swap_record_db_test.go). Backend gains BlockedBy, Query and Abort. The
registration loop is not a verbatim move: its select matches by query text
within the current database and its done check becomes the Abort probe, as
do the two record-swap loops, each keeping its message ("registration
finished (%v) while the first key was held", "the record finished without
writing the activated site's status: %v", "the record finished without
waiting on the parked request: %v"). Kept weaker on purpose: the
never-waited messages are now the helper's, which names the selection
("backend N never waited on a lock" for the pid loops, "no backend waited on
a lock held by backend N" for the record swaps, "no backend running a
statement containing %q waited on a lock" for the registration and invoice
loops), the record-swap and stamp bounds are the helper's ten seconds (were
the tests' thirty), the stamp loop accepts any waiting count (was exactly
one for its pid), and the invoice loop matches the statement text anywhere
in the query (was its prefix). TestDispatchStampsLockRecordsInOneOrder drops
from cognitive complexity 39 to 31; its pin is re-pinned to 31.
Names and results of the three FedWiki packages, internal/integration,
internal/workflows/desiredstate and internal/integrations/stripe/workflows
equal the parent's apart from the new tests (the import guard's forbidden
list with its three subtests, and the lock helper's selection test with its
three subtests and its Abort test) and one change: the three
TestReconcileDomains* tests in internal/integrations/fedwiki now pass on a
freshly reset database. They failed there at the parent, alone and in the
package run, because nothing had registered FedWiki; the fixture now does
(#33).
Fixture equivalence (each fixture run alone on a reset database, every table
of core, fedwiki and domains dumped before and after). Differences, none
read by an assertion: names and addresses carry the builder's shape
(organization "<name> <suffix>", email "<name>-<suffix>@example.test",
subject "sub-<name>-<suffix>"; the display name is the label for tenant
fixtures); the pool is the organization's default pool (name "Default", key
default, auto-managed) where the fixtures wrote a bare one; a workspace now
sits in the organization's default pool through a pool assignment where
newMemberWorkspace, seedOperatorSites and the claim fixtures wrote neither
(seedOperatorSites gains two pools and two assignments); every FedWiki
fixture registers FedWiki and the System tenant, which adds the provider row
(or fills operator_surface_path on the row a claim fixture inserted), the
operations, connection, state and outbox rows, the System tenant's user,
person, 'system' organization type, organization and workspace, and
refreshes the fedwiki_sites resource key; archived sites carry archived_at,
as the status query sets it; sites are minted under a database-minted id;
governing a limit goes through the rule-change function, which adds a
set-change row. Claim tokens are random in both.
25 breaks: 19 failed the old test at the parent and the new test here (one
code break per FedWiki test file in the function it pins, and one per
converted lock wait with the lock removed; the three loops with an Abort
probe fail through it with their own message), and six on the kit alone
failed the new test. No assertion in a test body changed.
|
||
|
|
254bc4ccb1 |
Count the test kit's query calls as test uses
scripts/sqlc-unused counts a call from a package covered by a ".*" entry of scripts/deadcode-testonly.txt as a test use, so one list defines the test-support packages for both checks, and the list's header says so. A query that only the kit's builders call now reads TEST-ONLY, not used. The check reads the module in a directory it is given, which lets a test run it over a fixture module. New tests: TestScanCountsATestSupportPackageAsTestUse, over a fixture module whose kit package and app package each call one query, and TestReadSupportTakesTheWholePackageEntries. The other tests, TestCheck and TestReadAllow, are unchanged. The output of go run ./scripts/sqlc-unused equals the baseline taken before step 2 once each line's count of test references is stripped. 2 breaks, each failed the new tests; they have no old side. |
||
|
|
1f0c697387 |
Check the shell through the HTML query helper
internal/testkit/htmltest parses rendered HTML and selects from it with CSS selectors (Parse and ParseIn, One, All, Count, None, Text, Texts, Attr, HasClass, HTML, Before, InOrder), on golang.org/x/net/html and github.com/andybalholm/cascadia, which joins go.mod as a direct requirement (BSD-2-Clause, pure Go, depending only on x/net). A page, which opens with a doctype or an html element, parses as a whole document, so the attributes of its html and body elements are kept; any other body parses as a fragment, a table row under a tbody, an option under a select and anything else under a body. Both parse with scripting off, so what a noscript holds is elements that selectors reach, as a browser without JavaScript renders it. Its own tests: the fragment context for tr and option, the attributes of html and body, the content of noscript, One's failure message naming the selector, None, Text, selection by attribute and role, Before, and InOrder. The import guard gets a row for it, and scripts/deadcode-testonly.txt an entry. harness_test.go gains the shell assertions both surfaces share, exported for server_test: the top bar, the account menu, the Identity and Access handoff, the drawer and the rail's account block. member_nav_test.go and operator_sidebar_render_test.go select regions by landmark and ARIA (nav.navbar[aria-label=Account], aside#app-rail, the account group's aria-labelledby list) and controls by attribute ([data-form="shell.confirm"], the button posting to /logout) instead of regionBetween, topBarRegion, railRegion and sidebarRegion, read aria-current on each member rail entry and on both surface switches, check order through InOrder, and keep a class assertion only where the class is the fact. sidebarSections selects the entry list instead of slicing the rail string, and sidebarLinkActive reads the link node instead of matching a regular expression. The page subtests of TestShellAccountMenu and TestShellMemberRail call named functions (checkAccountMenuPage, checkMemberRail); every test and subtest name is unchanged. Each ban and each count keeps the region the old one covered, or a wider one; a check that an element is present looks where the element belongs, such as the trigger and the Get help order in the bar and the entries in the rail, which is narrower than the body the old strings searched and stricter. A bar, a rail or a page the old tests searched as a string is searched as markup (Node.HTML) where the old string covered the element's own tag, the html and body start tags, or an attribute: the rail's d-lg-none count, app-rail-signout, d-none d-lg-flex, the identity tooltip, the operator rail's nav-link count and its ps-4, group and /logout bans, text-danger, navbar-collapse, the handoff explanation, mt-2 pt-2 border-top, and the bar's bans over everything before the rail. Counts that were page-wide stay page-wide: the account menu (any tag), the Get help item, the Operator panel switch, the dismiss control, the hx-post="/logout" controls (counted as markup, so data-hx-post counts), the bans on href="/logout" (markup, so any attribute ending in href counts) and the account-console links; those inside the rail are counted over the whole rail before they are placed in the account group: the group's name and email spans, its list, the Identity and Access, Sign out and Get help entries. The Dashboard link count and the Operator link ban also run over the page's markup, the drawer's two lists are counted by class prefix as well, and nothing before the account group reads Sign out. Where the old tests pinned an element's class as an exact string, the new ones compare its class token set exactly (AssertClassSet), which ignores token order only; the checks that were prefixes or regular expressions stay HasClass or class selectors, and an active operator entry must still carry nav-link. aria-current appears on the active rail entry and nowhere else in the member rail, and on neither surface switch nor the account group's entries. Sign out, Get help and the account group's name and email stay plain text, the trigger's one child is its label span, the menu header's children are the line break and the email span, and the line break follows the name. The closing </main> check stays a text check, since a parser closes the element anyway. One weakening is general: a markup change that alters no asserted fact no longer fails, such as an attribute added to an element the old tests matched as a whole markup string (a data attribute on Sign out, say), a wrapper, or a decorative child the comments do not exclude. No specific fact is kept weaker. The four gocognit exclusions of TestShellAccountMenu, TestShellMemberRail, TestShellRailAccountBlock and TestOperatorShellTopBarAndDrawer are gone; the lint reports nothing in their place. 124 breaks: 118 failed the old and the new shell tests (the template and code changes that move, drop or mislabel each asserted element; an untitled Get help item in the bar, the drawer's header and the rail; a Log out title on the brand link; an extra class on Sign out, on the email span, on the switch's li and on the page title; a missing class on the rail or on an account entry's li; a button among the rail's entries; a surface label, a Get help link or a danger Dashboard link between the bar and the rail; a logout button in the drawer's header or a logout form among its entries; the tooltip on the li or on the account trigger; an Operator panel label for a member without the role; a noscript holding a second main, a Dashboard link or a Sign out link to /logout; a data-hx-post Sign out in the content or the menu, and a data-href to /logout; aria-current on a surface switch or on Identity and Access; an active Billing entry without nav-link; a second account-console link or Identity and Access item; an element inside Sign out, the trigger, the menu header or the group's name; a class on the rail's own tag, on the html or body tag, or a second element where the old string counted one: the account menu, Get help, the Operator panel switch, a plain Sign out, the group's name and email, its list; a Sign out button before the account group on either surface; a Dashboard or an Operator link with a decorative child in the content; a third nav list; a bar without its navbar class), and 6 on the helper's own tests have no old side. The names and results of internal/server equal the parent's; new tests: TestParseKeepsRowsAndOptionsThatABodyContextDrops, TestParseKeepsTheAttributesOfHtmlAndBody, TestParseSelectsInsideNoscript, TestOneFailureNamesTheSelector, TestNoneFailureNamesTheSelectorAndQuotesTheMatch, TestTextCollapsesWhitespaceAndSelectsInDocumentOrder, TestSelectionByAttributeAndRole, TestBeforeHoldsWhatPrecedesTheMatch and TestInOrder in htmltest, and the guard's htmltest subtest. |
||
|
|
e8b78d93a7 |
Render the member, root and part tests through the member constructor, and delete the old set helpers
MemberSet joins OperatorSet in harness_test.go. The member, root and parts-only sets in the server tests go: rootTemplates, errorPageTemplates, renderIndex, renderEntitlements, memberTestTemplates, renderMemberDomains, the inline set in the member invoices test, the parts-only sets of the form-part and help-icon tests, and renderMember, which now calls Render on MemberSet. partsSet and renderPart go with them; the part tests render on OperatorSet, because they assert the operator crumb, and read the error of TestPageHeaderRejectsCountAndAction from ExecuteTemplate directly. The set of error_page_test.go that has no error.html stays synthetic. With the last test callers gone, web.ParseUIPartials, server.helpIcon, server.OperatorSurfaceRoot, server.MemberSurfaceRoot, server.rootLink and the server.HelpIcon type are deleted, with their scripts/deadcode-testonly.txt entries and the comments that described them (the partials' header comments now name the surface constructors). The names and results of internal/server and internal/web equal the parent's. 12 breaks (one per helper replaced, a text change in the template its first caller renders), each failed the old and the new test. |
||
|
|
d104ad91fe |
Build the member surface's templates in one constructor
web.MemberTemplates builds the member set from CoreTemplates and each integration's Mount, and composeUITemplates folds into it; operator.html and the operator-side integration files leave the root set. Start and the six member handlers call it. TestComposeUITemplates moves to internal/web as TestMemberTemplatesMounts, its subtests keeping their names except the last, now "template name without a key prefix is an error" (the constructor returns the error and Start panics through template.Must). New tests: TestMemberTemplatesHoldTheMemberFiles. 1 command break, caught by make screens on the new side; the constructor is new, so no old run. |
||
|
|
811fbdd26d |
Build the operator surface's templates in one constructor
web.OperatorTemplates builds the operator set from CoreTemplates and each integration's Mount, registering the whole function map before it parses; the four operator handlers call it. New tests, in internal/web: TestOperatorTemplatesHoldTheOperatorFiles, TestOperatorTemplatesParseASharedPartOnce, TestOperatorTemplatesRefuseAMountFileWithoutItsKeyPrefix and TestParseSourcesRefuseTwoFilesWithOneBaseName. 1 command break, caught by make screens on the new side; the constructor is new, so no old run. |
||
|
|
d1ac278e6b |
Open every test database through dbtest
internal/testkit/dbtest opens TEST_DATABASE_URL and E2E_DATABASE_URL, never migrates, and fails with "the test database is behind; run test/reset-test-db.sh" when the core ledger lacks the highest version of db.BaseSources(). The opener helpers except the scratch-database and container openers (26 of the 29) and the inline openers of the database tests call it; helpers that did more than open (providers, fake farms, the FedWiki provider row, cleanup of override rows) keep that setup. The stripe/workflows and workflows/entitlements openers keep their search_path through WithSearchPath. The closed-database seam tests use Closed. TestMigration18SetsExistingFedwikiRulesToForceReduce runs on a scratch database through Scratch and UpTo instead of rolling the shared core ledger back through goose's global state, because no opener migrates the shared database any more. The in-package forms tests of internal/server reached the integrations' forms only because an external test file imported internal/migrate; a test file now links internal/integrations explicitly. TestRegisterProviders_DB is re-pinned from gocognit 37 to 34. New tests: TestLedgerCheckRefusesAnEmptyDatabaseAndAcceptsTheTestDatabase (dbtest), TestOpenRefusesAnEmptyDatabaseAndAcceptsTheTestDatabase (dbtest, through opened, the path Open and OpenE2E share), TestKitPackagesReachOnlyTheirAllowedModulePackages (testkit). The skip messages of the openers are unified to "TEST_DATABASE_URL not set, skipping integration test". 4 breaks: Open skipping its ledger check and the ledger check accepting an empty database fail the new tests; a kit row that no longer allows internal/testkit fails the import guard; leaving the fedwiki rules as they were in migration 00018 fails the migration 18 test on both sides. |
||
|
|
2bc0bd1610 |
Add a tool that applies deliberate breaks one at a time
scripts/mutation-check reads a JSON list of breaks, applies each to the tree one at a time, restores the file byte for byte, and reports CAUGHT, MISSED, WRONG-MESSAGE, NOT-FOUND, SKIPPED or CONTROL-FAILED for each. New tests: TestApplyAndRestoreAreByteExact, TestOldTextMustOccurOnce, TestSidePicksPatternAndMessage, TestARecordWithASideRunsOnlyThere, TestOutcomes, TestStatelessListStopsOnAFailingControl, TestControlRunsOncePerDistinctTest, TestStatefulListPreparesAndControlsEachBreak, TestStatefulControlFailureMarksOnlyThatBreak, TestPrepareFailureStopsTheList, TestCommandRecordsAreClassifiedByExitAndText, TestCommandRecordReadsTheInspectedFileAndNeverAStaleOne, TestCommandControlFailsWhenTheTextIsAlreadyThere, TestSummarizeExitsOneUnlessEveryBreakIsCaught. |
||
|
|
d7815d3603 | Draw the Products page and the add-ons list from the decision | ||
|
|
2e1617cf4d | Add the offer decision and its table test | ||
|
|
d448afcfdd | Pin the exception list and run every check in make lint | ||
|
|
75f0572dfb | Add the gate's configuration and tools | ||
|
|
d807446ef4 |
Update allowlist and default models for Kimi and OpenRouter
- Add kimi.ai and openrouter.ai to allowlist for egress - Replace kimi-for-coding with kimi-code-plan-global in DEFAULT_MODELS |
||
|
|
56e65b669c |
Read invoices back from Stripe and archive the change
Stripe delivers webhook events in the endpoint's API version. Under a version later than the 2025-02-24.acacia stripe-go v81 pins, the payload-shaped invoice handlers projected every invoice with no subscription link and no lines, and every payment with no payment intent or method. - Invoice events read only the invoice id and run ReconcileInvoice, which reads the invoice, its lines and its payment intent's charges back at the pinned version and converges the core rows under a per-invoice lock, in any event order. A payment row is one attempt, keyed by its Stripe charge (Stripe store migration 00005). - Two clocks: created_at is when the console wrote a row; invoices gain issued_at and payments paid_at (core migration 00022, backfilled), and every invoice and payment list, the activity feed and the composite's latest invoice read those. - An hourly and at-boot invoice sweep reads back invoices never read, open invoices once a day, and invoices of dead-lettered events; the provider page states when it last finished. The first run is the repair of invoices projected so far. - The API version skew is logged once per version, and payment_method.attached links payments recorded before it. - A restricted key now needs Invoices read and Charges read. - scripts/db-reader-role.sql maintains console_reader, a login role that reads the console's tables without personal data, documented in docs/database-management.md and checked against a golden column list by TestConsoleReaderColumns. The demo snapshot keeps owners and privileges so the role's checks hold on it. - The demo seed and test fixtures carry issue and paid times. status/design-feedback.md gains four upstream notes, one written when #60 was closed. OpenSpec change stripe-invoice-reconcile is archived and its deltas synced into openspec/specs/. Follow-ups are #150, #151 and #152. |
||
|
|
b245bdb0a9 |
Fix security audit findings from 2026-09-21 scan
Remediate six confirmed security issues: deployment-only config keys, bounded provider responses, short-lived registration sessions, private init file mode, FedWiki workflow authorization, and switch preview gates. - Add DeploymentOnly config key declaration; refuse runtime overrides for keys that decide where secrets are sent - Create httplimit package; bound all provider response reads at 8 MiB - Set fifteen-minute deadline on /register sessions - Write mc-config.yaml with 0600 permissions - Derive FedWiki workflow IDs from site IDs; re-authorize sites before mutating activities - Apply switch authorization gates to the proration preview |
||
|
|
bea0ffc024 |
Add Codex CLI harness to agent runner
Support Codex CLI as a second agent harness alongside opencode, with per-harness credential mounting, model routing, and reasoning effort handling. |
||
|
|
0c78d5f425 |
Move issue tracking to the forge tracker
Replace status/issues.md and status/milestones.md with the Gitea forge tracker, add issue templates, and archive pre-forge issues as YAML. |
||
|
|
5829091881 |
Track the agent runner and its method page
The contained runner that drove the 2026-09 security audit, the README review and four rounds of design ideation lived only inside the ignored notebook. It moves to scripts/agent-runner/: the prepare, tools, audit, ideation and teardown scripts, the compose and container files, the allowlist proxy and the prompt templates, with the paths that assumed the notebook fixed and findings written to a caller-named directory. Run outputs, transcripts and the round-specific sheet scripts stay behind. docs/agent-runner.md states the method: the disposable git archive copy and the fail-closed proxy, how a task is shaped, union rather than intersection of findings across models, separate adjudication of every finding against the source, and the evidence a finding must carry. |
||
|
|
a5a4b9c591 |
Gate archives on notebook citations and add the harvest skill
A notebook's lessons survive only if they are written into a tracked home before the decision lands, so landing a change now has three pieces. The contract: a "Landing a change" section in MAINTAINING.md and a fifth item in the UI definition of done. The labor: a harvest skill that inventories the notebook, names each file's kind and routes findings to the owning docs page, reasoning to the change's design.md, problems to issues.md and reusable tools to a tracked home. The gate: scripts/notebook-citations.sh, a git grep over what git would commit for the notebook's directory shape, which make lint runs after the program's own lint, and scripts/archive-gate.sh, which refuses an mv into the archive or an openspec archive while the check reports hits. The gate is one script that any harness calls with the command it is about to run; Claude Code reaches it through a PreToolUse hook and opencode through a plugin. Both checks live in scripts/ rather than the lint subcommand because they are repository hygiene, not part of the shipped program. The generated openspec-archive-change skill is not edited; the post-archive reminder carries the harvest step instead. |
||
|
|
fe19ee415c |
Add CLA and SPDX headers, fix docs
- Pin Dockerfile to Go 1.23 to match go.mod - Record README front-door audit findings |
||
|
|
88db730fcc |
Add dual licensing and SPDX headers
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. |