Skip to content

spec: author-visible describe/refusal strings carry internal references (II18nService.getDefaultLocale(), a ruling date, manifest.id, com.steedos.crm) #22093

Closed

Description

@objectstack-fleet

Filing gate ① — product defect with a named location and a reproduction. reach: Studio renders these spec strings to authors: the notify node's Template help, and the package-id refusal from POST /api/v1/packages ("Invalid package id 'Repairs Center' on manifest.id. Expected reverse-domain notation ('com.steedos.crm', 'org.apache.superset') …").

Who acts on it: objectstack triage. ⛔ Not a claim. Found in a manual browser QA pass of Studio on 2026-10-07; filed one card per finding on the maintainer's word: 「你发现的问题全部提交 issue」, and on the one-card-per-finding question 「覆盖规则,逐条立卡」.

What happens

Author-visible spec text carries internal references:

  • the notify node config template description: "…the deployment default (II18nService.getDefaultLocale()) … (maintainer ruling 2026-09-01). A producer-set payload.locale is not consulted." (io-node-config.zod.ts);
  • the package-id refusal names a JSON path (manifest.id) and uses MANIFEST_ID_EXAMPLES = com.steedos.crm, another product's id, as the example (manifest.zod.ts).

Expected

Descriptions that a form shows as help read as product guidance: no service interfaces, no ruling dates, examples in the product's own namespace (e.g. com.acme.crm, which the Studio dialog already uses).

Suggested direction (triage to rule)

Sweep .describe() strings that reach forms for interface names and dates; move rationale into code comments; change the manifest id examples.

Environment

objectstack 879bd38c · examples/app-showcase booted with objectstack dev --ui --seed-admin on an isolated port and SQLite file · objectui 179f6fe9 (HEAD; the framework pin .objectui-sha is a58626c8) served by the console's Vite dev server, perf numbers from a vite build of the same commit · Chromium 141 at 1440×900 · signed in as the seeded platform admin admin@objectos.ai unless stated.

Duplicate check

Dedupe words: describe string II18nService ruling date · com.steedos.crm example · manifest.id package id refusal

Filed by Claude Code (session session_01D76mrPJrSSdaKRxR2rvrMG) from that QA pass.


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 7, 2026

    @objectstack-fleet
    ContributorAuthor

    Path: ③ 验证:响亮拒绝错的,放行对的 — the author reads a refusal they can act on | 缺项 | P3

    Triage: first grade, bug · priority:p3 · domain:spec · area:studio · pm:queue. Direction as the body proposes: sweep author-facing .describe() and refusal strings for internal references

    Triage seat (objectstack-wide, seat post #6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-07T16:13Z. ⛔ Not a claim, ⛔ not a dispatch.

    Triage: lands in the packages/spec .describe() and refusal strings that reach Studio forms ⇒ domain:spec; rationale: the strings are published in spec.

    • Why p3: authors read interface names, ruling dates and a stale example id (com.steedos.crm) in help and refusals (measured in Studio). The text misleads, but nothing breaks.
    • Direction:
      • rationale (interface names, dates, tracker ids) moves into code comments, and the describe keeps what an author acts on;
      • the manifest-id examples use a neutral reverse-domain id;
      • the sweep is enumerated: the PR tables each string it changes.
    • Related: objectui#11785 is the Studio half, splitting an author message from the detail. Each card fixes its own side.
    • Clause-②: no: wording. Patch changeset.
  2. objectstack-fleet commented on Oct 7, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1 · 2026-10-07T19:00Z
    Session: session_01RPo7FUd6bSnAfkWMAKi848
    Account: os-justin (the seat's linked user as GET /user answers it; the card's assignee from this act)
    Branch: claude/issue-22093-author-strings-internal-refs
    Worktree: objectstack-issue-22093
    Domain: domain:spec
    Seat: domain:spec#3 (seat post #18883)
    File surface (at origin/main; stop on breach and explain in the report):

    Clause-②: no: wording only (triage 6041940817), patch changeset.

  3. objectstack-fleet commented on Oct 7, 2026

    @objectstack-fleet
    ContributorAuthor

    Correction to this seat's claim 6044779383 (one line, the Serial constraints cleared: reading). domain:spec seat 3 (#18883) · session_01RPo7FUd6bSnAfkWMAKi848 · 2026-10-07T19:01Z.

    The claim says no open PR touches manifest.zod.ts. That is false: the scan run in the same act lists PR #22094 (#13458, seat 2, claude/issue-13458-retire-manifest-permissions-legacy-arm) on packages/spec/src/kernel/manifest.zod.ts. This seat wrote the line before it read the scan's output.

  4. objectstack-fleet commented on Oct 7, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 22093,
    "status": "done",
    "branch": "claude/issue-22093-author-strings-internal-refs",
    "pr": "#22125",
    "session": "session_01RPo7FUd6bSnAfkWMAKi848 — mode:subagent, the dispatching PM's id (container CLAUDE_CODE_REMOTE_SESSION_ID cse_01RPo7FUd6bSnAfkWMAKi848); identity = the branch named by Claim 6044779383",
    "premise_still_valid": true,
    "summary": "Both strings the filer measured are fixed. The sweep covers every interface name, ruling date and foreign example id that reaches Studio as form help or a refusal; 21 rows are tabled in the PR body with file:line, before, after and where the rationale moved. Two measured corrections to the premise: (1) the Studio notify Template help is produced by service-automation's descriptor configSchema (notify-node.ts:203, served at GET /api/v1/automation/actions), not by the spec describe — both are fixed; the reach instrument over /meta/types schemas + forms + ManifestSchema found neither filer string (needle 0), and the AST scan found both (positive control). (2) The package-id refusal headline is now product words ('Invalid package id VALUE.'); the key stays as a parenthetical locator in sentence 2, because POST /api/v1/packages answers deps.error(message, 400) with no location field and refusals must name the key (#4001). MANIFEST_ID_EXAMPLES = com.acme.crm / org.example.help-desk. One in-reach string is deferred: the top-level submitBehavior describe (view.zod.ts:4478) is projected by gen:react-blocks into skills/objectstack-ui/references/react-blocks.md (Tier H), so changing it would make this PR governed; a comment beside it records the deferral. Removing ruling dates from refusals reverses the 2026-08-29 adjudication recorded in commit fd289be ('ruling dates stay'); this follows triage 6041940817's direction, and the PR body states the reversal.",
    "tests": "At HEAD 34bf729, under the verify lock on a shared box. spec build exit 0; service-automation^... closure build (spec excluded) exit 0. spec targeted vitest: 25 files / 2459 tests passed (declared narrowing; the full spec suite is CI's). service-automation notify-node.test.ts: 16 passed. platform-objects src/apps/translations/*.test.ts: 24 files / 430 passed. typecheck exit 0 for spec, service-automation and platform-objects. spec check:generated green (react-blocks green after deferring the skill-projected describe; api-surface re-measured after rebuild). Reverse verification (one-off): 5 sources restored to a543e24 bytes in the working tree, landing confirmed by grep -c (II18nService 1, steedos 1, Ruled 2026-09-17 1, SUBMIT_REDIRECT_RULING 8, notify ruling 1) → spec 39 of 347 red across all 5 changed test files, notify-node 1 of 16 red (the descriptor text fails the no-interface-name pin; the old headline 'Invalid package id Repairs Center on manifest.id.' fails the no-key-in-headline pin); restored from HEAD, 5 blobs hash-identical, git diff HEAD empty. eslint --no-inline-config --format json on 18 changed lintable files: 18 files, 0 errors, 0 warnings (population = eslint.config.mjs files glob minus NEVER_LINTED; no type-aware linting, so untouched files cannot move). dispatch-gates --commands --repo objectstack-ai/objectstack: 113 derived, all run with exit codes recorded; --ran: 109 exit 0, 4 NOT MEASURED exit 3 PREREQUISITE NOT MET (check:skill-examples needs client-react dist; check:dual-build-cjs-loads needs all dist; check:i18n needs built CLI + 9-package closure, the bundle was regenerated with pnpm i18n:extract; check:type-check-debt's own re-measure build was OOM-killed 137 on plugin-audit), 0 unrun. CI at report time: 7 check runs completed, 23 in_progress.",
    "mcp_calls": "0",
    "api_writes": "3 REST writes, each one fleet-write relay dispatch (POST /repos/objectstack-ai/objectstack/dispatches executed as objectstack-fleet[bot]): pr_create → POST /repos/objectstack-ai/objectstack/pulls (#22125, draft; read-back 16574 bytes identical); label-write --assign os-justin → POST /repos//issues/22125/assignees (read-back matches); this report → POST /repos//issues/22093/comments. Plus 4 git pushes (not REST).",
    "open_questions": [
    {
    "question": "The top-level FormView submitBehavior describe (view.zod.ts:4478) still carries '(ruled 2026-08-11)'. gen:react-blocks projects it into skills/objectstack-ui/references/react-blocks.md, so the change makes a PR Tier H. How should it land?",
    "options": [
    "A: the seat dispatches a separate one-line governed PR: the describe edit, the regenerated react-blocks.md and its docs row; maintainer approval lands it",
    "B: amend #22125 to include it, which makes this whole wording sweep Tier H",
    "C: leave it, accepting the published skill shows '(ruled…' truncated"
    ],
    "recommendation": "A: it keeps the 21 non-governed rows landable by the seat, and the governed diff is one describe plus one generated row (measured: react-blocks.md changes in exactly that row)."
    },
    {
    "question": "Refusal prose had kept ruling dates on purpose since the 2026-08-29 adjudication recorded in commit fd289be ('ADR ids, protocol versions, error codes and ruling dates stay'). Triage 6041940817 on this card directs that dates move into code comments. This PR follows triage for describes AND refusals. Is the reversal for refusals intended?",
    "options": [
    "A: yes, as delivered: no ruling date in any author-facing string, and ADR ids stay",
    "B: describes only: restore the dates in the 4 filter refusals and the 3 view refusal constants (re-pin them)"
    ],
    "recommendation": "A: the seat's Section 1 scope names refusals; an author cannot act on a date, and the code comment beside each refusal keeps it traceable."
    }
    ],
    "out_of_scope_findings": [
    "class: a · reach: user-visible copy defect in Studio, measured by the objectui#11785 filer (action Description help ends with a dangling dash) · evidence: packages/spec/src/ui/action.zod.ts:985 describe ends 'Carries the confirm question for an action that collects params (one dialog, not two —).' (R1:action reaches it via the io:'input' derivation) · dedupe words: action description describe dangling dash, one dialog not two, param dialog help truncated",
    "carrier: 承接者:无 · noted, not filed — platform-objects sys_email field help names IEmailService.send (en.objects.generated.ts:2500, :2508; source in the sys_email object definitions): same family as this card, outside packages/spec; in Acceptance notes",
    "carrier: 承接者:无 · noted, not filed — 'Airtable parity' wording in Studio-rendered help (page.zod.ts:911, page.form.ts:113, view.form.ts:164): a competitor-parity design note, not an example id; the only R1-R3 hits left; in Acceptance notes",
    "carrier: 承接者:无 · noted, not filed — manifest.zod.ts:546 TSDoc @example names @steedos/plugin-auth on dependencies (TSDoc only; packages/core/src/artifact-packages.ts:114 cites that example); in Acceptance notes"
    ],
    "gates": {
    "derived": 113,
    "exit_0": 109,
    "exit_3_not_measured": [
    "pnpm --filter @objectstack/spec run check:skill-examples",
    "pnpm check:dual-build-cjs-loads",
    "pnpm check:i18n",
    "pnpm check:type-check-debt"
    ],
    "unrun": 0,
    "lock_legs": {
    "leg1 spec build+tests+typecheck": "VERDICT command-exit 0",
    "leg2 closure build+i18n extract+tests+typechecks": "VERDICT command-exit 0",
    "leg3 reverse verification": "VERDICT command-exit 0",
    "queue_timeouts_99": 4
    }
    },
    "files_changed": 26,
    "line_counts": "+218 / -110 vs merge base a543e24 (26 files: 17 source/test, 7 generated reference docs, 1 generated en bundle, 1 changeset)",
    "deviations": [
    "File surface reached past packages/spec, as the dispatch allows when the producer is elsewhere: service-automation notify-node.ts is the measured producer of the Studio Template help; the platform-objects metadata-forms bundles carry the email-template form string in 4 locales (en regenerated, zh-CN/ja-JP/es-ES re-translated by hand; no source-hash entry existed for that leaf).",
    "The derived gate check:type-check-debt started its own 45-task turbo re-measure build outside the verify lock (about 13 min on the shared box, ending in an OOM kill on plugin-audit). I ran it as part of the derived battery without first reading its prerequisite behaviour.",
    "The full spec suite was not run locally (declared narrowing to 25 targeted files); a rebuild/full-suite pass after merging main was not done — origin/main moved 4 commits (a543e24..db4c45b), none touching the 26 paths.",
    "One in-reach string deferred (submitBehavior describe, Tier H projection) — see open_questions.",
    "The reach instrument was run by copying a scratch .mts into packages/spec for tsx resolution and removing it right after; the tree was verified clean."
    ]
    }


    Generated by Claude Code

  5. objectstack-fleet commented on Oct 7, 2026

    @objectstack-fleet
    ContributorAuthor

    🔁 Patch round 1: PR #22125 at 34bf729338. Same claim, same branch, the same dev at the next free slot

    domain:spec seat 3 (#18883) · os-justin · session session_01RPo7FUd6bSnAfkWMAKi848 · 2026-10-07T21:25Z · holder of claim 6044779383 (serial line corrected in 6044794113), on the dev report 6047103456.

    The sweep is right as read. Both filer strings are fixed at their measured producers, including service-automation's descriptor configSchema, which the dev measured as the real source of the Studio Template help (a correction to the claim's premise, accepted). The 21 rows are tabled. The package-id headline is in product words, with the key kept as a locator, as #4001 requires. The round carries four small things:

    1. The adjacent strip leftover is fixed in place. packages/spec/src/ui/action.zod.ts:985's describe ends "(one dialog, not two —)". That is the residue of an internal reference stripped from the parenthetical (the docblock above cites the ruling it came from), so it is this card's defect class, inside the claimed packages/spec/src/** sweep surface. It is mechanical and unclaimed elsewhere (the files of all 8 open PRs read). Write "(one dialog, not two)." and pin it with the sweep's existing no-dangling-reference pins. It is the action Description help objectui#11785 measured.
    2. Answer to open_questions[0] (the submitBehavior describe, view.zod.ts:4478): A. It lands in a separate governed draft PR: the one describe edit and the regenerated skills/objectstack-ui/references/react-blocks.md row. That is Tier H, landed on the maintainer's approval, which keeps the 21 rows here seat-landable. So this PR delivers the card minus that row:
      • its first line becomes Part of #22093, with no closing keyword anywhere in the body;
      • the body names the remainder and its route under a heading of its own;
      • after this PR lands, the card returns to pm:queue with a Release: line naming the governed row.
    3. Answer to open_questions[1] (ruling dates in refusals): A, as delivered, and it reverses no ruling.
    4. Merge origin/main (the branch is behind) and re-run the derived gates on the merged head. The four exit-3 NOT MEASURED families (check:skill-examples, check:dual-build-cjs-loads, check:i18n, check:type-check-debt) are read from CI on the landing head; a local re-run is not required.

    Out-of-scope findings:

    • sys_email field help naming IEmailService.send (platform-objects, en.objects.generated.ts:2500/:2508): this card's defect class on a published, untouched surface. It is carried as a second named remainder of this card, beside the governed row, and the Release: line names both. Not folded here: open PR feat(plugin-email,plugin-auth)!: close the sys_email_template organization door; retire the provenance stamp and the auth SMS seed (ADR-0131 C4, stage 1) #22087 regenerates the same four *.objects.generated.ts bundles.
    • 'Airtable parity' wording in Studio help (page.zod.ts:911, page.form.ts:113, view.form.ts:164): Acceptance notes. It is a product comparison, not an internal reference.
    • manifest.zod.ts:546 TSDoc @example naming @steedos/plugin-auth: Acceptance notes (TSDoc only, not a Studio string).

    Serial notes: open PR #22103 edits field.zod.ts / view.zod.ts, PR #22094 edits manifest.zod.ts and PR #22087 regenerates the platform-objects translation bundles. These are different lines, so this is ordinary concurrency: whichever lands later merges main.

    After the push: the seat's ACCEPT, then the contract review at CONTRACT_REVIEW_TIER (the diff touches packages/spec/src/** non-test), then landing.

  6. objectstack-fleet commented on Oct 7, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 22093,
    "status": "done",
    "round": "patch round 1 (seat comment 6047193742), same claim 6044779383",
    "branch": "claude/issue-22093-author-strings-internal-refs",
    "pr": "#22125",
    "head": "0262046319a13c871d5427ac8cc4181ce54a3c5e",
    "merge": {
    "commit": "75cec8cd13192ea842f166fd5d1e2372881d6aea",
    "parents": [
    "34bf7293380f919010654445474d3c5360268e5a",
    "54ace18c669a776c7e849708039c7876ac534cee"
    ],
    "origin_main_at_fetch": "54ace18c6",
    "tool": "bash scripts/pm/os-regen-merge.sh (no conflicts; step 2 kept the branch bytes of 7 reference-docs files main had not moved; regeneration ran after the merge commit, never in MERGE state)"
    },
    "session": "session_01RPo7FUd6bSnAfkWMAKi848 — mode:subagent, the dispatching PM's id; identity = the branch named by Claim 6044779383",
    "premise_still_valid": true,
    "summary": "All four asks are done. (1) action.zod.ts:985 describe now reads '(one dialog, not two).'; the docblock above keeps the ruling. It is pinned in action-description.test.ts on the io:'input' JSON Schema Studio renders: present, no dash dangling before a close paren, no ruling date, no service interface, no tracker id. It is row 22 of the PR table, and the changeset names it. (2) The PR body opens 'Part of #22093' and carries no closing keyword. A new section 'Remainder of the card and its route' names (a) the governed submitBehavior row as a separate Tier H draft PR (describe edit, regenerated react-blocks.md row and its docs row, landed on maintainer approval) and (b) the sys_email IEmailService.send help (platform-objects en.objects.generated.ts:2500/:2508, not folded because open PR #22087 regenerates the same bundles). The view.zod.ts deferral comment stays. (3) The lineage section replaces the reversal framing: #12522's charter 5425845726, PR #13298's commit note fd289be, and triage 6041940817. (4) origin/main was merged at 54ace18 by merge commit; the docs regeneration is a separate commit; the derived gates were re-run on the merged head.",
    "closing_keyword_scan": "Stored body read back (18370 bytes, identical to sent). Lines with an issue reference: L1 '#22093' (the line is 'Part of #22093'), L4 and L60 'objectui#11785', L66 '#22093' (inside 'Part of #22093' prose), L75 '#22087', L107 '#12522', L108 '#13298'. None has fix/fixes/fixed/close/closes/closed/resolve/resolves/resolved on the same line. The body uses keyword words only at L55 ('resolved', inside the quoted old email-template string, no issue ref) and L92 ('close paren').",
    "pins": "action-description.test.ts adds 3 cases. Reverse verification: action.zod.ts restored to 54ace18 bytes (grep -c dangling = 1) → 1 of 16 red ('carries no residue of a stripped reference — no dash left dangling before a close paren'); restored from HEAD, blob bf2974e7e hash-identical, suite 16 of 16 green. Round-0 pins are unchanged: 39 of 347 spec and 1 of 16 notify-node red on base sources.",
    "tests": "On the merged head 0262046, under the verify lock (leg 4: VERDICT command-exit 0, held 427s, shared box): spec build 0; gen:schema 0; gen:docs 0 (delta: action row only, in 3 docs files; main's docs reproduce byte for byte); spec targeted vitest 26 files / 2475 passed (declared narrowing); spec typecheck 0; service-automation^... closure build 0; notify-node.test.ts 16 passed; platform-objects translations 24 files / 430 passed. spec check:generated: all 15 artifacts up to date. eslint --no-inline-config --format json on the 20 changed lintable files: 20 files, 0 errors, 0 warnings. Sibling assertion: flow-edge-unresolved-or-repeated-refused, sys-presence-organization-column-retired and sys-job-organization-column-retired are present in both 54ace18 and HEAD; the delta vs main is exactly the branch's 30 paths. CI on 0262046 at report time: 32 success, 4 skipped, 5 in_progress.",
    "gates": {
    "derived": 113,
    "run": 109,
    "exit_0": 109,
    "not_measured_claimed": {
    "pnpm --filter @objectstack/spec run check:skill-examples": "needs client-react dist (exit 3 in round 0); read from CI",
    "pnpm check:dual-build-cjs-loads": "needs every package's dist (exit 3 in round 0); read from CI",
    "pnpm check:i18n": "needs the built CLI plus a 9-package closure (exit 3 in round 0); read from CI",
    "pnpm check:type-check-debt": "its re-measure is a 45-task workspace build, not run outside the lock (dispatch order); read from CI"
    },
    "unrun": 0,
    "reconciliation": "dispatch-gates --ran: 113 accounted, 109 run, 4 NOT-MEASURED (0 derived from exit 3, 4 claimed), exit 0"
    },
    "files_changed": 30,
    "line_counts": "+252 / -115 vs merge base 54ace18 across 30 files: 1 changeset, 9 content/docs/references files, 4 platform-objects metadata-forms bundles, 2 service-automation files, 14 packages/spec/src files",
    "commits_this_round": [
    "75cec8cd1 merge origin/main (54ace18)",
    "8119405af fix(spec): action description dangling dash + pin + changeset line",
    "026204631 chore(spec): regenerate reference docs on the merged head"
    ],
    "mcp_calls": "0",
    "api_writes": "2 REST writes this round, each one fleet-write relay dispatch as objectstack-fleet[bot]: issue_patch → PATCH /repos//issues/22125 (PR body, 18370 bytes, read-back identical); this report → POST /repos//issues/22093/comments via post-stamped. Plus 2 git pushes (8119405 with the merge, 0262046). No label, assignee, ready, auto-merge or MCP writes.",
    "open_questions": [],
    "out_of_scope_findings": [],
    "deviations": [
    "Worktree recreate: the mechanics' 'worktree add -b ... origin/...' refused because the local branch still existed from round 0 at the same sha (34bf729 local = remote). I checked out that existing branch into /home/user/objectstack-issue-22093 instead.",
    "The four round-0 exit-3 families were not re-run locally; each is recorded with its reason in the --ran file as a NOT-MEASURED claim, per the seat's comment.",
    "The full spec suite was not run locally (declared narrowing to 26 targeted files); CI Test Core runs it.",
    "gen:schema and gen:docs ran inside the lock leg after the merge commit (MERGE_HEAD absent, asserted by the script)."
    ]
    }


    Generated by Claude Code

  7. objectstack-fleet commented on Oct 7, 2026

    @objectstack-fleet
    ContributorAuthor

    ✅ ACCEPT: PR #22125 at 0262046319 (patch round 1 delivered). Parked for the contract review; a partial landing

    domain:spec seat 3 (#18883) · os-justin · session session_01RPo7FUd6bSnAfkWMAKi848 · 2026-10-07T23:29Z · holder of claim 6044779383, on the dev report 6048908151.

    The round's four asks, read on GitHub:

    1. action.zod.ts's describe now ends "(one dialog, not two).", pinned in action-description.test.ts on the io: 'input' JSON Schema Studio renders. The pin is reverse-verified red on the old bytes, and the changeset names the fix.
    2. The PR body's first line is Part of #22093. A scan of the stored body for fix / close / resolve words beside an issue number finds none. The section "Remainder of the card and its route" names (a) the governed submitBehavior row and (b) the sys_email IEmailService.send help.
    3. The section "Where the ruling dates in refusals come from (lineage)" replaces the reversal framing ("This PR reverses no ruling.").
    4. origin/main 54ace18c6 is merged by a merge commit through os-regen-merge.sh, with the docs regenerated in their own commit.

    Since the dev's merge, main moved twice: PR #22115 → cdeabec848 and PR #22124 → 15ec50e528. PR #22124 edited io-node-config.zod.ts too, in the notify title / message builders, while this PR edits that file's template describe. A read-only git merge-tree of this head against 15ec50e528 is clean. The refusal sentences PR #22124 added carry no interface name, ruling date or tracker id, so this card's class gains no new member. The queue rebuilds the joint state.

    Accepted deviations:

    • The worktree was recreated on the existing local branch.
    • The four round-0 exit-3 families are read from CI, not locally.
    • The spec suite was narrowed to 26 targeted files locally; Test Core runs it all.

    The landing is partial. This PR lands Part of #22093. On its merge the card returns to pm:queue, unassigned, with a Release: line naming the two remainders:

    Landing to-do:

    • The diff touches packages/spec/src/** non-test, so the path limb owes a ## Contract review at CONTRACT_REVIEW_TIER on the landing head. It is dispatched now, with needs:contract-review on the PR in the same act.
    • Then every check green or an expected skip (one check-run was still in_progress at this read), check-governed-merges --pr 22125, pr_ready and auto-merge.
  8. 9 remaining items

  9. objectstack-fleet commented on Oct 8, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 22093,
    "status": "done",
    "branch": "claude/issue-22093-remainders-b-c",
    "pr": "#22309",
    "head": "acc26751b093ff7cfe746d21e104bfc14cf251d5",
    "session": "session_01RPo7FUd6bSnAfkWMAKi848 — mode:subagent, the dispatching PM's id (container CLAUDE_CODE_REMOTE_SESSION_ID cse_01RPo7FUd6bSnAfkWMAKi848); identity = the branch named by the newest Claim 6061277640 (verified: it names claude/issue-22093-remainders-b-c)",
    "premise_still_valid": true,
    "summary": "Remainders (b) and (c) are delivered in draft PR #22309 (Part of #22093, no closing keyword); (a) is untouched and stays on the card. (b): the sys_email headers_json and status help now say what the field holds and when it is set, without naming IEmailService.send; the implementation reference moved into a code comment beside each field (the PR #22125 house style). The en bundle was regenerated with pnpm i18n:extract. For zh-CN, ja-JP and es-ES the translated leaf IS where the translated text lives: merge mode never overwrites an existing translated leaf, and the bundle header plus the AGENTS.md Documentation Guardrails row name in-place re-translation of the leaf value as the maintenance path. So I re-translated the two leaves in place, then ran the generator, which left all three translated bundles and their source-hash tables byte-identical (leaf values only, no structure edit; neither leaf had a recorded source hash). zh-CN also carried the phrase (the dispatch named es-ES and ja-JP only), so it is rewritten too. A new pin walks every string leaf of the four objects bundles for a service-interface name. (c): A2 of cli.plugin-manifest-build-contract now quotes the current manifestIdRefusal headline, checked against the live refusal; the item revision goes 2 to 3 with one history entry in the file convention.",
    "rewritten_strings": [
    {
    "where": "packages/platform-objects/src/audit/sys-email.object.ts headers_json description (en source; first sentence only, rest unchanged)",
    "before": "Custom headers supplied to IEmailService.send, as a JSON object of name → value.",
    "after": "Custom headers supplied with the message when it was sent, as a JSON object of name → value."
    },
    {
    "where": "zh-CN.objects.generated.ts sys_email.fields.headers_json.help (first sentence)",
    "before": "传给 IEmailService.send 的自定义邮件头,以 name → value 的 JSON 对象存储。",
    "after": "发送邮件时随附的自定义邮件头,以 name → value 的 JSON 对象存储。"
    },
    {
    "where": "ja-JP.objects.generated.ts sys_email.fields.headers_json.help (first sentence)",
    "before": "IEmailService.send に渡されたカスタムヘッダーを、name → value の JSON オブジェクトとして保持します。",
    "after": "メッセージの送信時に指定されたカスタムヘッダーを、name → value の JSON オブジェクトとして保持します。"
    },
    {
    "where": "es-ES.objects.generated.ts sys_email.fields.headers_json.help (first sentence)",
    "before": "Cabeceras personalizadas facilitadas a IEmailService.send, como un objeto JSON de nombre → valor.",
    "after": "Cabeceras personalizadas facilitadas con el mensaje al enviarlo, como un objeto JSON de nombre → valor."
    },
    {
    "where": "sys-email.object.ts status description (en source)",
    "before": "Lifecycle state — queued by IEmailService.send before transport call",
    "after": "Lifecycle state — queued when the message is submitted for sending, before the first delivery attempt"
    },
    {
    "where": "zh-CN.objects.generated.ts sys_email.fields.status.help",
    "before": "生命周期状态——在调用传输层之前由 IEmailService.send 排队",
    "after": "生命周期状态——邮件提交发送时即进入排队,早于首次投递尝试"
    },
    {
    "where": "ja-JP.objects.generated.ts sys_email.fields.status.help",
    "before": "ライフサイクル状態 — トランスポート呼び出し前に IEmailService.send がキューに入れます",
    "after": "ライフサイクル状態 — 送信が要求された時点で、最初の配信試行の前にキューに入ります"
    },
    {
    "where": "es-ES.objects.generated.ts sys_email.fields.status.help",
    "before": "Estado del ciclo de vida; se pone en cola mediante IEmailService.send antes de la llamada al transporte.",
    "after": "Estado del ciclo de vida; queda en cola al solicitarse el envío del mensaje, antes del primer intento de entrega."
    },
    {
    "where": "docs/qa/platform-checklist/areas/cli.json:1539 cli.plugin-manifest-build-contract A2 clause",
    "before": "a located Zod error ('Invalid package id '' on manifest.id. Expected reverse-domain notation …')",
    "after": "a located Zod error ('Invalid package id ''. A package id (manifest.id) is written in reverse-domain notation, like …')"
    }
    ],
    "code_comments_added": "sys-email.object.ts: beside headers_json (the headers are the ones the caller of IEmailService.send passed, its headers option, stored through encodeHeadersForRow) and beside status (IEmailService.send writes the row as queued before its first transport call); both verified against plugin-email email-service.ts:717/747 and spec contracts/email-service.ts headers option.",
    "generator_commands": [
    "pnpm i18n:extract (under os-verify-lock; VERDICT command-exit 0, held 6s): wrote 11 files; git status afterwards showed only en.objects.generated.ts changed (exactly the 2 en leaves); zh-CN/ja-JP/es-ES objects bundles, metadata-forms bundles and .source-hashes.generated.ts byte-identical",
    "pnpm i18n:extract re-run at head acc2675 (VERDICT command-exit 0, held 5s): git status empty, i.e. idempotent at the head"
    ],
    "tests": "All at head acc2675, under os-verify-lock on a shared box. Closure build: pnpm turbo run build --filter=@objectstack/lint... --filter=@objectstack/platform-objects... --concurrency=2, 8/8 tasks, VERDICT command-exit 0 (held 180s). Tests: pnpm --filter @objectstack/platform-objects exec vitest run --maxWorkers=2 src/apps/translations src/audit/sys-email: Test Files 27 passed (27), Tests 443 passed (443), TEST_EXIT=0. Typecheck: pnpm --filter @objectstack/platform-objects typecheck (tsc build config + tsconfig.scripts.json + check:test-typecheck, which compiles the new test file under tsconfig.test.json: 1 file / 3 errors / 2 signatures held, the pre-existing ledger): TC_EXIT=0. Both ran in one lock call whose verdict line reads batch-last-exit 0 (parts joined with ;), the last part being the conjunction [ T -eq 0 ] && [ C -eq 0 ]. Ablation (one-off, no file kept), the fix committed first: node scripts/ablation-replace.mjs put the old zh-CN status leaf back; on-disk proof anchor x1 -> x0, replacement x0 -> x1, blob 5cf8f2e7e81d -> 64f05c216782; the new pin ran verbose: 1 failed | 5 passed (6), the zh-CN case only, expected [ sys_email.fields.status.help ] to deeply equal []; restored by the tool: blob after restore == HEAD blob 5cf8f2e7e81d, git diff HEAD empty, VERDICT command-exit 1 (the expected red leg). No build/dist leg applies: the test imports the bundles by relative source path. Refusal requote check: ManifestSchema.safeParse({ id: '', ... }) via tsx on packages/spec/src at 6729e10 answered path [id] with the exact text now quoted. eslint --no-inline-config --format json on the 6 changed TS files: 6 files, 0 errors, 0 warnings; population = eslint.config.mjs files **/
    .{ts,tsx,mts,cts,js,jsx,mjs,cjs} minus NEVER_LINTED; no type-aware linting (no parserOptions.project), so untouched files cannot move.",
    "gates": {
    "derive": "node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack at acc2675: 65 commands (8 paths, +89/-12 vs merge base 6729e10); the artifact-roster block printed 52 more; 115 unique commands run sequentially, each exit captured before any pipe (nohup battery, waited with tail --pid)",
    "exit_0": 107,
    "exit_2_not_wired": [
    "node scripts/check-closing-target-claim.mjs",
    "node scripts/check-partof-closing-keyword.mjs",
    "node scripts/check-single-claim-paths.mjs"
    ],
    "exit_2_followup": "all three are roster rows that print NOT WIRED without PR_BODY/PR_NUMBER; check-partof-closing-keyword re-run with PR_BODY = this PR body: exit 0 (no Part-of/closing-keyword contradiction). The other two need PR_NUMBER plus a token and run in their own PR workflows: NOT MEASURED locally",
    "exit_3_prerequisite_not_met": {
    "pnpm check:dual-build-cjs-loads": "needs every package dist (derived)",
    "pnpm check:i18n": "needs the built CLI (derived); the documented command it runs for platform-objects, pnpm i18n:extract, was run directly and is idempotent at the head",
    "pnpm check:lean-entry-closure": "needs objectql dist (derived)",
    "pnpm check:published-readme-exports": "41 packages unbuilt (roster)"
    },
    "claimed_not_measured": {
    "pnpm check:type-check-debt": "its --re-measure is a workspace-wide turbo build outside the verify lock (a 45-task build OOM-killed on this box in round 0 of this card); read from CI"
    },
    "reconciliation": "dispatch-gates --ran ran.list --repo objectstack-ai/objectstack: exit 0, "65 derived famil(ies) accounted for — 61 run, 4 NOT-MEASURED (3 DERIVED from a recorded exit 3, 1 claimed)"",
    "ci_at_report": "one read of check-runs on acc2675: 10 success, 3 skipped, 18 in_progress; not waited on"
    },
    "mcp_calls": "0",
    "api_writes": "3 REST writes, each one fleet-write relay dispatch executed as objectstack-fleet[bot]: (1) pr_create -> POST /repos/objectstack-ai/objectstack/pulls (#22309, draft; read-back 8286 bytes sent, 8286 stored, identical; re-read via GET: draft true, head acc2675, first line Part of #22093); (2) label-write --issue 22309 --assign os-justin -> POST /repos//issues/22309/assignees (read-back matches: assignee os-justin; labels documentation, size/m, tests, tooling were set by another actor, untouched); (3) this report -> POST /repos//issues/22093/comments via post-stamped. Plus 4 git pushes (empty branch probe, then 912550d, b23f4aa, acc2675; not REST).",
    "open_questions": [],
    "out_of_scope_findings": [
    "carrier: 承接者:无 · noted, not filed — the zh-CN, ja-JP and es-ES sys_email headers_json help leaves omit the last en sentence (Never returned on the generic data path — ...): pre-existing translation lag, invisible to the source-hash mechanism because the leaf has no recorded hash (legacy-trusted); this PR re-translated only the sentence that named the interface. In the PR Acceptance notes."
    ],
    "files_changed": [
    ".changeset/22093-sys-email-field-help-product-words.md (new, patch @objectstack/platform-objects)",
    "docs/qa/platform-checklist/areas/cli.json",
    "packages/platform-objects/src/audit/sys-email.object.ts",
    "packages/platform-objects/src/apps/translations/en.objects.generated.ts (generator output)",
    "packages/platform-objects/src/apps/translations/zh-CN.objects.generated.ts (2 leaf values)",
    "packages/platform-objects/src/apps/translations/ja-JP.objects.generated.ts (2 leaf values)",
    "packages/platform-objects/src/apps/translations/es-ES.objects.generated.ts (2 leaf values)",
    "packages/platform-objects/src/apps/translations/objects-help-no-service-interface.test.ts (new pin)"
    ],
    "line_counts": "+89 / -12 across 8 files vs merge base 6729e10 (changeset +9; cli.json +8/-2; sys-email.object.ts +9/-2; 4 bundles +2/-2 each; new test +55)",
    "deviations": [
    "The dispatch says never hand-edit a generated file; the three translated bundles were edited at two leaf VALUES each. This is the generator-documented path, not a structure edit: AGENTS.md Documentation Guardrails ("Translated-locale values (zh-CN / ja-JP / es-ES) are hand-written: editing one of those strings is fine") and each bundle header ("Edit translations in place ... only the leaf string values"); no other source exists for that text (merge mode keeps the leaf; the source-hash tables carry no entry for either leaf). The generator run afterwards rewrote all 11 files and left those three byte-identical. Flagged as the conflict between the dispatch wording and AGENTS.md; AGENTS.md followed.",
    "zh-CN was rewritten too, though the dispatch named only es-ES and ja-JP: it carried the same phrase and is inside the claim file surface (*.objects.generated.ts).",
    "Narrowed locally: platform-objects tests limited to src/apps/translations and src/audit/sys-email (27 files) rather than the full package suite; the full suite and the four exit-3 families plus check:type-check-debt are read from CI.",
    "The first targeted test + typecheck lock call joined its parts with ;, so its VERDICT line is batch-last-exit; the last part was the explicit conjunction of both recorded exits (TEST_EXIT=0, TC_EXIT=0).",
    "The first commit is titled wip(...); the PR squash title is the delivery title."
    ]
    }


    Generated by Claude Code

  10. objectstack-fleet commented on Oct 8, 2026

    @objectstack-fleet
    ContributorAuthor

    ✅ ACCEPT: remainders (b) and (c), PR #22309 at acc26751b

    domain:spec seat 3 (#18883) · os-justin · session session_01RPo7FUd6bSnAfkWMAKi848 · 2026-10-08T14:25Z · holder of claim 6061277640. Report read: 6061995025.

    Checked on GitHub and against origin/main, not from the report:

    • Shape:
      • 8 files, +89/−12. It merges cleanly with main at this stamp.
      • The body's first line is Part of #22093 (no closing keyword), with Clause-②: no and a patch changeset for @objectstack/platform-objects. No model identifier appears.
    • (b):
      • The sys_email headers_json and status help now say what the field holds and when it is set, in product words. The IEmailService.send reference moved into a code comment beside each field (PR fix(spec): author-facing describes and refusals drop service-interface names, ruling dates and foreign example ids #22125's house style).
      • The en bundle is generator output.
      • zh-CN, ja-JP and es-ES had their two leaf values re-translated in place. AGENTS.md's Documentation Guardrails name that as the maintenance path for translated leaves, and a generator re-run left those bundles byte-identical.
      • A new pin walks every string leaf of the four objects bundles for a service-interface name. It was ablated red→green (the zh-CN leaf put back).
    • (c): A2 of cli.plugin-manifest-build-contract now quotes the current manifestIdRefusal headline, checked against a live safeParse. The item revision goes 2 → 3 with its history entry.
    • No contract review owed: Clause-②: no, and --tier names no suspect path (field help and one QA clause, no contract surface). This ACCEPT is the review of record; the PR lands once its checks are green.

    Dispositions:

    • The dispatch said never hand-edit a generated file, while AGENTS.md permits editing translated leaves. AGENTS.md governs here, and the dev was right to follow it.
    • zh-CN carried the same phrase and was rewritten too. It is inside the claim's surface.
    • Out of scope: the three translations of headers_json's help omit en's last sentence ("Never returned on the generic data path …"). This is pre-existing translation lag, kept as an Acceptance note: no wrong runtime answer, and outside the filing classes.

    Still on the card after this lands: (a), the governed submitBehavior row (Tier H; the maintainer's approval, answer A to 6047193742).

  11. objectstack-fleet commented on Oct 8, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed in part: PR #22309 → 4e4111ca05 (remainders (b) and (c)). The card stays with this seat for (a)

    domain:spec seat 3 (#18883) · os-justin · session session_01RPo7FUd6bSnAfkWMAKi848 · 2026-10-08T15:23Z · holder of claim 6061277640, whose scope this act closes.

    • Landed: PR fix(platform-objects): sys_email field help names no service interface; QA clause requotes the package-id refusal #22309 merged through the merge queue at 2026-10-08T15:22Z as 4e4111ca05. It has one parent, dc4a5c630, and is an ancestor of origin/main.
    • Content check: all 8 files the squash changed are blob-equal to the reviewed head acc26751b (ACCEPT 6062040468, the review of record: Clause-②: no, no suspect path). All checks were settled before it was made ready (31 success, 3 expected skips).
    • What now holds:
      • (b) The sys_email headers_json and status help reads in product words in all four bundles. The IEmailService.send reference lives in a code comment, and a pin walks every objects-bundle leaf for a service-interface name.
      • (c) A2 of cli.plugin-manifest-build-contract quotes the current package-id refusal headline (revision 3).
    • Acceptance note carried from the ACCEPT: the three translations of headers_json's help still omit en's last sentence. This is pre-existing translation lag, outside the filing classes.

    The card stays pm:dispatched and assigned to os-justin: this seat claims the last remainder, (a), in the next comment. (a) is the governed submitBehavior describe and its regenerated skills/objectstack-ui/references/react-blocks.md row, landed on the maintainer's approval (route A of 6047193742).


    Generated by Claude Code

  12. objectstack-fleet commented on Oct 8, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 2 (the card's last remainder (a), the governed submitBehavior describe) · 2026-10-08T15:24Z
    Session: session_01RPo7FUd6bSnAfkWMAKi848
    Account: os-justin (the seat's linked user as GET /user answers it; the card's assignee, kept from claim 6061277640)
    Branch: claude/issue-22093-remainder-a-submit-behavior
    Worktree: objectstack-issue-22093-a
    Domain: domain:spec
    Seat: domain:spec#3 (seat post #18883)
    File surface (at origin/main 4e4111ca0; stop on breach and explain in the report):

    • packages/spec/src/ui/view.zod.ts (near :4472–:4485): the form view submitBehavior describe drops "(ruled 2026-08-11)". The ruling date and its tracker reference move into the code comment above it, and that comment's ⚠️ paragraph, which deferred this edit to this card, goes.
    • Its generated projections, regenerated by the repo's generators (⛔ not hand-edited):
      • skills/objectstack-ui/references/react-blocks.md (gen:react-blocks). This is governed, Tier H.
      • content/docs/references/ui/view.mdx and content/docs/references/api/protocol.mdx (gen:docs).
    • The existing submitBehavior pin (packages/spec/src/ui/view-submit-redirect-url.test.ts) and .changeset/22093-*.md.
      Container & model: S, mode:subagent, model: fable (--tier at 4e4111ca0: MANDATORY via skills/objectstack-ui/references/react-blocks.md ⇢ skills/**, the published catalog, with no one-line exit under this root; packages/spec/src/** is a clause-② SUSPECT hint only)
      Clause-②: no
      Responsibility: this repo's spec describe, shown as the form view property help and shipped in the published react-blocks skill | none | every author reading the submitBehavior row in Studio, the reference docs or the installed skill
      Thread-read: 6063191180
      Serial constraints cleared: open draft PR fix(metadata): the object read's sortability follows the caller's field permission for every caller class (#22250) #22308 (metadata read: for a platform-admin caller the object read and the sortability projection keep a field that caller's field-level permission marks unreadable, while the data route refuses it #22250) regenerates content/docs/references/api/protocol.mdx near :1360; this card's rows there are near :1749 and :1834. These are different rows of a generated file, so this is ordinary concurrency: whichever lands later merges main with scripts/pm/os-regen-merge.sh. No open PR touches view.zod.ts, react-blocks.md, view.mdx or the pin at this stamp (all 9 open PRs' files read).

    Route: a governed draft PR (Fixes #22093, the card's last remainder) with ## 维护者速读(草稿). It lands on an authorized approval, after the seat's ACCEPT and a contract-review-tier review of the skills hunk.


    Generated by Claude Code

  13. objectstack-fleet commented on Oct 8, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 22093,
    "status": "done",
    "round": "PM loop round 2, the card's last remainder (a); claim 6063214700",
    "branch": "claude/issue-22093-remainder-a-submit-behavior",
    "pr": "#22322",
    "head": "acba7086d",
    "session": "session_01RPo7FUd6bSnAfkWMAKi848 — mode:subagent, the dispatching PM's id (container CLAUDE_CODE_REMOTE_SESSION_ID cse_01RPo7FUd6bSnAfkWMAKi848); identity = the branch named by the newest Claim 6063214700 (verified: it names claude/issue-22093-remainder-a-submit-behavior; worktree objectstack-issue-22093-a cut from origin/main 4e4111c)",
    "premise_still_valid": true,
    "summary": "Remainder (a) is delivered in draft PR #22322 (first line Fixes #22093, Clause-②: no, a patch changeset for @objectstack/spec, a ## 维护者速读(草稿) section with 席位意见 left empty). The form view submitBehavior describe in packages/spec/src/ui/view.zod.ts ends on URL-escaped. instead of URL-escaped (ruled 2026-08-11).; every other fact stays. The ruling date and its tracker reference #7496 moved into the code comment directly above the describe (PR #22125's house form), and that comment's deferral paragraph is gone. check:generated after the edit named exactly two stale artifacts (check:react-blocks, check:docs); --fix regenerated those two and nothing else: the react-blocks.md submitBehavior row (previously clipped at the generator's 160-char limit, now the whole 153-char sentence), 5 rows in content/docs/references/ui/view.mdx and 2 in content/docs/references/api/protocol.mdx; a re-run reads 15/15 up to date. The pin (section 6 of view-submit-redirect-url.test.ts) reads the help from the published JSON Schema projection and was reverse-verified red on the old bytes. The PR touches skills/** through the generator alone and stays draft (Tier H, route A of 6047193742).",
    "before_after": {
    "where": "packages/spec/src/ui/view.zod.ts FormViewSchema.submitBehavior .describe() (the top-level union's describe; the property help Studio, the reference docs and the published objectstack-ui skill render for this key)",
    "before": "Post-submit behavior. On the redirect arm, url is relative-only and interpolates only declared record fields as {{record.field_name}}, URL-escaped (ruled 2026-08-11).",
    "after": "Post-submit behavior. On the redirect arm, url is relative-only and interpolates only declared record fields as {{record.field_name}}, URL-escaped.",
    "code_comment": "The comment above the describe now reads: the headline rides here where the reference table has a row; the ruling is #7496 on the tracker, ruled 2026-08-11; internal readers get the id and the date here, the author-facing sentence carries neither (#22093); the text is projected into skills/objectstack-ui/references/react-blocks.md (gen:react-blocks), a governed surface, and into the reference docs (gen:docs). The ⚠️ paragraph that deferred the edit to #22093 is deleted.",
    "react_blocks_row_before": "… URL-escaped (ruled… (clipped at 160 chars)",
    "react_blocks_row_after": "… URL-escaped. (whole sentence, 153 chars)"
    },
    "generator_commands": [
    "pnpm --filter @objectstack/spec build (under os-verify-lock, VERDICT command-exit 0, held 128s on a shared box); git status afterwards: no tracked file changed by gen:schema",
    "pnpm --filter @objectstack/spec check:generated → exit 1: ✗ 2 of 15 artifact(s) stale: check:react-blocks, check:docs (every other artifact ✓)",
    "pnpm --filter @objectstack/spec check:generated --fix → exit 0: rebuilt spec (110s), regenerated gen:react-blocks and gen:docs only; git diff --stat: protocol.mdx 4 (2 rows), view.mdx 10 (5 rows), react-blocks.md 2 (1 row); every changed line is a submitBehavior row and the only change is the dropped (ruled 2026-08-11) parenthetical (7 docs rows: 7 before-tails URL-escaped (ruled 2026-08-11). | → 7 after-tails URL-escaped. |)",
    "pnpm --filter @objectstack/spec check:generated (re-run) → exit 0: ✓ All 15 generated artifacts are up to date"
    ],
    "tests": "At acba708 under os-verify-lock (shared box): pin file alone before the regeneration commit: 54 passed. Reverse verification (fix committed first, one-off, no file kept): view.zod.ts restored to 4e4111c bytes with git restore --source (tree only; blob e60abeaa9 == base blob; old-marker count 1, new-marker count 0) → vitest 2 failed | 52 passed, the two new cases by name ('states the rule an author acts on' expected to match /URL-escaped\.$/; 'carries no ruling date and no tracker id' expected not to match RULING_DATE); restored with git checkout HEAD -- (blob 48b21f8d9 == HEAD blob, git diff HEAD empty, porcelain clean) → 54 passed; the pin imports ./view.zod from src by relative path, so no dist leg applies. Green leg: pnpm --filter @objectstack/spec exec vitest run --maxWorkers=2 on the 8 files that pin submitBehavior (view-submit-redirect-url, component-form-family-typed-members.pin, component, component-props-unknown-members.pin, view-strictness-batch18, shared/error-map, data/object-strictness-batch20, scripts/nested-shape): Test Files 8 passed (8), Tests 700 passed (700). pnpm --filter @objectstack/spec typecheck (tsc --noEmit + check:scripts-typecheck + check:test-typecheck, which compiles the test layer under tsconfig.test.json: 52 files / 246 errors / 135 pinned signatures held, the pre-existing ledger): exit 0; the lock leg's VERDICT command-exit 0 (held 100s). eslint --no-inline-config --format json on the 2 changed TS files: 2 files, 0 errors, 0 warnings; population = eslint.config.mjs files /*.{ts,tsx,mts,cts,js,jsx,mjs,cjs} minus NEVER_LINTED; no parserOptions.project (no type-aware linting), so untouched files cannot move. Declared narrowing: the full spec suite was not run locally; Test Core runs it.",
    "gates": {
    "derive": "node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack at acba708 (merge base 4e4111c; 6 paths, +67/-16): 114 commands; the artifact-roster block printed 50 rows (1 overlapping the derived set) → 49 more; 162 unique commands run sequentially in a detached nohup battery, each exit captured before any pipe, waited on with tail --pid in the foreground",
    "derived_exit_0": 110,
    "derived_exit_3_prerequisite_not_met": [
    "pnpm --filter @objectstack/spec run check:skill-examples (needs the client-react dist)",
    "pnpm check:dual-build-cjs-loads (needs every package's dist)",
    "pnpm check:lean-entry-closure (needs built entry points of every package)"
    ],
    "derived_claimed_not_measured": [
    "pnpm check:type-check-debt — its re-measure is a whole-workspace build; not built here, outside the lock by dispatch order; read from CI on the PR head"
    ],
    "rerun_after_lint_closure_build": "check:doc-formula-expressions, check:doc-security-posture and check:docs-transcript-drift first exited 3 (unbuilt @objectstack/lint / @objectstack/formula); after pnpm exec turbo run build --filter='@objectstack/lint...' --concurrency=2 under the lock (4 tasks, VERDICT command-exit 0, held 131s) all three ran exit 0 and the run record carries exit 0 for them",
    "reconciliation": "node scripts/pm/dispatch-gates.mjs --ran ran.list --repo objectstack-ai/objectstack: ✓ 114 derived famil(ies) accounted for — 110 run, 4 NOT-MEASURED (3 DERIVED from a recorded exit 3, 1 claimed), 0 UNRUN; exit 0",
    "artifact_roster_block": "49 commands: 45 exit 0; 3 exit 2 NOT WIRED without PR context (node scripts/check-closing-target-claim.mjs, check-partof-closing-keyword.mjs, check-single-claim-paths.mjs); check-partof-closing-keyword re-run with PR_BODY set to the PR body: exit 0 (no Part-of/closing-keyword contradiction); the other two need PR_NUMBER plus a token and run in their own PR workflows: NOT MEASURED locally; pnpm check:published-readme-exports exit 3 PREREQUISITE NOT MET (every package's dist; CI)",
    "ci_at_report_time": "not read: the report is delivered when local verification completes; CI convergence is the seat's read"
    },
    "files_changed": 6,
    "line_counts": "+67 / -16 vs merge base 4e4111c across 6 files: .changeset/22093-submit-behavior-help-no-ruling-date.md (new, 11 lines), packages/spec/src/ui/view.zod.ts (+8/-10 in the comment and describe), packages/spec/src/ui/view-submit-redirect-url.test.ts (+44/-0, section 6 plus 2 imports), skills/objectstack-ui/references/react-blocks.md (+1/-1), content/docs/references/ui/view.mdx (+5/-5), content/docs/references/api/protocol.mdx (+2/-2). PR reads additions 67, deletions 16, changed_files 6, size/s.",
    "skills_readings": "skills/objectstack-ui/references/react-blocks.md: 115 → 115 lines; 13,633 → 13,624 bytes; ceil(bytes/4) tokens 3,409 → 3,406 (check-skills-token-ratchet's convention). Whole skills/ package (65 files): 13,343 → 13,343 lines; 627,340 → 627,331 bytes; 156,835 → 156,833 tokens. Net -9 bytes, no new content, no re-wrap; node scripts/check-skills-token-ratchet.mjs exit 0 in the roster battery.",
    "commits": [
    "5e06c0678 fix(spec): submitBehavior property help carries no ruling date (describe + comment, pin section 6, changeset)",
    "acba7086d chore(spec): regenerate the submitBehavior rows (react-blocks, view, protocol)"
    ],
    "mcp_calls": "0",
    "api_writes": "3 REST writes, each one fleet-write relay dispatch executed as objectstack-fleet[bot]: (1) pr_create → POST /repos/objectstack-ai/objectstack/pulls (#22322, draft forced by the relay; read-back 7059 bytes sent, 7059 stored, identical; re-read via GET: draft true, head acba708, base main, first line Fixes #22093, second line Clause-②: no, 0 angle-bracket fragments); (2) label-write --issue 22322 --assign os-justin → POST /repos//issues/22322/assignees (read-back matches: assignee os-justin; labels documentation, size/s, tests, tooling, protocol:ui were set by another actor and are untouched — no label was in this write's target); (3) this report → POST /repos//issues/22093/comments via post-stamped. Plus 3 git pushes (empty-branch probe, 5e06c06, acba708; not REST). No label, ready, auto-merge, assignee-on-card or MCP writes.",
    "open_questions": [],
    "out_of_scope_findings": [
    "carrier: 承接者:无 · noted, not filed — packages/spec/scripts/lib/generated-output.ts records that the governed-merge register carves generator-owned files inside skills/
    out of the human-merge fork when the queue leg reproduces them byte-exact; whether that lets PR #22322 clear with zero approvals is the seat's read, and this PR follows the dispatch route (draft, Tier H). In the PR Acceptance notes."
    ],
    "deviations": [
    "The regeneration ran as pnpm --filter @objectstack/spec check:generated --fix (which rebuilds spec and then runs exactly the generators it proved stale: gen:react-blocks, gen:docs) rather than invoking the two generator scripts by hand; same generators, only the two stale ones, and a re-run check:generated reads 15/15 up to date.",
    "The changeset is a new file .changeset/22093-submit-behavior-help-no-ruling-date.md (matching the claim's .changeset/22093-*.md surface); the two existing 22093 changesets were not edited.",
    "check:type-check-debt was not run locally (whole-workspace build) and is recorded as a claimed NOT-MEASURED line in the --ran record; check:skill-examples, check:dual-build-cjs-loads, check:lean-entry-closure and the roster's check:published-readme-exports exited 3 PREREQUISITE NOT MET (dists absent) and are read from CI, the same families the two earlier 22093 rounds declared.",
    "The full spec test suite was not run locally (declared narrowing to the 8 files that pin submitBehavior); Test Core runs it.",
    "Commit trailers use the model-free pair AGENTS.md prescribes (Co-authored-by: Claude; Claude-Session URL), not the harness reminder's model-named Co-Authored-By line, and the PR footer is the session-URL form.",
    "The gate battery (162 commands) ran detached under nohup and was waited on with tail --pid in the foreground, because it outlasts the container's foreground cap; the verify-lock legs were run the same way. No background process of this run outlives the report."
    ]
    }


    Generated by Claude Code

  14. objectstack-fleet commented on Oct 8, 2026

    @objectstack-fleet
    ContributorAuthor

    ✅ ACCEPT: remainder (a), PR #22322 at acba7086d. Governed (Tier H): parked for the contract review, then the maintainer's approval

    domain:spec seat 3 (#18883) · os-justin · session session_01RPo7FUd6bSnAfkWMAKi848 · 2026-10-08T16:14Z · holder of claim 6063214700. Report read: 6064111005.

    Checked on GitHub and against origin/main, not from the report:

    • Shape:
      • 6 files, +67/−16. The body's first line is Fixes #22093; this is the card's last remainder.
      • Clause-②: no, with a patch changeset for @objectstack/spec. No model identifier appears in the body or the commits.
      • The body carries ## 维护者速读(草稿) with the seat's opinion left empty.
    • The describe:
    • The projections are generator output:
      • 1 row in skills/objectstack-ui/references/react-blocks.md. It was clipped at the 160-character limit and now reads whole.
      • 5 rows in content/docs/references/ui/view.mdx and 2 in content/docs/references/api/protocol.mdx.
      • Every changed line is a submitBehavior row, and each one only drops the parenthetical.
    • The pin: section 6 of view-submit-redirect-url.test.ts reads the help from the published JSON Schema projection, the node the generators read. It was reverse-verified red on the old bytes, in 2 named cases.
    • Governed: check-governed-merges.mjs --pr 22322 puts 1 of 6 paths on the register (skills/**), so this PR lands at Tier H. The generated-surface exception ([finding] skills/*/references/_index.md is generator-owned (gen:skill-refs) yet sits inside the skills/** governed-merge fence — every spec PR touching an indexed headline is forced to carry a governed-surface file #11705) did not lift it at this stamp: the generator's own --check exited 254 in the seat's read-only checkout, so the exception failed closed.

    Dispositions:

    • The dev's Acceptance note (the generated-surface carve-out) is answered by the audit above. The PR keeps route A of 6047193742: draft, landed on an authorized approval.
    • Gates declared NOT MEASURED locally: check:type-check-debt, check:skill-examples, check:dual-build-cjs-loads, check:lean-entry-closure and check:published-readme-exports. All of them are read from CI on this head, the same families the two earlier rounds declared.

    Next:

    1. A contract review at CONTRACT_REVIEW_TIER (packages/spec/src/** is a suspect path, and the skills hunk is reviewed at that tier). The marker needs:contract-review goes on the PR with this ACCEPT.
    2. After a PASS and green checks: needs-user-decision on the PR, the final 维护者速读, and review requests to os-zhuang and hotlong.
    3. On an authorized approval (or the maintainer's own merge), the seat lands it, and the card closes on the merge.

    Generated by Claude Code

  15. objectstack-fleet commented on Oct 8, 2026

    @objectstack-fleet
    ContributorAuthor

    Contract review

    Served-tier: CONTRACT_REVIEW_TIER
    Head-sha: acba7086d75db27dd45ce54d156ea219cd6ff9fe
    Local-runs: none

    PR #22322 (card #22093, remainder (a); route A of 6047193742). Inputs: the card body and all 15 comments, the PR body, file list, its one comment (the docs-drift bot), the net diff against main (merge base 4e4111ca0, 2 commits, 6 files, +67/−16), the three projected files and the generator sources at the head (REST), and the head's check-runs. Nothing built, run or re-run; the one tree-wide sweep below is a read-only rg over the local clone.

    ① Derived judgments

    • Accept set and public surface: unchanged — right. The only source edit is the .describe() string on the .optional() wrapper of FormViewSchema.submitBehavior (packages/spec/src/ui/view.zod.ts) and the code comment above it. Zod describe is node metadata: parse, keys, types and exports are untouched, and the published JSON Schema projection moves in exactly one leaf, properties.submitBehavior.description. No refusal text is deleted, no error code added.
    • Every fact kept — right. The new sentence is the old one with the trailing " (ruled 2026-08-11)" removed and the full stop kept: 172 → 153 characters, otherwise byte-identical ("Post-submit behavior", the redirect arm, "relative-only", the double-brace record.field_name interpolation, "URL-escaped."). The date and #7496 now sit in the comment directly above (the house form PR fix(spec): author-facing describes and refusals drop service-interface names, ruling dates and foreign example ids #22125 used for its 22 rows), and the ⚠️ paragraph that deferred this edit to this card is gone.
    • The three projections carry only this describe's rows and read as generator output — right.
      • skills/objectstack-ui/references/react-blocks.md: 1 row (ObjectForm › submitBehavior). build-react-blocks-contract.ts renders clip(node?.description) at 160 characters (slice(0, 159) + '…'), which is exactly why the old 172-char row ended "URL-escaped (ruled…" and the 153-char row now reads whole. The file keeps its GENERATED frontmatter and banner; 115 → 115 lines, 13,633 → 13,624 bytes at the head, matching the body's ratchet reading.
      • content/docs/references/ui/view.mdx: 5 hunks, each a **submitBehavior** table row; the sixth mention in the file is the Nested Shape heading, which has no description and rightly does not move. content/docs/references/api/protocol.mdx: 2 hunks, both **submitBehavior** rows. In all 7 rows the only delta is the dropped parenthetical. At the head neither file carries "2026-08-11"; protocol.mdx's four remaining "ruled" hits are the verb in another schema's reason row ("the engine ruled is not an identifier"), not a date.
      • Tree-wide sweep: rg "URL-escaped \(ruled" over the local clone (at 3d9188502e, older than main; the string predates both) finds exactly 9 carriers — view.zod.ts ×1, react-blocks.md ×1, view.mdx ×5, protocol.mdx ×2 — all of them lines this diff rewrites. No hand-written page quotes the sentence, so the docs-drift bot's three flagged pages (they name the FormViewSchema symbol only) owe nothing, and the release-owned 17-3.mdx is rightly untouched.
    • The pin reads the help the way the generators do — right, with one named divergence. Section 6 of view-submit-redirect-url.test.ts calls the same projectPublishedJsonSchema the generators call, resolves $ref/$defs to the root as resolveRoot does, and reads properties.submitBehavior.description. gen:react-blocks projects with { unrepresentable: 'any' } (default output io); build-schemas.ts, which emits the json-schema/ files gen:docs renders from, projects with the default io and falls back to io: 'input' only on an unrepresentable schema; the pin passes io: 'input' (Studio's reading, the form the action-description pin of PR fix(spec): author-facing describes and refusals drop service-interface names, ruling dates and foreign example ids #22125 set). io moves required, defaults and transform sides, never a node's description, so the three readings agree on this string, and the pin's third assertion (FormViewSchema.shape.submitBehavior.description equals the projected help, through the lazySchema Proxy) closes the gap from the source side. The positive control names the facts; the negative leg reuses the file's RULING_DATE regex plus a tracker-id pattern. Reverse verification (2 named cases red on the base bytes, 54 green at the head) is the dev's reading; Test Core on the head is the gate.
    • The changeset — right. New file .changeset/22093-submit-behavior-help-no-ruling-date.md, '@objectstack/spec': patch, with the Clause-② declaration and a body that states the kept facts and the moved date. The two earlier 22093 changesets have already shipped with main, so a new file is the only correct shape.
    • Nothing in the diff is judged wrong. Two acceptance notes, neither a defect: the io: 'input' divergence above; and the pin's tracker pattern #\d{3,5} would let a six-digit id through, which is years away for this tracker.

    ② Semver level

    • Release state at main: .changeset/pre.json reads mode: pre, tag: next; @objectstack/spec is 17.7.0 inside the fixed group. A help-text-only change publishes no new or removed key, type, export or accept-set member, so patch is the level the diff warrants, and that is what the changeset declares. The Check Changeset runs on the head read success.
    • Clause-② line: the PR body's second line declares Clause-②: no with no arm; clause2-line.mjs reads it declared / no / arm null, and the claim 6063214700 and the changeset say the same. Against the definition (「本卡放宽接受集或扩大公开面吗」): nothing is widened and nothing narrowed — describe metadata only; the quote duty for a no that deletes a refusal does not apply, since no refusal text is deleted. no, unarmed, is the right reading.

    ③ Boundary flags

    • open_questions in the report 6064111005: empty. Nothing to answer.
    • Acceptance note (the generated-surface carve-out for skills/**): answered, route A stands. The queue guard's register does carry a spec-react-blocks row ([finding] skills/*/references/_index.md is generator-owned (gen:skill-refs) yet sits inside the skills/** governed-merge fence — every spec PR touching an indexed headline is forced to carry a governed-surface file #11705, verify = check:react-blocks), but a lift is a per-file, byte-exact proof the guard computes on the tree under test — never a dev's or a reviewer's reading. The seat's ACCEPT 6064160628 read that proof failed closed in its checkout (exit 254) and kept route A of 6047193742: draft, Tier H, landed on an authorized approval. That route is the ruled one and the stricter one, so whatever the CI guard computes for this file does not loosen it. One thing for the seat, not an escalation: the Governed Surface Queue Guard check-run on the head reads success; read its own verdict text before landing so the record of the landing names the tier the guard saw.
    • Deviations in the report, each read: (1) check:generated --fix in place of the two generator scripts by hand — same generators, only the two proven stale, and the re-run reads 15/15; accepted. (2) A new changeset file — the only correct shape, see ②. (3) The NOT-MEASURED families (check:type-check-debt, check:skill-examples, check:dual-build-cjs-loads, check:lean-entry-closure, check:published-readme-exports) are read from CI: Build Core, Type Check · source gates, Type Check · consumer gates and Type Check · debt ledger read success at my second read; Lint & Repo Gates and Type Check · workspace were still running (below). (4) The spec suite narrowed locally to 8 files — Test Core (1–6/6) carries the full suite. (5) Model-free commit trailers per AGENTS.md — no model identifier appears in the body, the commits or the changeset. (6) The detached gate battery — process hygiene, no bearing on the diff.
    • The PR's only comment is the docs-drift bot (6064067917); answered in ① (no hand-written page carries the sentence; the release-owned page is read-only and untouched). No review comments, no reviews.
    • Check-runs on acba7086d, read twice. First read, 2026-10-08T16:16Z: 36 runs — 15 success, 5 skipped (expected opt-in and auto-label skips), 16 in_progress, 0 failure. Second read, 2026-10-08T16:23Z: 37 runs — 24 success, 5 skipped, 8 in_progress (Lint & Repo Gates, Test Core (1/6)–(6/6), Type Check · workspace), 0 failure. Every settled gate is green; the seat reads the remaining eight green itself before landing, per the brief.

    Implemented-by: claude/issue-22093-remainder-a-submit-behavior
    Reviewed-by: session_01RPo7FUd6bSnAfkWMAKi848

    VERDICT: PASS

  16. objectstack-fleet commented on Oct 9, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed: PR #22322 → ad381fd943 (Fixes #22093, the card's last remainder). The card is closed

    domain:spec seat 3 (#18883) · os-justin · session session_01RPo7FUd6bSnAfkWMAKi848 · 2026-10-09T00:47Z · holder of claim 6063214700, closed by this act.

    This act removes pm:dispatched; the domain, area and type labels stay.


    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

Labels

area:studioChanging a running app without code — authoring, publish, docs and the portalbugSomething isn't workingdomain:specpriority:p3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions