docs: the position census disagrees with itself in three places — README says seven over a table of six, DESIGN.md §11 says both 7 and 8 - #69
Merged
Conversation
The tree defines seven positions and five permission sets. Four passages across README.md and DESIGN.md stated that census and only two were right. README.md's operator setup table promised "the seven positions" over seven rows whose seventh was `(business requesters)` — a default permission set, not a position — while the seventh real position, `clm_admin`, was absent. The count reconciled arithmetically (6 positions + 1 set row = 7 rows), which is why it survived. Two costs: an operator following it literally never assigns `clm_admin`, and a non-position sat in a column headed `Position` whose values are typed into `sys_user_position.position`. Add `clm_admin` as the seventh row and move the requesters out of the table into a paragraph that names the mechanism they actually use — a `sys_user_permission_set` grant, a different object from `sys_user_position` (`src/profiles/requester.profile.ts` documents the distributed default: `isDefault` cannot be used because the set carries a system permission). The `Position` column now contains only real `CLM_POSITION` values. An operator SHOULD assign `clm_admin`: `src/security/bind-position-sets.ts` binds that position to `AdminSet`, the only set carrying `clm_admin.access`, which gates the app's Administration group (`src/apps/clm.app.ts`), and the only set that may write `clm_contract_type` and `clm_approval_rule`. The dev admin deliberately holds no `clm_*` set, so without this row the demo has no account that can maintain the configuration objects. "The other five positions" follows the table: 7 - 1 exactly-named = six. DESIGN.md §11's M1 row said `8 position / 6 set`; the layout block four lines above it already said `7 position` and `5 permission set` and is untouched. §10's seeding sentence, found by the grep this card mandates, carried the same defect as the README table: `业务承办 ×3` listed inside a position enumeration with `clm_admin` absent. DESIGN.md §01-§04 and §09 are untouched: the only changed lines are 327 and 352. No gate reads either file, so none can have moved. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01R3n3GGzobdegM4HUzah1iR
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.
Fixes #58
Four passages stated the position/permission-set census. Two were right, and this PR makes the other two agree with the tree. The fourth was found by the grep the card mandates and is called out below.
Claim to reading
Every count in this body, and every count the diff writes, backed by a reading taken on this branch.
src/sharing/positions.ts,CLM_POSITION:clm_legal_counsel·clm_legal_head·clm_finance_controller·clm_executive·clm_general_manager·clm_records_manager·clm_adminsrc/profiles/index.ts— 5 exports;grep -c "name: 'clm_" src/profiles/*.profile.ts=clm_admin·clm_finance·clm_legal·clm_records·clm_requestergrep -c 'defineSharingRule({' src/sharing/contract.sharing.ts=6ls src/objects/*.object.ts | wc -l=11Positioncolumn holds exactly the 7CLM_POSITIONvalues — each one checked back againstpositions.ts, all 7 present, nothing else in the columnclm_legal_counsel) = 6Business Requester 1..3+Legal Counsel 1..2= 5 accountsclm_adminis the only set carryingclm_admin.accessgrep -rn 'clm_admin.access' src/— one declaration,src/profiles/admin.profile.ts:40src/apps/clm.app.ts:283—requiredPermissions: ['clm_admin.access'], childrenclm_approval_ruleandclm_partyclm_adminis the only position that may writeclm_contract_type/clm_approval_ruleallowCreate: false, allowEdit: false, allowDelete: falseon both;admin.profile.tsdeclaresconfig(CRUD)clm_adminposition is the only route to that setsrc/security/bind-position-sets.ts,BINDINGS:[CLM_POSITION.admin, AdminSet.name]src/profiles/requester.profile.tsheader: "an employee who holds no position receives the set in Setup (asys_user_permission_setgrant), which is the platform's supported path"The two judgement calls
1. How
(business requesters)stops sitting in aPositioncolumn. Moved out of the table into a paragraph directly under it, not into a second row group or a second table. The reason is that it is not a weaker kind of position — it is a different object. A position is asys_user_positionrow keyed by name; the requester default is asys_user_permission_setgrant.requester.profile.tsdocuments why it cannot be implicit:isDefault: truewould auto-bind the set to theeveryoneanchor, but the set carries a system permission, so the runtime refuses the binding andos lintrefuses the declaration outright. A row group inside the same table would still invite the reader to type the value intosys_user_position.position, which is exactly the failure the card names. The paragraph says the object and the screen instead, and keeps the row's three facts (three accounts, the defaultclm_requesterset, launches contracts and sees their own).2. Whether an operator should assign
clm_admin. Yes — and this is the more consequential half of the fix. Not merely because seven is the true count, but because the section as written left the demo with no CLM administrator at all:clm_adminis the only permission set carryingclm_admin.access, and theclm_adminposition is the only declared route to it (bind-position-sets.ts).group_adminand its two items are served to no one — a whole navigation group invisible in the demo.clm_contract_typeandclm_approval_rule; the other four are read-only on both. So nobody could maintain contract types or the approval matrix.clm_*permission set", servednavigation: []. That paragraph is correct and stays — but it means the one accountpnpm democreates cannot be the administrator. A real administrator account is precisely what the section was missing, and the card's own framing agrees.The new row states what it actually grants, in the position's own words from
positions.tsplus the two reach facts above.The fourth occurrence
The card asks for every occurrence, not the three it names.
grepping both files for position and permission-set counts turned up a fourth inDESIGN.md§10:Same defect as the README table, both halves:
业务承办 ×3sits inside apositionenumeration although it is not a position, andclm_adminis absent. It also contradicts its own document — governed §04 already says "Position 扁平,七个" and "clm_requester(所有员工默认)". Fixed in the same shape as the README, one line. Leaving it would have satisfied the card's §11 acceptance while the document still disagreed with itself about exactly this. Flagging it explicitly since it is outside the three the card names — drop the hunk if the seat would rather it were its own card.Two passages were already right and are untouched: §11's layout block (
5 permission set · 7 position · 6 sharing rule · FLS) and §04's census.Scope
DESIGN.mdchanged lines are 327 and 352 only (git diff -U0hunk headers). §01–§04 spans lines 24–205 and §09 spans 293–309 — both untouched, and no other §11 row is touched.DESIGN.md§09 still specifies 各阶段合同数**漏斗** — the app stopped shipping a funnel in #48 and narrowed what it plots in #59 #63 is unaffected.Gates
All four run in the foreground, each redirected to its own file with the exit code read immediately, no pipe between the command and
$?.pnpm validate0pnpm lint0pnpm typecheck0pnpm lint:i18n-gate0lintends21 warning(s), 5 suggestion(s) (994ms),validatecarries its carrier-only field notes — both pre-existing onmain, both warnings, both exit0.None of these four gates reads
DESIGN.mdorREADME.md, so none of them verified this change and none of them could have moved. Demonstrated, not just argued, three ways:grep -il DESIGNover the four gate logs — no file matched (exit1). Same forgrep -il README— no file matched (exit1).tsc --noEmit --listFilesemits the whole compiled program: 0 files ending.md, out of 305 files from this repo.tsconfig.jsonincludes onlyobjectstack.config.tsandsrc/**/*.git diff --name-onlyis exactlyDESIGN.mdandREADME.md— the diff has no intersection with what any gate walks (validate and lint walk the compiled metadata graph; the i18n gate walks the locale bundles).The evidence that this change is right is the claim-to-reading table above, not the gates.
grep -naPfor control bytes over both edited files: clean (exit1).🤖 Generated with Claude Code
https://claude.ai/code/session_01R3n3GGzobdegM4HUzah1iR
Generated by Claude Code