Skip to content

Upgrade the @objectstack/* dependencies from 17.4.0 to 17.7.0, walking the official upgrade checklists of 17.5, 17.6 and 17.7 - #85

Merged
zhuangjianguo merged 5 commits into
mainfrom
claude/issue-82-objectstack-17-7
Oct 10, 2026
Merged

zhuangjianguo merged 5 commits into
mainfrom
claude/issue-82-objectstack-17-7

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Part of #82 — everything the card asks for is here except one product choice, which this PR deliberately does not make: whether pnpm dev / pnpm demo turn 17.5's package-authored scheduled work back on (see Scheduled work — the decision this PR leaves open). Once that is decided, #82 can close.
Clause-②: no

What changed

All four @objectstack/* dependencies move together to ^17.7.0, the lockfile is regenerated and committed, and the app is migrated through the 17.5, 17.6 and 17.7 upgrade checklists. Every source edit below was forced by a 17.5–17.7 refusal, a gate, or a comment the bump made false — no capability was adopted.

Commit Files Why
d633b33 package.json, pnpm-lock.yaml 4 pins ^17.0.0 → ^17.7.0 as one set. Lockfile: 53 distinct @objectstack/* packages, all 17.7.0, zero 17.4.0 strings. zod resolves 4.6.5 (we pin none).
d633b33 contract.object.ts, payment-plan.object.ts, approval-rule.object.ts os validate exited 1 on 17.7: `scale` is not valid on a `currency` field — delete the key on 6 currency fields (17.5 retired key). Deleted. Display now follows the currency's ISO 4217 minor unit (USD rendered 139,500.00 in the browser).
d633b33 contract_detail.page.ts page:header breadcrumb removed in 17.6 (os migrate meta offer page-header-breadcrumb-removed, plus a validate warning). The shell's breadcrumb still draws.
d1551a2 pnpm-workspace.yaml The TEMPORARY FIXTURE (overrides: pinning better-auth + ten @better-auth/* to 1.7.2) retired: its removal condition objectstack#16186 is closed, and @objectstack/plugin-auth@17.7.0 pins the whole family to exactly 1.7.3. Measured, both ways — see Auth below.
c4aa32c scripts/demo.mjs, src/data/contract.seed.ts, src/data/keys.ts Three comments and pnpm demo's printed operator note said the demo boot leaves every seeded owner_id NULL. 17.5 (widened in 17.7) runs the first-admin ownership claim on every seed settle, so on 17.7 those rows end on the dev admin. Only the sentences the bump made false move.
7fd37c5 src/translations/{en,zh-CN}/flows.ts (new), {en,zh-CN}.ts, {en,zh-CN}/app.ts pnpm lint:i18n-gate exited 1 on 17.7 with 36 zh-CN keys missing: 34 flows.contract_intake.* (17.7 flipped the flows translation group live, which switches on the coverage demand — on 17.4 the walk produced no flow keys, so the intake wizard was English in zh-CN and nothing could say so) and pages.contract_detail.title/subtitle (17.5 made a slotted page's slots.header addressable; both are record-interpolation templates).
56c7501 3 dashboards, contract_detail.page.ts Their inline-translation rationale said the bundle has no key for the filter bar / addresses zero page components. False from 17.5 (globalFilters keys; the walk now returns 14 on this page) and subCaption is retired in 17.7. A dated note each; the inline maps are left in place (adopting the new keys is its own card).

Untouched on purpose: engines.protocol: '^17' and objectstack.manifest.json specVersion: ^17.0.0 (17.7.0 still implements protocol 17 — os doctor: Declared engines.protocol covers the installed platform), the peerDependencyRules block (still true on 1.7.3 — see Install), and every governed file.

Gates — on 56c7501, exit codes captured to a file before any pipe

VALIDATE_EXIT=0      → Running author-time rules (49)...   ✓ Validation passed (1341ms)
LINT_EXIT=0          6 suggestion(s) (1051ms)
TYPECHECK_EXIT=0     > tsc --noEmit   (no output)
I18NGATE_EXIT=0      ✓ i18n gate · LOCALES "en", "zh-CN" · COVERAGE : 0 missing keys across 2 locale(s)

Run through this container's shared verify lock. For comparison, main @ 14c899f (17.4.0): validate 44 rules ✓, lint 21 warning(s), 5 suggestion(s), typecheck ✓, i18n gate ✓. The 21 field-no-consumers warnings are gone on 17.7 because 17.5 (c3a95d9) credits a field placed on the synthesized layout by its declared field group — every field here declares a group. The 6 suggestions are the approval-approver advisories (one new on manager_review, which names /api/v1/auth/admin/set-user-manager).

os migrate meta --from 17

first run (before fixes) on 56c7501
Refusals left after the chain 6 — scale on 6 currency fields, all in src/objects/ 0 (schemaValid: true)
Mechanical changes offered 38: 1 page-header-breadcrumb-removed (applied) + 37 flow-decision-mode-inclusive-explicit 37 flow-decision-mode-inclusive-explicit — declined, each reviewed
Manual to-dos 304 generic protocol-18 items, none naming a site in this app same 304, none naming a site
Data migrations named — 0

The 37 decision offers. 17.5 made an edge-branched decision take its first matching branch; migrate meta offers mode: 'inclusive' to preserve the old every-true-branch behaviour. I dumped all 37 from the artifact with their out-edge conditions: every one is written as an explicit partition — C beside !C, or disjoint conjunctions (decision_rung2's four legal × finance cells, decision_party_given's resolved / inline / ask, decision_executed_file's four arms ending R vs X || !R). First-match and every-true-branch therefore take the same single edge in every state, so none needs the key — applying them blindly would make os validate report flow-decision-inclusive-overlap on all 37 (the checklist's own warning).

Per-release checklist tables

DB (a) = fresh .objectstack/data booted by 17.7. DB (b) = in-place: a database created by main (17.4.0, pnpm demo + the README operator setup), copied before the bump, then migrated and booted by 17.7. Every line marked not exercised on the release pages is recorded here with what it cost on this app.

17.5.0

# Checklist line Verdict Reading
1 Walled deployments: declare OS_PLATFORM_OWNER_EMAIL does not apply boot banner Tenancy: single; no group/isolated posture authored
2 Decide about scheduled work applies — decision left open six flows bound=False — disabled by deployment policy; see the decision section. Not decided in the diff
3 Read the switch with os doctor applies ✓ Package-authored scheduled work OFF (the default); with the variable set: ON — packaged time-triggered flows … are armed
4 Run os migrate account-issuer applies, DB (b) sys_account: 11 row(s) scanned, 11 distinct (provider_id, account_id) key(s). No key is held by more than one row — sys_account.issuer is safe to drop.
5 api flow config.secret does not apply type: 'api' 0 hits; /automation/_status lists no api trigger
6 Move pins as one set; @better-auth/* to exactly 1.7.3; zod ≥ 4.6.1 if pinned applies 4 pins moved; all eleven family members 1.7.3 once the fixture is gone (kept, it breaks sign-in — Auth); zod not pinned by us
7 Leave protocol declarations on 17 applies both unchanged; migrate meta: this runtime implements protocol 17
8 Apply the sys_account drop with os migrate apply --allow-destructive, then account-issuer expecting zero applies — does not converge (platform) DB (b): apply --allow-destructive --yes → 0 destructive, issuer still present; account-issuer again → same safe to drop … run apply --allow-destructive; 17.7 boot logs [schema-drift] sys_account.issuer … orphaned — "os migrate apply --allow-destructive" to drop it. Harmless here (nullable; new accounts store issuer NULL and sign in). Reported below
9 Do not read Nothing to migrate as completion applies it listed 6 refusals + 38 offers + 304 to-dos; this table is the rest
10 Review each offered mode: 'inclusive'; migrate meta --stored for stored decisions applies 37 reviewed, all partition, none applied; --stored (DB b): Examined 0 stored metadata row(s)
11 Recompile artifacts from an earlier os compile before serving cubes applies every boot ran --compile; no hand-written cubes; 19 analytics calls across 3 dashboards all 200
12 Wrap the default export in defineStack(...) does not apply already export default defineStack({ … })
13 Fix refused RLS predicates; check defaults to using applies — reviewed and measured 0 rls-predicate-* findings; all 8 policies are using-only. 17.5's check defaults to using measured on both versions: identical results (admin 403 on an in_review contract, legal owner 200) — see Out of scope
14 Rewrite view / page shapes (layout, sort strings, filter records, tabs, owner/hidden, type: 'page', undoable) does not apply 0 hits; validate passes
15 Delete page.assignedProfiles does not apply the one hit is a comment
16 Rewrite flow shapes (wait, decision branch expression/label, builtin keys, connector_action, region bodies) does not apply no wait/connector nodes; validate passes at parse and registerFlow (boot registered all 12)
17 lookup screen field reference does not apply no flow declares a lookup screen field (the two type: 'lookup' hits are dataset dimensions)
18 Move chartConfig structure onto the widget does not apply chartConfig hits are comments; dashboards draw (browser)
19 Other analytics shapes does not apply no cubes; validate passes
20 Delete retired keys (… scale on currency fields …) applies 6 scale keys deleted (d633b33); every other key listed: 0 hits
21 manifest.id reverse-domain, no underscores does not apply app.objectstack.hotclm
22 Expect new error-severity findings applies author-time rules 44 → 49; 0 errors at validate and lint
23 Re-check dateRange preset dashboards does not apply no dateRange authored (3 hits are comments); compareTo tile renders Approved This Month 1 · 89% vs last month
24 New numeric columns; no NOT NULL from required alone; no column retyped applies clm_contract.amount float on 17.4-created, in-place and fresh DBs; planned_amount keeps notnull=1 (authored storage.notNull)
25 Repair blank strings in non-text columns applies, DB (b) 0 blank strings across every non-text clm_* column
26 Remote Turso does not apply SqlDriver(better-sqlite3) file DB
27 unbuildable_index in os migrate plan applies, DB (b) plan: 0 change(s): 0 safe, 0 needs-confirm, 0 destructive, 1 additive column on sys_migration
28 S3 keyPrefix does not apply no S3 adapter
29 sys_notification_delivery retention does not apply no retention override
30 Grant object read to analytics principals applies — measured dataset query answers what /data answers per caller: requester 43 / 43, counsel 120 / 120, admin 120 / 120
31 M2M MCP clients → API keys does not apply none configured
32 SCIM projection read does not apply no SCIM
33 No active organization → global grants only applies — no effect single tenancy; every account lands in the default org
34 Anonymous 401 from client.auth.me() does not apply no client SDK use
35 ctx.engine.find envelope does not apply 0 hits
36 Narrowed findOne / update / hook return shapes applies tsc --noEmit exit 0
37 beforeUpdate reading a readonly field from ctx.input.data applies — already satisfied the hooks read input[key] !== undefined ? input[key] : previous[key] (contract.hook.ts:196, :375, :609), so a stripped key falls back to the stored value; the state machine ran in_review → in_approval → approved in the browser
38 registerHook on find-one/count/aggregate events does not apply 0 hits
39 Refused filter shapes in code applies — exercised all six jobs (manual triggers), the approval ladder and 3 dashboards ran without a refused filter
40 Write values in declared spellings applies fresh seed: 820 rows, identical per table and per column to 17.4 (268 columns compared; only platform owner_id differs — see Boot)
41 Narrowed published types applies tsc --noEmit exit 0
42 /diff, /history, /audit, /layers does not apply app calls none
43 Removed APIs (GET /api/v1/automation, export jobs, client.reports, spec/cloud, api-assembled, CONCURRENT_LIMIT_EXCEEDED) does not apply imports are spec, /automation, /data, /identity, /security, /system, /ui only
44 enableOnInstall: true does not apply no package installs
45 MCP callers' argument names / confirm does not apply none

17.6.0

# Checklist line Verdict Reading
1 App-declared anonymous endpoints (authRequired: false) does not apply 0 hits
2 fallbackPermissionSet: null embedders does not apply stock objectstack dev; every account holds a set
3 manage_platform_settings for datasource metadata does not apply no datasource metadata
4 Stored flows sharing a packaged flow's name applies, DB (b) 0 stored metadata rows; no shadowed-flow warning at boot; /automation/_status 12 flows
5 Stored datetime before year 1000 applies, DB (b) 0 values across every datetime column
6 Turso mode: 'local' beside syncUrl does not apply SQLite file
7 Move pins; pnpm update hono if a scanner flags the older copy applies — conditional part not triggered hono@4.13.7 remains under @objectstack/cli → @objectstack/mcp → @modelcontextprotocol/sdk (pnpm why); this repo runs no scanner, so not run
8 Leave protocol on 17 applies unchanged
9 migrate meta --from 17, then --stored --apply applies --from 17: breadcrumb applied, 37 offers declined; --stored DB (b): 0 rows, so no --apply
10 migrate audit-metadata-bodies, then --apply applies, DB (b) sys_audit_log: 0 scanned, 0 to rewrite · sys_activity: 0 scanned · Nothing to rewrite
11 Cube member sql / dataset member field must be a column; delete refreshKey applies — none fired validate passes; refreshKey 0
12 Connector triggers / syncConfig / fieldMappings does not apply no connectors (hits are prose)
13 Page / view shapes (div, requires, endpoint, subform columns, grouping, publicPicker, breadcrumb) applies breadcrumb deleted (1 site); the rest 0 hits
14 New author-time refusals (picklists, api secret, action translation keys, JSON/multi-value dimensions, dimensionless pie/donut/funnel) applies — none fired 13 chart hits and 39 Field.select pass validate
15 os validate --strict fails on dead keys does not apply to the gate the gate does not run --strict; measured anyway: it fails only on the 7 existing advisories, no liveness-dead-property / unconsumed-widget-option
16 time defaults as a bare wall clock does not apply no time fields
17 「is empty」 now matches '' / [] applies — no result change pending_archive filters archive_no is_empty (text): 114 NULL, 0 '' in both DBs; legal_intake filters a lookup
18 Review saved filters, list views, dashboards for refused shapes applies no stored views (DB b); browser: 3 list views + 3 dashboards render, 19 analytics calls 200
19 Import files in ISO 8601 does not apply app ships no import file
20 Remote Turso sequences does not apply —
21 Auditors' unmasking permission set does not apply no auditor audience in DESIGN.md §04
22 --visibility private on os plugin publish does not apply —
23 Console issues at the 17.6 pin (incl. zh-CN console strings in English) superseded at 17.7's pin zh-CN console strings render Chinese (新建 / 筛选 / 分组 / 全部刷新 / 确认 / 取消); Studio saves not reached
24 invalid_date override needs _range siblings does not apply no override
25 status: 'obsolete'; subflows; flows named _… does not apply no flow name starts with _ (_daily-sweep.ts is a builder file); no subflows
26 http node signingSecret does not apply no http nodes
27 strictReadonlyWrites formula values does not apply —
28 spec/migrations imports, --clone-from, os dev --no-watch, nextUtcCalendarDay does not apply —
29 Custom hosts and drivers does not apply —
30 data.record.* events does not apply —

17.7.0

# Checklist line Verdict Reading
1 Convert retired fields' leftover columns first does not apply no field retired (scale is a key); migrate plan DB (b) lists no orphaned app column
2 Bodies / flows touching sys_metadata does not apply 0 hits
3 sharing.enabled: true on public forms does not apply no public forms
4 Approval node configs vs ApprovalNodeConfigSchema; deprecated approver type over a position name applies — clean validate passes; approvers are { type: 'position', value } and { type: 'manager' }; contract_approval bound=True; one ladder step driven end to end (browser)
5 Pending approval requests in the pre-rename spelling applies, DB (b) sys_approval_request: 0 rows (the seed opens none — README says so)
6 Code addressing an unregistered object does not apply boot and every flow run clean
7 Rolling back past 17.7 (v2: ciphertext) applies — nothing to keep dev LocalCryptoProvider; the app sets and rotates no secret
8 Move pins applies done
9 Protocol on 17 applies unchanged
10 migrate meta --from 17, --stored --apply (agent lifecycle, heading/subheading, resizableColumns, sortField, page requires, widget subCaption) applies — none present none offered for this app; the 3 subCaption hits are comments (corrected in 56c7501); --stored DB (b): 0 rows
11 audit-metadata-bodies (content hash) applies, DB (b) 0 rows to rewrite
12 Replace an in-memory boot store does not apply SQLite file
13 Rotate flow secrets moved into sys_flow_credential does not apply no flow carries a secret
14 Rotate JWT keys; re-mint share links not exercised dev deployment, no share links
15 Resume / cancel paused runs from before the upgrade applies, DB (b) 0 paused runs (sys_automation_run absent before 17.7)
16 os secret rewrap (optional) not run keeps the rollback path, as the line advises
17 Federated objects on objectstack start does not apply none
18 Stored datasource row skipped under a code-defined name does not apply no such boot line
19 New parse refusals (select with no options, agent memory, requires on non-html page, joined reports, pie/donut/funnel with dimension and ≥ 2 values, subCaption, cube metric types, '*', hook bodies, approval configs) applies — none fired validate passes
20 New author-time errors (resultDialog keys, JSON cube members, record:related_list action ids, html literals) applies — none fired validate passes
21 component-props-* advisories; resizable; sortField; element:text variant applies — none fired no advisory printed; 0 hits
22 Bound action translation globalActions → objects._actions does not apply 0 hits
23 View container default form does not apply no formViews, no .edit reference
24 404 RECORD_NOT_FOUND from by-id writes on unreadable rows applies — not separately exercised the write refusal measured here is a readable-but-not-editable row (403, identical on 17.4)
25 organization_id of another org on create does not apply single tenancy
26 Boolean / list / analytics window spellings; RLS comparands applies — exercised six jobs, ladder and dashboards ran; RLS predicates inList(status) and owner == current_user.id
27 Credential columns / SECRET_MASK does not apply no secret fields
28 acted_as; {{ body }} in approval templates does not apply app reads neither; no templates
29 Localization setting keys does not apply —
30 409 METADATA_CONFLICT token does not apply no metadata writes from app clients
31 External sign-ins to unverified local email does not apply no external IdP
32 X-Share-Password CORS does not apply —
33 isolated + scheduled work: organization on packaged jobs does not apply single posture, no defineJob
34 Re-sign non-Ed25519 plugin artifacts does not apply —
35 os dev -a / --artifact / OS_ARTIFACT_PATH does not apply pnpm dev / demo.mjs use objectstack dev --compile only
36 os package install hook / job bodies does not apply —
37 ICryptoProvider.keyedDigest does not apply —
38 Renamed / removed exports (checkDashboardWidget…, AIChatWindowProps, StateMachineSchema) applies tsc exit 0; installed spec-changes.json release 17.6.0 → 17.7.0: 50 added, 15 removed, 0 converted, 0 migrated
39 Membership for engine-inserted users does not apply users are created through the auth admin endpoint (response carries organizationId; new account signs in)
40 sourceFieldMeta for a hand-built AnalyticsService does not apply —

Auth — the fixture, measured both ways

17.7.0 with the 1.7.2 override 17.7.0 without it (this PR)
Resolved family better-auth + 10 @better-auth/* at 1.7.2 all eleven at 1.7.3 (plugin-auth's exact pins)
Boot WARN [auth] dev admin seed skipped: Unknown field 'issuer' on object 'sys_account' dev admin seeded
POST /api/v1/auth/sign-in/email 401 INVALID_EMAIL_OR_PASSWORD (sign-up 403, self-registration closed) 200 · GET /api/v1/auth/get-session 200
In-place DB (b) — 17.4-created admin and requester sign in 200; admin/create-user 200; the new account signs in 200

Keeping the fixture would have shipped an app no one can log into on a fresh database.

Install

pnpm install printed no peer-dependency warning. Because peerDependencyRules suppresses some, I resolved the same manifest twice in a scratch copy, with and without the block: without it pnpm reports exactly the five the block documents, now on 1.7.3 (four @better-auth/utils@0.4.2 peers given 0.5.0, one better-sqlite3@^12 given 13.0.3), and the two lockfiles are byte-identical. The block's comment still holds, so it stays.

Boot-log diff against main — same seed, clean .objectstack/data, read at seeder quiescence

Both boots: pnpm demo on an empty database, row counts per clm_* table polled every 5 s until 6 identical reads and 90 s of log silence (a 20 s window was too short: the background seed paused at 520 rows for ~30 s before resuming).

Reading main @ 14c899f (17.4.0) 17.7.0 (d1551a2)
Seed summary "inserted":820,"errored":404,"referencesDropped":0 identical
Rows per table approval_rule 6 · clause 30 · contract 120 · contract_type 9 · contract_version 0 · deviation 25 · obligation 200 · party 40 · payment_plan 300 · review 60 · signature 30 identical
Per-column non-null counts (268 columns) — identical except platform owner_id: NULL on all 820 rows on 17.4, the dev admin on all 820 on 17.7 (17.5/17.7 seed-settle claim; README procedure still hands contracts over 43 / 43 / 34)
Plugins 38 41 (+ MigrationRecovery, PackageServicePlugin, TelemetryDatasource)
Flows 12 flow(s) 9 bound 12 flow(s) 3 bound — six schedule flows NOT bound — disabled by deployment policy
System started with degraded capabilities / plugin failed to load absent absent
Platform ERROR lines [sql-driver] DATABASE_ERROR (_objectstack_sequences) and sys_oauth_resource UNIQUE both gone
Boot diagnostics 2 warnings (inline seed budget; sharing-rule bulk regrant) 9: inline seed budget, [Analytics] No admitObjectRead configured … at init, OAuth is served UNENCRYPTED (dev http), and the 6 scheduled-flow notices
Author-time rules at compile 44 → 26 warnings 49 → 6 warnings

The new [Analytics] … will NOT enforce the OBJECT-LEVEL read grant warning is an init-order notice, not a leak: measured per caller above (#30 of 17.5).

In-place upgrade — DB (b)

os migrate account-issuer → clean · os migrate plan → 0 changes · os migrate apply --allow-destructive --yes → 1 additive column, 0 destructive · os migrate meta --stored → 0 rows · os migrate audit-metadata-bodies → 0 rows · then pnpm dev on 17.7: Server is ready, 41 plugins, 820 clm_* rows intact, existing accounts sign in, new accounts can be created. First in-place boot additionally logs five sys_permission_set … drifted from its metadata definition — re-projected (the shipped sets) and three [schema-drift] orphans (sys_account.issuer, its unique index, one sys_job_queue index).

Browser — Chromium at /opt/pw-browsers/chromium-1194/chrome-linux/chrome, no playwright install

17.7.0 on pnpm demo (fresh DB, README operator setup, re-run to hand rows over), driven with Playwright.

Surface Who What the browser showed
Sign-in /_console/login 5 accounts all land on /_console/apps/clm/clm_contract/view/my_contracts
我的合同 › Launched by Me Business Requester 1 43 rows, grouped (Active 18, Approved 2, Draft 2, …), amounts 139,500.00
Contract detail, all 7 tabs Business Requester 1 Overview (owner BR1, legal owner LC1) · Versions 0 · Review & Deviations 0/0 · Approvals · Obligations & Payments 6 · Signing & Archive · Discussion
Inbox reminders Business Requester 1 header badge 9, panel 9 total · 9 notifications · 0 pending approvals, rows Instalment 2 overdue: Independent Contractor Agreement — Marcus Lindgren … — after one manual run of each job (scheduled work is off; see below)
Every dashboard Dev Admin (clm_admin) Legal Workbench 6 / 12 / 6 / 2 / 1 + Pipeline by Stage · Executive Overview (currency bars, 12, 21, routes 11 / 42 / 23 / 4, signed value) · Finance Overview (Falling Due, Overdue 3,413,450, 30 instalments, top-10 table, planned vs settled) — 19 analytics calls, all 200
One approval step Legal Counsel 2 → General Manager Send for Approval was correctly refused twice by the app's own gates (1 deviation(s) are still open…, then An approved legal review is required…); on a contract with neither: POST /api/v1/actions/clm_contract/send_for_approval → 200, request at manager_review waiting on the requester's manager; GM opened Waiting on Me, Approve → Confirm: POST /api/v1/approvals/requests/…/approve → 200, contract approved with approved_at stamped, and BR1 notified Contract approved: …
Non-admin audiences BR1, LC1, LC2, GM as above; requester analytics scoped to her 43
zh-CN LC1, BR1 (Accept-Language: zh-CN) lang=zh-CN; nav 我的合同 / 法务工作台 / 管理层看板 / 财务看板; list and dashboard labels Chinese; record header still interpolates (ICA-2026-0001); the intake wizard now reads 发起合同 · 合同信息 · 标题 · 我方签约主体 … with Chinese placeholders

Console / network, every pass: no page errors. Recurring and pre-existing: a 401 on get-session before sign-in, an aborted organization/list (the startup race PR #37 recorded), and for non-admin accounts 403 PERMISSION_DENIED on sys_activity, sys_comment, sys_attachment and sys_approval_request (Discussion reads You don't have permission…). Those four 403s are identical on 17.4 — measured by booting main over the same database and replaying the calls — so they are not this bump's.

Scheduled work — the decision this PR leaves open

Readings. On 17.7 the six daily jobs (F3, F4, F10–F13) register but do not arm: bound=False — disabled by deployment policy, os doctor OFF (the default). They still run when triggered — POST /api/v1/automation/NAME/trigger answered 200 for all six with the switch off and wrote 45 inbox rows across six recipients — so the reminder layer itself works; only the clock is off. With OS_AUTOMATION_SCHEDULED_WORK_ENABLED=true the same database binds 9 of 12 flows (17.4's count) and boot diagnostics drop from 9 warnings to 2. os dev loads .env.development* (dotenv-flow), but .gitignore excludes .env and .env.*; os start does not read the development files.

Why it is a choice, not a mechanical setting. The platform flipped the default deliberately (a clock-driven workload's cost is a fact about the deployment, not about the flow); these jobs mutate data at 06:00 / 07:00 UTC (mark overdue, expire contracts, draft renewals — PR #42 noted a re-run of pnpm demo then drops two rows); and every mechanism touches run instructions or repo config.

A — ON for pnpm dev and pnpm demo B — platform default everywhere, documented C — ON for pnpm demo only
How committed .env.development plus a .gitignore exception (or a wrapper script for dev) README: a deployment that wants M3's reminders sets the variable; locally, run a job with the trigger route scripts/demo.mjs passes the variable to the demo boot; README note for deployments
Cost new committed config surface next to where secrets usually go; dev diverges from the platform default every boot prints six notices, which AGENTS.md's a boot that logs warnings is not a passing boot would read as non-passing pnpm dev keeps the six notices; two local commands differ

Four axes:

  • Real business need — M3's acceptance 「到期、逾期提醒在收件箱可见」 needs the jobs running in a real deployment, which only the deployer's environment can do in every option, so the README line is needed in all three. In a demo session the reminders come from manual runs unless the server spans 06:00 UTC, so A and C differ from B mainly on long-running demos and boot noise. pnpm dev is deliberately empty: the jobs have nothing to sweep there.
  • Long-term soundness — B matches the platform contract exactly; C limits repo-level policy to the one showcase command; A adds a config surface the repo has so far kept out of git.
  • Keeping AI from getting it wrong — the trap is "verified locally, silently off in production": production boots print the same six notices, so it is loud in every option, but only a README line tells an operator before the first boot. Normalising six warnings on every verification boot (B) erodes the repo's own boot-warning rule, which is how a real degradation gets ignored; a committed .env.development (A) is a place an agent later drops a secret.
  • Startup focus — B is smallest (README lines); C is one env entry plus README; A is a file plus a .gitignore exception.

Recommendation: C, plus a README sentence for deployments. It restores the M3 showcase exactly as 17.4 ran it, keeps policy out of git, and leaves pnpm dev — empty, nothing to remind about — on the platform default, whose notices are accurate there. B is coherent if the maintainer prefers zero repo policy. AGENTS.md's boot-warning rule is governed prose; listed below.

#31's unlock probe on 17.7.0 — report only

Recipe from #80: a scratch probe31_cycle dataset with avg over submitted_at / activated_at and a derived: { op: 'difference' }. Never committed.

Layer 17.4.0 (#80) 17.7.0
Author time pnpm validate 0, renders pnpm validate 1 and pnpm build 1: measure-aggregate-field-type-refused on both measures — applies aggregate "avg" to field "submitted_at", which object "clm_contract" declares as datetime. pnpm typecheck 0
Runtime save door — PUT /api/v1/meta/dataset/probe31_cycle → 422 INVALID_METADATA; nothing stored (GET → 404)
Engine aggregate 200, -0.8555… POST /api/v1/analytics/query avg over submitted_at → 400 INVALID_FIELD …so the query was NOT run
What the operator sees a tile reading -0.86 a refusal at every door; no number

Outcome: it errors. #31's criterion 「本仓升到含该修复的版本后那条错路确实报错」 reads as met on 17.7.0. The metric itself is still uncomputable (refuse, not provide). ⚠️ The first author-time run did not reach the question — it was refused on a new required dataset label (datasets.4.label: Invalid input); I recorded it as a non-measurement and re-ran with only label: 'Probe 31' added. Tree restored both times and proved by state: git status --porcelain empty, git diff HEAD 0 bytes, git hash-object src/datasets/index.ts = git rev-parse HEAD:src/datasets/index.ts = 14ce0601805306c73537a3b724ece7451ea7b67f, probe file absent.

Platform findings — for the seat to file upstream (not patched here)

  1. os migrate account-issuer / the boot's [schema-drift] prescribe a command that cannot drop sys_account.issuer. 17.7.0, SQLite DB created by 17.4.0, app with requires: ['auth']. os migrate plan/apply compose 0 plugins and examine 20 tables; sys_account is reported only as an undeclared platform table. os migrate apply --allow-destructive --yes → 0 destructive; the column stays; account-issuer and the next boot both prescribe the same command again. Harmless on SQLite here (nullable, NULLs pass the unique index), but the 17.5 checklist's expect zero never arrives.
  2. The flows translation face has no key for a screen's description or a screen field's select options. 17.7.0 zh-CN intake wizard: heading, labels and placeholders translate; the body text and options (Head office, USD — US Dollar) stay English. The schema's own guidance says description is out of the face.
  3. Pure interpolation templates are demanded as translation keys. pages.NAME.title / .subtitle holding only {contract_number} / {title} count as missing until a bundle repeats them verbatim.

Acceptance notes

  • Governed prose this bump made stale (⛔ not edited): AGENTS.md:62 cites the fixture in pnpm-workspace.yaml, which no longer exists. AGENTS.md:97 and DESIGN.md §03 (line 98) require every number to declare its decimals; 17.5 refuses scale on a currency field (decimals follow the currency). AGENTS.md's a boot that logs warnings is not a passing boot now meets six by-design scheduled-work notices on every default boot (see the decision). PR The two surfaces that merely restate the gate set should name pnpm verify instead of enumerating it — a restatement of a definition cannot be allowed to drift #81 holds AGENTS.md.
  • Non-governed docs outside this card's file surface: docs/backlog/02-contract-domain.md and 03-post-signature-domain.md say currency, scale 2.
  • Behaviour changes with no edit: the 14 named list views omit pageSize and now page at 50 instead of 25 (ruled platform default); platform owner_id on seeded rows the fixture does not deal (obligations, instalments, …) is the dev admin instead of NULL.
  • Capabilities that make an existing workaround obsolete — reported, not adopted: 17.5's pages.NAME.components.ID.* on slotted pages and dashboards.NAME.globalFilters.* could replace the 22 inline { en, 'zh-CN' } labels on the record page and the inline filter copy on the three dashboards.
  • Out of scope, pre-existing (identical on 17.4): a clm_admin holder cannot edit a contract past submitted (PATCH /api/v1/data/clm_contract/ID → 403), because every position also binds clm_requester, whose using-only contract_requester_edit_window is the only applicable update policy — while README says clm_admin holds full reach over every CLM object. Also the four sys_* 403s for non-admins listed under Browser.
  • scripts/check-lint-i18n-gate.mjs's REACH list has no flow class, so a regression that stops walking flows would not fail REACH (COVERAGE still counts them). Not changed: bump only.
  • No changeset: this repo has no changeset gate.

🤖 Generated with Claude Code

https://claude.ai/code/session_01HihZ11bQSqjCgjzHbpv4M1


Generated by Claude Code

claude added 5 commits October 9, 2026 14:52
…ale and page breadcrumb

WIP on #82. All four @objectstack/* deps move together to ^17.7.0 and the
lockfile resolves every @objectstack/* package to 17.7.0.

17.5 refuses `scale` on a currency field (the currency's ISO 4217 minor unit
decides display) — `os validate` exited 1 on the six amount fields. 17.6
removed `page:header` `breadcrumb`; `os migrate meta --from 17` offers the
same deletion (page-header-breadcrumb-removed).

The better-auth fixture in pnpm-workspace.yaml is still in place at this
commit; it is measured and removed separately.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HihZ11bQSqjCgjzHbpv4M1
…s to 1.7.3

The override named objectstack-ai/objectstack#16186 as its removal condition
(closed completed). @objectstack/plugin-auth@17.7.0 now pins better-auth and
every @better-auth/* member to exactly 1.7.3, which is what the 17.5 upgrade
checklist asks for, and all eleven members resolve there without an override.

Measured before removing it: 17.7.0 with the 1.7.2 pins still in place boots,
but refuses the dev-admin seed ("Unknown field 'issuer' on object
'sys_account'"), so a fresh database has no account and sign-in answers 401.
Keeping the fixture would have shipped an app nobody can log into.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HihZ11bQSqjCgjzHbpv4M1
Three comments and pnpm demo's printed operator note said the demo boot leaves
every seeded owner_id NULL until the requester accounts exist. 17.5 (widened in
17.7, plugin-security CHANGELOG) also runs the first-admin ownership claim on
every seed settle (`app:seeded`), so on 17.7.0 the demo boot ends with every
ownerless row parked on the dev admin. Measured on a clean database: all 120
contracts owned by Dev Admin after the first `pnpm demo`; after the README's
operator setup the next `pnpm demo` hands them over 43 / 43 / 34 as before.

Only the sentences the bump made false move; the dated 17.3/17.4 measurements of
legal_owner, owner and decided_by (still NULL on 17.7) are untouched.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HihZ11bQSqjCgjzHbpv4M1
…r 17.7's coverage walk

`pnpm lint:i18n-gate` exited 1 on 17.7.0 with 36 zh-CN keys missing, none of
them new strings:

- 34 `flows.contract_intake.*` keys — the intake wizard's flow label, screen
  headings and field labels/placeholders. 17.7 (spec aead296) flipped the
  `flows` translation group to `live`, which switches on the coverage demand;
  on 17.4 the walk produced no flow keys at all, so a zh-CN user launched a
  contract through an English wizard and no gate could say so.
- `pages.contract_detail.title` / `.subtitle` — 17.5 (4bbf766, #16772) made a
  slotted page's `slots.header` addressable. Both are record interpolation
  templates, the same string in every locale.

The Chinese reuses the object bundle's words for the same columns; `en/flows.ts`
mirrors the inline English so the two bundles carry the same keys.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HihZ11bQSqjCgjzHbpv4M1
…17.5

The dashboards' globalFilters comment said the bundle has no key for the filter
bar and listed `widgets.<id>.{title,description,subCaption}`; the record page's
said `walkAddressedPageComponents` addresses zero components on a slotted page.
17.5 (spec 4bbf766, #16772) added `globalFilters` keys and rooted the walk at
`slots` (the same call returns 14 on contract_detail on 17.7.0), and 17.7
retired `subCaption`. Each comment gains a dated note; the inline maps still
render and are left in place — adopting the new keys is a separate card, not
part of a dependency bump.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HihZ11bQSqjCgjzHbpv4M1
@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 10, 2026 00:09
@zhuangjianguo
zhuangjianguo merged commit c31c7e2 into main Oct 10, 2026
2 checks passed
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