docs(domains): make the runbooks true against the code - #97
Merged
Conversation
The AI-assistant catalog will be authored from these runbooks, so a wrong filter documented here becomes a wrong number shown to a user with no indication it is wrong. This is a truth pass, not an expansion. Method: a verifier per runbook that had to open the cited code before writing anything, then an adversarial auditor that tried to refute each edit with a file:line. The auditors caught 19 bad edits from the first pass -- including one that contradicted a commit already on main -- and those refutations were themselves re-checked before being applied. Two auditor findings were REJECTED after checking: the sales-orders status-downgrade paragraph and the returns customer-portal rows are responsive to real omissions, not overreach. The bigger corrections: - returns.md documented a status machine that does not exist. APPROVED / REFUNDED / EXCHANGED are not ReturnStatus members; the real chain runs PICKUP_SCHEDULED / PICKUP_COMPLETED / RECEIVED. It also documented a restockingFeePct field and a fee calculation -- grep for "restocking" over app/src and app/prisma returns nothing. Deleted rather than softened. - staff-auth.md said the permission layer "gates exactly one route". Recounted: of 337 Pages Router route files carrying either guard, 216 gate on a capability and 121 still gate on the role enum (8 use both). - pos.md described processorTxnId as unique with INSERT-on-conflict webhook semantics. There is no unique index; idempotency comes from a PENDING filter. - accounting.md named a SystemGLMapping section that does not exist and pointed the JE generator at a GET-only endpoint. - sales-orders.md told readers "the POS does not send statuses. Do not look for a status field." It does, and cancelled/returned are load-bearing. - reporting.md routed readers to 22 dead Pages-Router URLs and claimed the revenue-status filter was universal -- it was absent from four reports until #95, which this now describes. - config-presets.md said the roles preset controls which Role rows exist. applyPreset never deletes a Role; only rolePermission rows are replaced. Nine sentences were repaired that a scrubbing pass in the initial public release had mangled, replacing an order-number prefix with the literal phrase "the return prefix" -- e.g. "late-the return prefix-inside-period flagged", and in import-pipeline.md a prefix-swap rule reduced to "the sale prefix->the return prefix" three times. Rewritten to name the MECHANISM (isReturnOrder / RETURN_STORE_SUFFIX) rather than restore a tenant literal, which is the direction the rest of this work is going. Where the mechanism could not be located in code -- service-dispatch's order-number token -- the claim was dropped rather than guessed. Three code findings came out of the verification and are tracked separately: the warehouse returns queue and pickup endpoints have no role check behind role-gated pages (#53), isReturnOrder hardcodes one tenant's RS prefix (#52), and the default business timezone ships as America/New_York (#51). Verification state, stated plainly: accounting, sales-orders, returns, commission and reporting were adversarially verified by agent. staff-auth, pos and config-presets were verified by hand -- their audit batch died twice on API errors, so I re-derived the route counts, the REGISTER permission set, the absent processorTxnId index and the applyRoles delete behaviour directly. markdownlint + prettier clean. Formatting-only churn on the other 26 domain docs was reverted to keep this diff readable. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…merged Two claims described behaviour #96 removed, both flagged in that PR as needing confirmation once it landed: accounting.md said "only the date choice is timezone-aware" and named startOfDay/endOfDay's setUTCHours. Those helpers are gone; the source queries now use the half-open businessDayRange window, and the journal is matched on its date marker instead — a distinction worth stating, since matching the marker by that window would report every reconciled day as missing its entry west of UTC. seed-data.md said generateSalesJournal derives its window from date.setHours(...) in LOCAL process time, which is why the seed pins TZ=UTC. The window now reads AppSettings.timezone, so TZ=UTC still pins the seed's own Date construction but no longer governs the journal — and the default timezone is America/New_York, so a seeded payment near a UTC day boundary landing in the adjacent journal is the default case rather than an exotic one. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The AI-assistant catalog will be authored from these runbooks, so a wrong filter documented here becomes a wrong number shown to a user with no indication it's wrong. This is a truth pass, not an expansion — no new sections, no date stamps, no de-specifying real vendor names.
Method
A verifier per runbook that had to open the cited code before writing anything, then an adversarial auditor that tried to refute each edit with a
file:line.The auditors caught 19 bad edits from the first pass — including one that contradicted a commit already on
main. Those refutations were themselves re-checked before being applied, and two were rejected: thesales-ordersstatus-downgrade paragraph and thereturnscustomer-portal rows are responsive to real omissions, not overreach.The bigger corrections
returns.mdAPPROVED/REFUNDED/EXCHANGEDaren'tReturnStatusmembers. Plus arestockingFeePctfield and fee calculation; grep for "restocking" overapp/srcandapp/prismareturns nothing. Deleted, not softened.staff-auth.mdpos.mdprocessorTxnIddescribed as unique with INSERT-on-conflict webhook semantics. No unique index exists; idempotency comes from aPENDINGfilter.accounting.mdSystemGLMappingsection that doesn't exist; pointed the JE generator at a GET-only endpoint.sales-orders.mdreporting.mdconfig-presets.mdrolespreset controls whichRolerows exist.applyPresetnever deletes aRole.The mangled sentences
Nine sentences were repaired that a scrubbing pass in the initial public release had broken — an order-number prefix replaced by the literal phrase "the return prefix":
Rewritten to name the mechanism (
isReturnOrder/RETURN_STORE_SUFFIX) rather than restore a tenant literal — the direction the rest of this work is going. Where the mechanism couldn't be located in code (service-dispatch's order-number token), the claim was dropped rather than guessed.Code findings, tracked separately
/api/warehouse/returns/queueand/pickupsare baregetServerSessionwith no role check, behind pages that are MANAGER/ADMIN/WAREHOUSE gated. Customer names, phones and pickup addresses.isReturnOrderhardcodes one tenant'sRSprefix (shared.ts:210, commented "Returns Saybrook").America/New_York.Verification state, stated plainly
accounting,sales-orders,returns,commission,reportingstaff-auth,pos,config-presets— their audit batch died twice on API errors, so I re-derived the route counts, the REGISTER permission set, the absentprocessorTxnIdindex and theapplyRolesdelete behaviour myself rather than shipping them unchecked.markdownlint+prettierclean. Formatting-only churn on the other 26 domain docs was reverted to keep this diff readable.🤖 Generated with Claude Code