Skip to content

Upgrade the @objectstack/* dependencies from 17.7.0 to 18.1.0, walking the official upgrade checklists of 18.0 and 18.1 - #110

Merged
zhuangjianguo merged 1 commit into
mainfrom
claude/project-thread-dee6rv
Oct 25, 2026
Merged

zhuangjianguo merged 1 commit into
mainfrom
claude/project-thread-dee6rv

Conversation

@zhuangjianguo

Copy link
Copy Markdown
Collaborator

Requested by Steedos · project thread

Part of #82. Unblocks #84, #86, #98, #100, #107 and the remainder of #95. Main is at 936f3de; this branch is rebased onto it.

What changed

Each step of the official 18.0.0 and 18.1.0 checklists that applies to this app:

  • Pins. All four @objectstack/* dependencies are pinned to exactly 18.1.0. pnpm-workspace.yaml gains the eight-line overrides block that holds the CLI's own ranges (18.1 step 1). The lockfile now resolves no @objectstack/* package at any other version.
  • Protocol. engines.protocol in the stack and in objectstack.manifest.json is now '^18', and specVersion is now '^18.0.0'.
  • Flows: one expression dialect per slot (ADR-0032). os validate refused 252 places on 18.1.
    • Every value slot now takes a CEL envelope: CRUD fields/filter, script inputs, notify recipients/sourceId, loop collection, screen defaults. The envelopes come from the new src/flows/_values.ts:
      • ref(path) is the guarded read that os validate prescribes. It returns null wherever the 17.x template wrote nothing.
      • must(path) is used for filter operands. An absent operand refuses the node there, as before.
    • {$User.Id} is now current_user.id.
    • The renewal refusal message is now a CEL string concatenation.
    • Text slots (notify title/message, screen description) take {{ path }} holes.
    • Date macros in filters ('{today}', '{tomorrow}', '{N_days_ago}') stay plain strings, because they are query placeholders.
  • Page. template: 'full-width' is removed in spec 18. It rendered the same as the default, so it is deleted.
  • Positions ↔ permission sets. 18 retires sys_position_permission_set, so src/security/bind-position-sets.ts and the onEnable hook are deleted. Each position now names its sets in permissionSets (src/sharing/positions.ts). The pairs are the same: its own set plus clm_requester. POST /security/explain shows clm_admin arriving via position:clm_admin.
  • i18n. 18.1's lint walks more of the flow surface: screen descriptions, select options, successMessage, and approval step labels. This adds the 36 zh-CN keys it reported, mirrored in en. Option labels reuse the object bundle's own words.

Not fixed here

  • "Backfill Executed Contract" (executed_upload) answers 403. The message is "This caller may not start this flow…". 18.1 refuses to start a runAs: 'system' autolaunched flow from an action. The flow is elevated on purpose: only a system write may insert a contract born active. The platform's remedy is flow-level requiredPermissions on a screen/api flow, which is on objectstack main (#25643) and not in 18.1.0. Changing the flow type alone would let any signed-in user reach an elevated insert through /automation/executed_upload/trigger. Per AGENTS.md ("platform gaps wait for the platform"), the button stays broken until the release that ships #25643. The user chose this on 2026-10-25.
  • signature_record / signature_record_on_create were validated statically only. Driving them needs a full signing round. Their rewrite is the same pattern as the flows exercised below.

Gate output (on the head of this branch)

$ pnpm validate
  ✓ Validation passed   (6 info-level approval-approvers-may-resolve-empty, 1 hierarchy-security capability notice; both pre-existing)
$ pnpm lint
  6 suggestion(s)       EXIT=0
$ pnpm typecheck
> tsc --noEmit          EXIT=0
$ pnpm lint:i18n-gate
✓ i18n gate
  COVERAGE : 0 missing keys across 2 locale(s)

Browser evidence (Playwright, pre-installed Chromium, zh-CN, 1440×900, pnpm demo:zh on an empty database)

  • Boot. The boot printed ✓ Server is ready, Tenancy: single, and Plugins: 44 loaded. Nothing reported degraded, no such table, or a failed plugin. The only WARN is the CLI's own Plugin superseded: com.objectstack.metadata. The seed loaded 120 contracts, 9 types, 40 parties and 60 reviews.
  • Pages. 我的合同, the contract record page (MSA-2026-0001) and 法务工作台 rendered with their data.
  • Intake wizard (NDA, new counterparty). Screens: type → 合同信息 → 新建相对方 → 首个版本 → upload PDF → 立即提交.
    • Every resume returned 200, ending with successMessage: "Contract launched.". NDA-2026-0022 was saved submitted with the counterparty created, version_count: 1, and owner_id set to the caller.
    • The 18.1 screen descriptions and option labels render in Chinese.
  • Order Form with 立即提交, after rebasing onto The intake wizard's "Submit now" fails for every requester — FLOW_FAILED, the edit-window RLS policy refuses the post-submit row, while the header Submit button on the same draft succeeds #91. ORD-2026-0017 went to in_approval, and contract_approval paused at manager_review.
  • Approval ladder.
    • The 待我处理 inbox shows 「合同审批 / 直属上级」, the new zh-CN keys.
    • After two 通过 clicks: the run completed through manager_review → finance_only → mark_approved → notify_approved, the contract is approved, and the inbox shows "Contract approved: …".
  • 发起续签, pressed twice.
    • The first press created ORD-2026-0017. It carries 13 inherited fields identical to the source and dates rolled on a term.
    • The second press returned 400 FLOW_FAILED with "This contract already has a renewal draft (ORD-2026-0017). Open that one instead of starting a second."
  • Six daily sweeps. For this check only (not committed) the cron was set to * * * * * and OS_AUTOMATION_SCHEDULED_WORK_ENABLED=true.
    • All six end completed. turn_stalled sent 2 notifications. payment_overdue sent 18, e.g. "Instalment 2 overdue: 订单 — 灯塔金融 … Planned 1400; received so far 700.".
    • The first obligation_due run caught a mis-wrapped {tomorrow} macro. It is fixed here and was re-run completed.
  • Console. The only error was the pre-login 401 GET /auth/get-session probe.

Generated by Claude Code

Walks the official 18.0.0 and 18.1.0 upgrade checklists:
- pin every @objectstack/* dependency to exactly 18.1.0 and hold the CLI's own
  ranges with a pnpm override (18.1 checklist step 1)
- declare protocol ^18 in the stack manifest and objectstack.manifest.json
- rewrite every flow value slot from the retired {path} template dialect to a
  CEL value envelope (ref/must in src/flows/_values.ts) and every text slot to
  {{ }} holes (ADR-0032, 252 refusals)
- drop page template 'full-width', removed in spec 18
- bind positions to permission sets through permissionSets on the position
  definition; the sys_position_permission_set binder retires with the object
- add the zh-CN (and mirrored en) keys 18.1's flow i18n surface now walks:
  screen descriptions, select options, successMessage, approval step labels

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LWgCfQwCTdEDv21fUM79aB
@zhuangjianguo zhuangjianguo self-assigned this Oct 25, 2026
@objectstack-fleet

Copy link
Copy Markdown
Contributor

席位核对 — ACCEPT · head 7ba038e · 2026-10-25T11:28Z

check reading
shape draft → main, base 936f3de (= main), line 1 Part of #82; no closing keyword anywhere in the body
scope 26 files, +1010/−1038 (lockfile +617/−637); governed surface none (AGENTS.md · CLAUDE.md · DESIGN.md · docs/design/** untouched); under the 3000-line threshold
pins @objectstack/{spec,runtime,plugin-hono-server,cli} exactly 18.1.0; pnpm-workspace.yaml overrides hold the CLI's own ranges at 18.1.0 (18.1 checklist step 1); protocol ^18 in stack and manifest
positions src/security/bind-position-sets.ts + onEnable deleted; each position names [own set, clm_requester] in permissionSets — same pairs as the 17.x binder (two leadership rungs: clm_requester only)
flows value slots → ref() / must() CEL envelopes (src/flows/_values.ts), {$User.Id} → current_user.id, text slots → {{ }}, date macros left plain; browser-exercised: intake (NDA, new counterparty, upload, submit), Order Form → in_approval, the approval ladder to approved, Start Renewal ×2, all six daily sweeps completed
CI on the head both Validate check-runs success on 7ba038e = PR head.sha
gates (PR body) validate ✓ · lint 6 suggestions, exit 0 · typecheck exit 0 · i18n gate 0 missing keys
known regression, accepted executed_upload (Backfill Executed Contract) answers 403 on 18.1 until the release carrying objectstack-ai/objectstack#25643; the maintainer chose to land without it; #43 already carries Blocked-by: objectstack-ai/objectstack#25643
acceptance note two comments in src/apps/clm.app.ts (lines 31 and 321 on the head) still cite the deleted bind-position-sets.ts; folded into the #95 remainder (descriptions and stale notes), not a blocker

Landing: under the maintainer's standing authorization (project thread, 2026-10-25: 「你可以自己审核的就自己合并」). After it lands the seat rewrites the upgrade Blocked-by: lines to #110 and dispatches the queue.


Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 25, 2026 11:29
@zhuangjianguo
zhuangjianguo merged commit 7b736a0 into main Oct 25, 2026
2 checks passed
This was referenced Oct 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants