Skip to content

Upgrade the @objectstack/* dependencies from 17.3.0 to 17.4.0 #35

Closed

Description

@zhuangjianguo

Maintainer directive, 2026-09-09, verbatim: 「object stack 可以升级到 17.4 了」.

@objectstack/* 17.4.0 was published today and is now latest on every package this repo
consumes. This card moves the app onto it and proves the app still works, on a real boot in a real
browser — not by the version string changing.

Where the repo actually is (readings, 2026-09-09T13:50Z)

Reading Value How
Declared range ^17.0.0 on @objectstack/spec, runtime, plugin-hono-server, cli package.json
Resolved pin 17.3.0, every package pnpm-lock.yaml ('@objectstack/cli@17.3.0', spec@17.3.0, runtime@17.3.0, plugin-hono-server@17.3.0)
latest on npm 17.4.0 npm view @objectstack/<pkg> dist-tags — all four agree
Protocol range engines: { protocol: '^17' } (objectstack.config.ts:35) 17.4 is inside it; ⛔ do not widen it

The caret already admits 17.4.0 — the lockfile is what is holding the app at 17.3.0. So this is
not only a package.json edit; the lockfile has to move and be committed.

What is coming with it

17.4.0 is 396 changesets across 61 packages: 35 carrying a breaking marker, 140 other minor,
221 patch (content/docs/releases/v17/17-4.mdx on objectstack-ai/objectstack@origin/main). That
page is a machine draft and says so — its breaking list is "a floor, never a clearance", so an
unmarked breaking change would not appear on it. Treat it as a starting point for the sweep, not the
sweep.

Exposure the PM measured — front-load this one

⚠️ b398ad2 — BREAKING (behaviour), the one most likely to break this app:

a static readonly field is now stripped from a non-system caller's INSERT payload inside
engine.insert
, exactly as it already was on engine.update. […] Seeding a read-only column at
create time is a system act — use context.isSystem, a flow's runAs: 'system', a system hook
or a seed.

src/objects/contract.object.ts declares ~20 readonly: true fields — owner_id, the four
route_* booleans, and the nine lifecycle timestamps (submitted_at, review_started_at,
approved_at, signed_at, activated_at, archived_at, …). The file's own comment at line 26 says
"which is why readonly: true does not lock the engine out" — that sentence was written against
17.3 and is exactly the kind of claim this release re-opens.

The changeset's own text says a seed is a system act, so the seeder should be unaffected — ⛔ that
is a PM mechanism assumption, not a finding. Falsify it first, because if it is wrong the failure
mode is the one this repo already shipped once: #26, owner_id NULL on all 120 seeded contracts
and 我的合同 blank for every audience.
A silent column drop reports through onFieldsDropped /
droppedFields and a warn log — so read the boot log, do not just count rows.

Exposure the PM measured as absent (do not spend time re-deriving)

grep -rnE "\btimeout\b|\bttl\b|idleTimeout|sessionTimeout" --include=*.ts . → zero hits outside
node_modules. The same grep style returns 20+ hits for readonly: true, so the zero is real and not
a broken pattern. That clears:

  • e9fcd6b (duration-unit key renames hook.timeout/job.timeout → timeoutMs, ttl → ttlMs)
  • ed5d557 / 5071310 / bc0ac1d / 0145680 (driver-turso timeout refusals — this app has no turso driver)
  • 7629f4d (MetadataManagerConfig.cache retirement)

Also measured absent in src/: record_picker (clears 414c1fc), 'tree' fields (clears
fb77aa5), any ESignatureConfig / deadline key (clears the ESignatureConfig half of c463d03).

Re-verify these yourself before relying on them — they are one PM grep at one moment, and the
release list is a floor.

Exposure that needs a measurement, not a guess

  1. Flows (src/flows/: contract-intake, contract-approval, signature-record) — 21aabbc,
    52804cd, 53cf263 make FlowSchema refuse duplicate node ids, duplicate edge ids, and a region
    node id colliding with the top-level id space. pnpm validate is the instrument.
  2. Dashboards / datasets — 233222e closes timeDimensions[].dateRange's string arm to the
    date-range preset vocabulary, refusing anything else with 400 ANALYTICS_DATE_RANGE_UNRECOGNIZED.
    src/dashboards/legal.dashboard.ts:193 describes "the timeDimensions entry the executor
    shifts"
    . All three dashboards must be opened in a browser, not just validated.
  3. Positions / security — 8e0b297 makes positions[] on the session payload the security axis.
    This app binds position sets in src/security/bind-position-sets.ts and has seven positions.
  4. i18n — cf9bda4 makes the kernel's in-memory fallback learn the declared i18n.fallbackLocale
    (this app declares fallbackLocale: 'en'). pnpm lint:i18n-gate must still exit 0 and the
    zh-CN console must still be Chinese; Card 11 — translations: en (default) and zh-CN, with a gate that fails on a missing key #32 landed that surface yesterday and it is the newest,
    least-settled thing in the repo.
  5. 65846bc — a batch row now reports a unique-constraint refusal as UNIQUE_VIOLATION. This app
    declares unique indexes; the seeder inserts in batches.

Rider: closes #34 (declared, not smuggled)

#34 asks for two prose numbers to be corrected and says in its own body that the fix should "ride
the next card that touches these files"
. This is that card: it re-boots the app and re-measures both
quantities as a matter of course.

  • src/data/index.ts:81 says the demo installs 780 rows; it installs 820. One word.
  • scripts/demo.mjs:16-17 (0.813s) and src/data/plan-contracts.ts:28 (~1.8s, annotated
    (measured)) give two answers for the same interval. Two numbers in the repo's own prose are wrong or contradict each other (780 vs 820 rows; 0.8s vs ~1.8s) #34 is explicit: ⛔ do not swap one
    unverified number for another.
    Re-measure on your 17.4 boot, make the two sites agree — or delete
    the number from plan-contracts.ts and have it cite demo.mjs, so there is one place to be wrong.
  • Report the row count you actually observe. If 17.4 changes it, 820 is not automatically the
    answer
    — say what you measured and why it differs.

Put Fixes #34 in the PR body only if you actually re-measured both. If you did not, leave #34
open and say so.

Acceptance

  • pnpm validate && pnpm lint && pnpm typecheck && pnpm lint:i18n-gate — all four exit 0, exit codes
    captured before any pipe.
  • pnpm-lock.yaml shows 17.4.0 for all four direct dependencies and is committed.
  • A boot-log diff against main — same seed, clean .objectstack/data, both read at seeder
    quiescence (row count stable and log stable), not at the ready banner. Card 11 — translations: en (default) and zh-CN, with a gate that fails on a missing key #32's report shows why:
    its first baseline read 135 lines / 0 errors and the seeder then wrote 142 more. Report new
    warnings, onFieldsDropped / droppedFields, and any System started with degraded capabilities.
  • Browser (pnpm dev --seed-admin, Chromium at /opt/pw-browsers/, ⛔ no playwright install):
    sign in, open 我的合同 (the The demo opens on an empty screen: owner_id is NULL on all 120 seeded contracts, so 我的合同 › Launched by Me is blank for every audience #26 surface — confirm owner_id is populated), the contract detail
    page's seven tabs, and all three dashboards (the timeDimensions risk). Do one pass in zh-CN
    to confirm Card 11 — translations: en (default) and zh-CN, with a gate that fails on a missing key #32's bundle still resolves. Report what the console logged, not what you expect.
  • A changeset, or the skip-changeset label — changeset-check.yml gates every PR.
  • ⛔ Bump and migrate only. If 17.4 ships a capability that makes an existing workaround in this
    repo obsolete — the seed locale axis in c1d8f98 vs this repo's own OS_SEED_LOCALE switch is
    the known example — report it, do not adopt it here. That is a separate showcase card.
  • If a breaking change needs a product decision rather than a mechanical migration, stop and return
    needs_decision with options and a recommendation. ⛔ Do not decide it in the diff.

Activity

  1. self-assigned this
    on Sep 9, 2026
  2. zhuangjianguo commented on Sep 9, 2026

    @zhuangjianguo
    CollaboratorAuthor

    Claim: PM loop round 1 (seat repo:hotclm, taken this fire). Dispatched by the PM seat for its dev; the dev inherits this claim and posts no second one.

    Session: session_01R3n3GGzobdegM4HUzah1iR
    Branch: claude/issue-35-objectstack-17-4
    Worktree: hotclm-issue-35 (dedicated, off origin/main @ b9a2524)
    Domain: repo:hotclm (single-lane repo — no domain:* axis)
    File surface: package.json · pnpm-lock.yaml · whatever the 17.4 migration provably forces under src/ — plus, as the declared rider for #34, src/data/index.ts · src/data/plan-contracts.ts · scripts/demo.mjs (stop on breach; explain in the report)
    Container & model: L, mode:subagent, model: default judgement tier — scripts/pm/dispatch-gates.mjs is objectstack-side tooling keyed to that repo's file surface and has no reading to give here, so the tier is the PM's explicit decision under the "M/L and any card carrying design judgement" rule, not a quoted --tier line.
    Clause-②: no — a dependency bump in a consumer app neither relaxes an acceptance set nor widens a published surface. This repo produces no @objectstack/* contract; it consumes one.
    Thread-read: none (no comments on this card at claim time, 2026-09-09T13:5xZ)
    Serial constraints cleared: none to clear. Zero open PRs in this repo, zero other pm:dispatched cards, and every claude/issue-* branch on the remote is merged into main @ b9a2524 (git ls-remote --heads origin, 2026-09-09T13:50Z).

    fold-or-serial, answered explicitly: #34 and this card share the hot files src/data/ and
    scripts/demo.mjs. They are not folded — folding gate ① (same defect shape, same fix) fails: a
    dependency migration and a prose-number correction are different work. #34 rides this card instead,
    which is what #34's own body asks for ("ride the next card that touches these files"), and it is
    carried as a declared increment in the file surface above rather than as an unannounced extra.
    The reason it is the right moment and not merely a convenient one: #34's second half requires a
    re-measurement on a current boot, and this card has to take that boot anyway.


    Generated by Claude Code

  3. claude commented on Sep 9, 2026

    @claude
    Contributor

    os-dev-report

    {
      "issue": 35,
      "status": "done",
      "branch": "claude/issue-35-objectstack-17-4",
      "pr": "https://github.com/objectstack-ai/hotclm/pull/37",
      "premise_still_valid": true,
      "base": "b9a2524b2f5b3bc6a837c6ec26d6773f5cd5ee7a",
      "head": "ba4eb43",
      "summary": "Lockfile moved from 17.3.0 to 17.4.0 for all 57 resolved @objectstack packages; package.json byte-identical to main (the ^17.0.0 caret already admitted 17.4) and engines.protocol '^17' untouched. Zone 2 assumption 1 CONFIRMED, not falsified: a clean-database pnpm demo boot on 17.4 installs the same 820 rows with every readonly:true stamp present, field for field identical to the 17.3.0 baseline taken in the same worktree; b398ad2's strip is live for a non-system REST caller (a forged contract_number was dropped and the hook's ORD-2026-0017 stored) and the FLS-locked readonly families refuse with 403 PERMISSION_DENIED before the strip could be silent. Zone 2 assumption 2 re-verified and left alone: contract.object.ts:26 is still true on 17.4 (a non-system child insert moved the parent's readonly planned_amount 0 -> 12345). Browser-verified in Chromium after performing the README operator setup: 我的合同 shows rows for Business Requester 1, owner_id 120/120 populated at 43/43/34, all three dashboards render real numbers, all seven contract-detail tabs open, one zh-CN pass fully Chinese, zero HTTP 400-or-worse from any app endpoint. #34's two prose numbers were both re-measured on this run, so the PR carries Fixes #34.",
      "gates": [
        { "command": "pnpm install --frozen-lockfile", "exit": 0, "evidence": "Lockfile is up to date, resolution step is skipped" },
        { "command": "pnpm validate", "exit": 0, "evidence": "Validation passed (876ms); 26 author-time warnings (5 pre-existing + 21 new-in-17.4 field-no-consumers)" },
        { "command": "pnpm lint", "exit": 0, "evidence": "21 warning(s), 5 suggestion(s) (844ms)" },
        { "command": "pnpm typecheck", "exit": 0, "evidence": "tsc --noEmit, no diagnostics" },
        { "command": "pnpm lint:i18n-gate", "exit": 0, "evidence": "COVERAGE: 0 missing keys across 2 locale(s); 1525 keys expected" }
      ],
      "gate_capture_method": "each command redirected to its own log file, $? read on the next line; no pipe between the command and the exit code. All four run through /home/user/objectstack/scripts/pm/os-verify-lock.sh (ACQUIRED after 0s, held 18s).",
      "boot_diff": {
        "method": "same worktree, clean .objectstack/data, pnpm demo, both read at seeder quiescence (3 consecutive stable row-count reads AND 20s of log silence), not at the ready banner",
        "rows_installed": { "main_17_3_0": 820, "branch_17_4_0": 820 },
        "seed_result_line": { "main": "inserted:820 errored:120 referencesDropped:0", "branch": "inserted:820 errored:120 referencesDropped:0" },
        "readonly_stamp_nulls_over_120_contracts": { "main": "contract_number 0, category 0, direction 0, route_legal_head 0, execution_formalities 0, submitted_at 60, signed_at 48, activated_at 48", "branch": "identical" },
        "rollups": { "main": "planned_amount sum 47700500, 0 nulls", "branch": "identical" },
        "degraded_capabilities": { "main": "absent", "branch": "absent" },
        "no_such_table": { "main": "absent", "branch": "absent" },
        "plugins_loaded": { "main": 38, "branch": 38 },
        "onFieldsDropped_droppedFields_on_app_objects": { "main": "none", "branch": "none" },
        "author_time_rules": { "main": "42 rules / 5 warnings", "branch": "44 rules / 26 warnings" },
        "warnings_removed_by_17_4": "5 x [sql-driver] declared field 'id' asks for storage the platform's own 'id' column does not provide (5 -> 0)",
        "errors_added_by_17_4": "2, both on platform sys_* tables: [sql-driver] DATABASE_ERROR no such table _objectstack_sequences; ERROR Insert operation failed sys_oauth_resource UNIQUE constraint failed"
      },
      "browser": {
        "engine": "/opt/pw-browsers/chromium-1194/chrome-linux/chrome (pre-installed, no playwright install)",
        "http_400_or_worse_from_app_endpoints": 0,
        "page_errors": 0,
        "my_contracts_as_requester": "rows present; grouped Status Active 16; AMD-2026-0004, ICA-2026-0001, LSE-2026-0005, SUP-2026-0017 visible",
        "owner_id": "120/120 populated, 3 distinct owners, 43/43/34 split (matches README)",
        "dashboards": "legal_workbench 6/12/10/1 + Approved This Month 2 with compareTo; executive_overview value-by-currency bars + 12/19 + routes 11/41/23/4; finance_overview overdue 2176250 + 12 instalments + top-10 table",
        "contract_detail_tabs": "7 of 7 clicked and rendered: Overview, Versions, Review & Deviations, Approvals, Obligations & Payments (6), Signing & Archive, Discussion",
        "zh_CN": "full Chinese console via Accept-Language zh-CN (预览版/合同/我发起的/法务工作台/管理层看板/财务看板), widget titles and descriptions included",
        "recurring_console_lines_not_caused_by_this_diff": [
          "GET /favicon.ico -> 404 (/_console/favicon.ico and .svg both 200)",
          "GET /api/v1/auth/organization/list -> net::ERR_ABORTED with [AuthProvider] Failed to load organizations; the same route answers 200 to a direct call with the same cookie, so it is a Console startup race, and the route is new in plugin-auth 17.4"
        ]
      },
      "files_changed": [
        "pnpm-lock.yaml (+441 -440) — the whole bump",
        "scripts/demo.mjs (+7 -3) — #34 rider: the interval re-measured on 17.4, stated once",
        "src/data/index.ts (+1 -1) — #34 rider: 780 -> 820",
        "src/data/plan-contracts.ts (+8 -3) — #34 rider: second answer for the same interval deleted; the ordering claim the re-measurement falsified corrected without changing its conclusion"
      ],
      "files_not_touched": "package.json (byte-identical to main), objectstack.config.ts, pnpm-workspace.yaml, DESIGN.md, AGENTS.md, CLAUDE.md, LICENSE, CHANGELOG.md, docs/**, src/objects/**",
      "line_budget": "n/a — no skills/** or published-package surface in the diff. Hand-written diff is 16 added / 7 removed lines across 3 files; the remaining 441/440 is the generated lockfile.",
      "deviations": [
        "No changeset and no skip-changeset label. The card's acceptance names changeset-check.yml; this repo has no such workflow (.github/workflows holds only ci.yml), no .changeset/ directory, no @changesets/cli dependency, and get_label reports 'skip-changeset' does not exist in objectstack-ai/hotclm. AGENTS.md is consistent: 'Release notes: None per PR. CHANGELOG.md is written at release time by the maintainer.' Creating the label would install a gate nothing reads.",
        "package.json ranges deliberately left at ^17.0.0. pnpm update rewrote them to ^17.4.0 and re-sorted the dependency keys; that was reverted and pnpm install re-run, so the lockfile records specifier ^17.0.0 / version 17.4.0 and pnpm install --frozen-lockfile exits 0.",
        "Browser verification required the README's operator setup first, which is more than 'pnpm dev --seed-admin': self-registration is closed on this environment (SELF_REGISTRATION_CLOSED, posture invite_only), so the three Business Requester accounts were created through the admin create-user endpoint, granted clm_requester via sys_user_permission_set, and pnpm demo re-run so its upserts hand owner_id over. The dev admin was put in the clm_admin position (sys_user_position.position, spelled by NAME) because without it GET /api/v1/meta/app/clm serves it navigation: []. Without that step 我的合同 is empty on 17.3 and 17.4 alike, which is documented product behaviour and not a regression.",
        "Two probe rows (one clm_contract, one clm_payment_plan) were written into the local scratch database by the b398ad2 measurement. Local .objectstack/data only; nothing committed."
      ],
      "assumptions_tested": {
        "zone2_1_readonly_insert_strip_breaks_the_seed": "FALSIFIED as a risk / PM assumption CONFIRMED — 820 rows and every stamp present on 17.4, identical to baseline",
        "zone2_2_contract_object_ts_26_may_now_be_false": "still TRUE on 17.4 (planned_amount 0 -> 12345 from a non-system child insert), so the comment was NOT edited",
        "zone2_3_absence_greps": "re-verified: 0 hits for timeout|ttl|idleTimeout|sessionTimeout in any .ts outside node_modules (control: 35 hits for 'readonly: true' under src/), 0 for record_picker, 'tree', ESignatureConfig, deadline",
        "zone2_4_820_rows": "measured 820 on both sides",
        "card_233222e_timeDimensions_dateRange": "no dateRange string is authored anywhere in this app; the only timeDimensions surface is legal.dashboard.ts:193's { $gte, $lte } + compareTo, which the executor lowers itself. That tile rendered its number and comparison; ANALYTICS_DATE_RANGE_UNRECOGNIZED appears in no boot log or browser session.",
        "card_8e0b297_positions_axis": "session payload now carries positions: [platform_admin, org_owner, clm_admin, everyone] and the app's permission model resolves off it correctly",
        "card_65846bc_unique_violation": "no app-object unique refusal occurred; the one that surfaced is a platform sys_oauth_resource row (see findings)"
      },
      "mcp_calls": "5 — issue_read get #35, issue_read get_comments #35, issue_read get #34, issue_read get #26, get_label skip-changeset. The branch push, the PR creation and this comment went through git and repo-scoped REST, not MCP.",
      "open_questions": [],
      "out_of_scope_findings": [
        "noted, not filed: 17.4 RETIRES a boot-noise workaround-adjacent condition — the five [sql-driver] \"declared field 'id' asks for storage the platform's own 'id' column does not provide\" warnings present on every 17.3.0 boot are gone on 17.4.0. Nothing to adopt; recorded so the next reader does not hunt for them. Carrier: this PR body.",
        "noted, not filed: the pnpm-workspace.yaml better-auth 1.7.2 override fixture is NOT retired by 17.4 — sign-in still passes with the pins in place and the block still names objectstack-ai/objectstack#16186 as its removal condition. Left untouched. Carrier: this PR body.",
        "noted, not filed: OS_SEED_LOCALE vs c1d8f98's seed locale axis — the card named this as the known 17.4 capability that obsoletes a workaround here. Not adopted (Zone 1 rule 3). No measurement was taken of the new axis, because taking one means authoring against it; the PM's showcase card is the right carrier.",
        "PLATFORM (objectstack), needs PM to file — new author-time rule field-no-consumers fires 21 times on this app (17.4 runs 44 author-time rules where 17.3 ran 42). Every verdict is 'carrier-only': clm_clause.standard_text/fallback_text, clm_contract_type.description/template_placeholders, clm_contract_version.notes, clm_deviation.deviation_text/justification, clm_obligation.evidence/notes, clm_party.legal_representative/address/contact_phone/bank_name/bank_account/risk_note/screened_at, clm_review.comments/internal_note, clm_signature.envelope_id/signers/notes. Gates stay green (warnings). Deciding per field between 'give it a consumer' and 'remove the declaration plus its translation carriers' is product work on 21 fields — a hotclm card of its own, not a rider on a dependency bump. I did not file it: it needs a product decision on 21 surfaces and the PM owns that queue.",
        "PLATFORM (objectstack), needs PM to file — 17.4 logs two new ERROR lines on platform sys_* tables on any boot after the first, on a clean single-tenant sqlite dev database: (1) [sql-driver] DATABASE_ERROR ... SELECT \"tenant_id\" FROM \"_objectstack_sequences\" WHERE 1 = 0 - no such table: _objectstack_sequences (a column-existence probe against a table that does not exist yet, logged at error level); (2) ERROR Insert operation failed {\"object\":\"sys_oauth_resource\", \"UNIQUE constraint failed: sys_oauth_resource.identifier\"} raised from createWithAutonumberResync (a platform bootstrap row re-inserted on a database that already has it; 17.3 logged nothing here, consistent with 65846bc surfacing refusals that used to be swallowed). Neither touches app data. AGENTS.md's rule for platform gaps is report, never patch, and filing them belongs in objectstack-ai/objectstack with its PLATFORM_GAPS append, which is outside this card's repo and file surface.",
        "PLATFORM (objectstack), needs PM to file — the single-boot seed path diverges from its own log. CLM_DEMO_SEED=1 objectstack dev --compile --ui --seed-admin on a clean database (NOT pnpm demo) installs 760 rows, not 820: all 60 clm_review rows are refused with 'Reviewer is required', which is exactly the failure scripts/demo.mjs's two-boot handover exists to prevent. The loader then logs 'Deferred reference UNRESOLVED after pass 2 - clm_contract.owner_id stays NULL' for all 120 contracts while the database ends up holding the dev admin's id in owner_id on all 120. pnpm demo never takes that path so the product is unaffected, but a log that says NULL over a column that is not NULL is the kind of claim this repo's discipline exists to catch. Side effect worth recording: this resolves #26's open contradiction 2 - 'the runtime claims ownerless seeded rows for the dev admin once that account is minted (measured)' is true on the single-boot ordering and false on the two-boot one, so the original annotation was measured on a path #21's handover removed.",
        "noted, not filed: src/data/keys.ts says an unresolvable owner_id name 'lands NULL, silently'. It is not silent on either version - 17.3.0 and 17.4.0 both log 120 SeedLoader ERROR lines plus 20 Seeder WARN lines for it. One word, in a file this PR already touches, but it is outside #34's declared two numbers and outside what the bump forced, so it was left alone rather than smuggled in."
      ]
    }

    Generated by Claude Code

  4. zhuangjianguo commented on Sep 9, 2026

    @zhuangjianguo
    CollaboratorAuthor

    Review: ACCEPT — PR #37, head ba4eb43, CI green (2/2 Validate completed/success). Merging under the AGENTS.md merge delegation. Readings below are mine, taken against GitHub and the tree, not read off the report.

    ⛔ First: a premise in my own dispatch order was wrong, and the PR was right to refuse it

    I put changeset-check.yml and the skip-changeset label into #35's acceptance. No such gate exists in this repository. Verified myself on origin/main:

    git ls-tree --name-only origin/main .github/workflows/   -> .github/workflows/ci.yml   (only)
    git ls-tree --name-only origin/main .changeset/          -> (absent)
    git show origin/main:package.json | grep -i changeset    -> (no @changesets dep)
    

    I imported that criterion from the PM lane charter at references/lanes/hotcrm.md — which is the charter for hotcrm, a different repository. This is precisely the naming trap I recorded in the seat register (#36) about 40 minutes before writing the dispatch, and it caught me in the same fire. AGENTS.md here is the consistent authority: "Release notes: None per PR. CHANGELOG.md is written at release time by the maintainer."

    ⇒ The PR carries no changeset and no label, deliberately and correctly. Creating the label would have installed a gate nothing reads. Recorded as my error, not as the PR's deviation.

    Verification I performed independently

    Check Method Result
    Path surface git diff --name-only origin/main...FETCH_HEAD (⛔ not get_files, which exceeded the token cap on the lockfile, and ⛔ not the report's own list) pnpm-lock.yaml · scripts/demo.mjs · src/data/index.ts · src/data/plan-contracts.ts
    Governed surface grep of that list for DESIGN.md/AGENTS.md/CLAUDE.md/LICENSE/CHANGELOG.md/docs/design/ clean, zero hits
    package.json untouched absent from the diff list the "byte-identical" claim holds
    Scope vs claim declared surface was lockfile + package.json + whatever the migration forces under src/ + the three rider files actual is narrower than declared, never wider
    CI get_check_runs, after re-reading the PR object for its head 2 runs, both Validate, both completed/success, both on ba4eb43a8ff… = the PR object's head
    Arithmetic PR reports 457/447 across 4 files 441+7+1+8 = 457, 440+3+1+3 = 447 ✓

    The front-loaded risk was answered better than I asked

    I asked whether b398ad2 would strip the ~20 readonly: true stamps out of the seed and reproduce #26. The PR did not answer it by counting 820 rows — it answered it three ways, and the third is the one I did not think to ask for:

    1. The seeder is unaffected — stamps present at counts identical field-for-field to a 17.3.0 baseline taken in the same worktree.
    2. The strip is nonetheless live — a non-system REST insert carrying contract_number: 'FORGED-0001' got 201 with the hook's ORD-2026-0017 stored instead, read back out of SQLite rather than from the response body.
    3. Where it could have been silent, this app already refuses loudly — the same insert with submitted_at / approved_at / route_* answers 403 PERMISSION_DENIED, and so does a PATCH. §04's field-level security sits in front of the strip for every family whose forging would matter.

    (2) and (3) together are the real finding: the mechanism is armed, and this app's own FLS is what makes it non-silent. "820 rows, therefore fine" would have been a weaker answer to the same question.

    contract.object.ts:26 re-verified and left alone — a non-system child insert moved the parent's readonly planned_amount 0 → 12345, so the sentence is still true on 17.4. Not editing a comment that turned out to be correct is the right call; I had flagged it as suspect and it was not.

    Rider #34 — spot-checked by reading the diff, not the summary

    Fixes #34 is therefore earned under the card's own condition.

    Accepted with findings, not silently

    ⚠️ One collision with AGENTS.md the maintainer should see, which I am not deciding. AGENTS.md says a boot logging no such table is "not a passing boot", and 17.4 adds exactly that at ERROR level — no such table: _objectstack_sequences, a column-existence probe against a table that does not exist yet. It is platform-internal, touches no app data, and AGENTS.md's own rule for platform gaps is report, never patch, so the app cannot fix it. Net boot-noise change on 17.4: −5 warnings (the [sql-driver] declared field 'id' family is gone), +2 platform ERROR lines, +21 author-time warnings. Capability is not degraded — degraded capabilities absent, plugins 38 = 38, every app surface verified in the browser. I am accepting on that basis and routing the two ERROR lines upstream, but the judgement about sitting on a platform version that logs errors on boot is the maintainer's, not mine.

    ⚠️ The 21 new field-no-consumers warnings are a real finding about this showcase, not noise. 17.4 runs 44 author-time rules where 17.3 ran 42, and one of them reports 21 fields declared here that nothing reads or displays — clm_party.address / bank_account / contact_phone, clm_signature.envelope_id / signers, clm_review.internal_note, and more. In an exhibit, declared-equals-enforced matters double: a field a translation bundle names and nothing renders teaches every AI that copies this repo to declare inert metadata. Correctly refused as a rider on a dependency bump — deciding 21 fields between "give it a consumer" and "remove the declaration and its translation carriers" is product work. Filing it as its own card.

    The four out_of_scope_findings marked needs PM to file are mine now; filed below and linked from here.

    Landing

    AGENTS.md merge delegation (maintainer 2026-09-07, verbatim: 「你自己派发自己合并」): CI green on the head ✓ · ACCEPT recorded on the issue ✓ (this comment) · diff touches no governed surface ✓ (verified above, not asserted) · not a second REWORK round ✓. All four hold ⇒ ready, then squash-merge. This repo runs no merge queue (ci.yml only), so the direct squash AGENTS.md specifies is the sanctioned path here.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions