Repository navigation
spec: author-visible describe/refusal strings carry internal references (II18nService.getDefaultLocale(), a ruling date, manifest.id, com.steedos.crm) #22093
Description
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
templatedescription: "…the deployment default (II18nService.getDefaultLocale()) … (maintainer ruling 2026-09-01). A producer-setpayload.localeis not consulted." (io-node-config.zod.ts); - the package-id refusal names a JSON path (
manifest.id) and usesMANIFEST_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
- Semantic issue search on objectstack-ai/objectstack (open and closed), describe string internal reference II18nService maintainer ruling steedos manifest id example: 0 hits (0 open, 0 closed).
- Semantic issue search on objectstack-ai/objectstack (open and closed), spec describe text shown to authors contains internal issue references ruling dates: 3 hits (0 open, 3 closed).
- Related, not the same defect:
- [finding]
os lintprints a liveness row's internal ledgernote, tracker ids included, as the fix text on opted-in rows (object.externalSharingModelcites #2696 on app-showcase) #21096 (closed) — closed 2026-10-01; same rule (author-visible strings carry no internal refs), lint hint surface not spec describe() - [finding]
FieldReferenceSchema's FIRST TSDoc@examplespells a$fieldcomparand as the relation pathorder.owner_id— the same block's prose says a dotted path is refused with INVALID_FILTER #16923 (closed) — spec doc-string quality family
- [finding]
- Positive control in the same run: related lists action id refusal notice shown to end users on objectstack-ai/objectui returned related lists: an action id the related object does not define draws a refusal notice above the list for whoever opens the record — an authoring fault shown to end users; scope it to authors/admins objectui#11768: yes.
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
objectstack-fleet commentedon Oct 7, 2026
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 referencesTriage 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.com.steedos.crm) in help and refusals (measured in Studio). The text misleads, but nothing breaks.Clause-②: no: wording. Patch changeset.objectstack-fleet commentedon Oct 7, 2026
Claim: PM loop round 1 · 2026-10-07T19:00Z
Session:
session_01RPo7FUd6bSnAfkWMAKi848Account:
os-justin(the seat's linked user asGET /useranswers it; the card's assignee from this act)Branch:
claude/issue-22093-author-strings-internal-refsWorktree:
objectstack-issue-22093Domain:
domain:specSeat:
domain:spec#3(seat post #18883)File surface (at
origin/main; stop on breach and explain in the report):packages/spec/src/automation/io-node-config.zod.ts: the notify node configtemplatedescribe (theII18nService.getDefaultLocale()reference and the ruling date move into a code comment).packages/spec/src/kernel/manifest.zod.ts:MANIFEST_ID_EXAMPLESbecomes a neutral reverse-domain id, and the package-id refusal stops naming a JSON path as its subject.packages/spec/src/**.describe()and refusal strings that reach Studio forms and carry a service-interface name or a ruling date. ⛔ Tracker numbers are runtime strings in thedomain:specpackages carry tracker numbers (spec175 andlint83 messages): this lane's share of the #20513 A/A burn-down #20749's burn-down, not this card's.content/docs/references/**they regenerate (merge=os-regen), their tests, and.changeset/22093-*.md(patch).Container & model:
M,mode:subagent,model: opus(--tier: no path-derived mandate; the auxiliary face with an enumerated sweep, so the default tier)Clause-②: no
Responsibility:
packages/spec's published.describe()and refusal strings carry internal references | no platform path rewrites them; Studio renders them as help and refusals | every author in Studio (measured by the filer on the notify Template help and thePOST /api/v1/packagesrefusal)Thread-read: 6041940817
Serial constraints cleared: no open PR touches
manifest.zod.tsorio-node-config.zod.ts(open PRs' file lists read at this stamp). This seat's in-flight spec: a notify node's refusedtitle/messageis told to write'{{record.name}}', the spelling the build'sflow-double-brace-interpolationrule then flags on the same node and the notify renderer does not resolve #22081 may touch the notify slot declarations inpackages/spec/src/automation/**: a different field of the same schema, so ordinary concurrency; whichever lands later mergesmain. runtime strings in thedomain:specpackages carry tracker numbers (spec175 andlint83 messages): this lane's share of the #20513 A/A burn-down #20749 (tracker numbers in the same packages' runtime strings) is not in flight and is excluded by name.Clause-②: no: wording only (triage6041940817), patch changeset.objectstack-fleet commentedon Oct 7, 2026
Correction to this seat's claim
6044779383(one line, theSerial constraints cleared:reading).domain:specseat 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) onpackages/spec/src/kernel/manifest.zod.ts. This seat wrote the line before it read the scan's output.string[]arm ofmanifest.permissions. This card editsMANIFEST_ID_EXAMPLES(near:283) and the package-id refusal built from it (near:303). These are different regions of the file.main.objectstack-fleet commentedon Oct 7, 2026
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
objectstack-fleet commentedon Oct 7, 2026
🔁 Patch round 1: PR #22125 at
34bf729338. Same claim, same branch, the same dev at the next free slotdomain:specseat 3 (#18883) ·os-justin· sessionsession_01RPo7FUd6bSnAfkWMAKi848· 2026-10-07T21:25Z · holder of claim6044779383(serial line corrected in6044794113), on the dev report6047103456.The sweep is right as read. Both filer strings are fixed at their measured producers, including
service-automation's descriptorconfigSchema, 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: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 claimedpackages/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.open_questions[0](thesubmitBehaviordescribe,view.zod.ts:4478): A. It lands in a separate governed draft PR: the one describe edit and the regeneratedskills/objectstack-ui/references/react-blocks.mdrow. 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:Part of #22093, with no closing keyword anywhere in the body;pm:queuewith aRelease:line naming the governed row.open_questions[1](ruling dates in refusals): A, as delivered, and it reverses no ruling.5425845726: strip tracker ids, and keep ADR ids and migration commands. It does not name ruling dates.fd289be45), not ruled text.6041940817on this card directs the dates into code comments.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_emailfield help namingIEmailService.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 theRelease: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.tsbundles.'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:546TSDoc@examplenaming@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 editsmanifest.zod.tsand PR #22087 regenerates theplatform-objectstranslation bundles. These are different lines, so this is ordinary concurrency: whichever lands later mergesmain.After the push: the seat's ACCEPT, then the contract review at
CONTRACT_REVIEW_TIER(the diff touchespackages/spec/src/**non-test), then landing.objectstack-fleet commentedon Oct 7, 2026
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
objectstack-fleet commentedon Oct 7, 2026
✅ ACCEPT: PR #22125 at
0262046319(patch round 1 delivered). Parked for the contract review; a partial landingdomain:specseat 3 (#18883) ·os-justin· sessionsession_01RPo7FUd6bSnAfkWMAKi848· 2026-10-07T23:29Z · holder of claim6044779383, on the dev report6048908151.The round's four asks, read on GitHub:
action.zod.ts's describe now ends "(one dialog, not two).", pinned inaction-description.test.tson theio: 'input'JSON Schema Studio renders. The pin is reverse-verified red on the old bytes, and the changeset names the fix.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 governedsubmitBehaviorrow and (b) thesys_emailIEmailService.sendhelp.origin/main54ace18c6is merged by a merge commit throughos-regen-merge.sh, with the docs regenerated in their own commit.Since the dev's merge,
mainmoved twice: PR #22115 →cdeabec848and PR #22124 →15ec50e528. PR #22124 editedio-node-config.zod.tstoo, in the notifytitle/messagebuilders, while this PR edits that file'stemplatedescribe. A read-onlygit merge-treeof this head against15ec50e528is 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:
Test Coreruns it all.The landing is partial. This PR lands
Part of #22093. On its merge the card returns topm:queue, unassigned, with aRelease:line naming the two remainders:submitBehaviordescribe (view.zod.ts) and its regeneratedskills/objectstack-ui/references/react-blocks.mdrow: a separate Tier H draft PR, landed on the maintainer's approval;sys_emailfield help namingIEmailService.send(platform-objects), after 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 settles the same generated bundles.Landing to-do:
packages/spec/src/**non-test, so the path limb owes a## Contract reviewatCONTRACT_REVIEW_TIERon the landing head. It is dispatched now, withneeds:contract-reviewon the PR in the same act.in_progressat this read),check-governed-merges --pr 22125,pr_readyand auto-merge.9 remaining items
docs(qa): requote the package-id refusal in cli.plugin-manifest-build…
objectstack-fleet commentedon Oct 8, 2026
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
objectstack-fleet commentedon Oct 8, 2026
✅ ACCEPT: remainders (b) and (c), PR #22309 at
acc26751bdomain:specseat 3 (#18883) ·os-justin· sessionsession_01RPo7FUd6bSnAfkWMAKi848· 2026-10-08T14:25Z · holder of claim6061277640. Report read:6061995025.Checked on GitHub and against
origin/main, not from the report:mainat this stamp.Part of #22093(no closing keyword), withClause-②: noand apatchchangeset for@objectstack/platform-objects. No model identifier appears.sys_emailheaders_jsonandstatushelp now say what the field holds and when it is set, in product words. TheIEmailService.sendreference 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).cli.plugin-manifest-build-contractnow quotes the currentmanifestIdRefusalheadline, checked against a livesafeParse. The item revision goes 2 → 3 with its history entry.Clause-②: no, and--tiernames 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:
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
submitBehaviorrow (Tier H; the maintainer's approval, answer A to6047193742).objectstack-fleet commentedon Oct 8, 2026
Landed in part: PR #22309 →
4e4111ca05(remainders (b) and (c)). The card stays with this seat for (a)domain:specseat 3 (#18883) ·os-justin· sessionsession_01RPo7FUd6bSnAfkWMAKi848· 2026-10-08T15:23Z · holder of claim6061277640, whose scope this act closes.4e4111ca05. It has one parent,dc4a5c630, and is an ancestor oforigin/main.acc26751b(ACCEPT6062040468, the review of record:Clause-②: no, no suspect path). All checks were settled before it was made ready (31 success, 3 expected skips).sys_emailheaders_jsonandstatushelp reads in product words in all four bundles. TheIEmailService.sendreference lives in a code comment, and a pin walks every objects-bundle leaf for a service-interface name.cli.plugin-manifest-build-contractquotes the current package-id refusal headline (revision 3).headers_json's help still omit en's last sentence. This is pre-existing translation lag, outside the filing classes.The card stays
pm:dispatchedand assigned toos-justin: this seat claims the last remainder, (a), in the next comment. (a) is the governedsubmitBehaviordescribe and its regeneratedskills/objectstack-ui/references/react-blocks.mdrow, landed on the maintainer's approval (route A of6047193742).Generated by Claude Code
objectstack-fleet commentedon Oct 8, 2026
Claim: PM loop round 2 (the card's last remainder (a), the governed
submitBehaviordescribe) · 2026-10-08T15:24ZSession:
session_01RPo7FUd6bSnAfkWMAKi848Account:
os-justin(the seat's linked user asGET /useranswers it; the card's assignee, kept from claim6061277640)Branch:
claude/issue-22093-remainder-a-submit-behaviorWorktree:
objectstack-issue-22093-aDomain:
domain:specSeat:
domain:spec#3(seat post #18883)File surface (at
origin/main4e4111ca0; stop on breach and explain in the report):packages/spec/src/ui/view.zod.ts(near:4472–:4485): the form viewsubmitBehaviordescribe drops "(ruled 2026-08-11)". The ruling date and its tracker reference move into the code comment above it, and that comment'sskills/objectstack-ui/references/react-blocks.md(gen:react-blocks). This is governed, Tier H.content/docs/references/ui/view.mdxandcontent/docs/references/api/protocol.mdx(gen:docs).submitBehaviorpin (packages/spec/src/ui/view-submit-redirect-url.test.ts) and.changeset/22093-*.md.Container & model:
S,mode:subagent,model: fable(--tierat4e4111ca0: MANDATORY viaskills/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 skillThread-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.mdxnear:1360; this card's rows there are near:1749and:1834. These are different rows of a generated file, so this is ordinary concurrency: whichever lands later mergesmainwithscripts/pm/os-regen-merge.sh. No open PR touchesview.zod.ts,react-blocks.md,view.mdxor 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
objectstack-fleet commentedon Oct 8, 2026
os-dev-report⚠️ paragraph that deferred the edit to #22093 is deleted.",
{
"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
redirectarm,urlis relative-only and interpolates only declared record fields as{{record.field_name}}, URL-escaped (ruled 2026-08-11).","after": "Post-submit behavior. On the
redirectarm,urlis 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
"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
objectstack-fleet commentedon Oct 8, 2026
✅ ACCEPT: remainder (a), PR #22322 at
acba7086d. Governed (Tier H): parked for the contract review, then the maintainer's approvaldomain:specseat 3 (#18883) ·os-justin· sessionsession_01RPo7FUd6bSnAfkWMAKi848· 2026-10-08T16:14Z · holder of claim6063214700. Report read:6064111005.Checked on GitHub and against
origin/main, not from the report:Fixes #22093; this is the card's last remainder.Clause-②: no, with apatchchangeset for@objectstack/spec. No model identifier appears in the body or the commits.## 维护者速读(草稿)with the seat's opinion left empty.submitBehaviorhelp now ends "URL-escaped." Every other fact in the sentence is unchanged.skills/objectstack-ui/references/react-blocks.md. It was clipped at the 160-character limit and now reads whole.content/docs/references/ui/view.mdxand 2 incontent/docs/references/api/protocol.mdx.submitBehaviorrow, and each one only drops the parenthetical.view-submit-redirect-url.test.tsreads 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.check-governed-merges.mjs --pr 22322puts 1 of 6 paths on the register (skills/**), so this PR lands at Tier H. The generated-surface exception ([finding]skills/*/references/_index.mdis generator-owned (gen:skill-refs) yet sits inside theskills/**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--checkexited 254 in the seat's read-only checkout, so the exception failed closed.Dispositions:
6047193742: draft, landed on an authorized approval.check:type-check-debt,check:skill-examples,check:dual-build-cjs-loads,check:lean-entry-closureandcheck:published-readme-exports. All of them are read from CI on this head, the same families the two earlier rounds declared.Next:
CONTRACT_REVIEW_TIER(packages/spec/src/**is a suspect path, and the skills hunk is reviewed at that tier). The markerneeds:contract-reviewgoes on the PR with this ACCEPT.needs-user-decisionon the PR, the final 维护者速读, and review requests toos-zhuangandhotlong.Generated by Claude Code
objectstack-fleet commentedon Oct 8, 2026
Contract review
Served-tier:
CONTRACT_REVIEW_TIERHead-sha:
acba7086d75db27dd45ce54d156ea219cd6ff9feLocal-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 againstmain(merge base4e4111ca0, 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-onlyrgover the local clone.① Derived judgments
.describe()string on the.optional()wrapper ofFormViewSchema.submitBehavior(packages/spec/src/ui/view.zod.ts) and the code comment above it. Zoddescribeis 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.redirectarm, "relative-only", the double-bracerecord.field_nameinterpolation, "URL-escaped."). The date and#7496now 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 theskills/objectstack-ui/references/react-blocks.md: 1 row (ObjectForm›submitBehavior).build-react-blocks-contract.tsrendersclip(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 theNested Shapeheading, 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'sreasonrow ("the engine ruled is not an identifier"), not a date.rg "URL-escaped \(ruled"over the local clone (at3d9188502e, older thanmain; 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 theFormViewSchemasymbol only) owe nothing, and the release-owned17-3.mdxis rightly untouched.view-submit-redirect-url.test.tscalls the sameprojectPublishedJsonSchemathe generators call, resolves$ref/$defsto the root asresolveRootdoes, and readsproperties.submitBehavior.description.gen:react-blocksprojects with{ unrepresentable: 'any' }(default output io);build-schemas.ts, which emits thejson-schema/filesgen:docsrenders from, projects with the default io and falls back toio: 'input'only on an unrepresentable schema; the pin passesio: 'input'(Studio's reading, the form theaction-descriptionpin of PR fix(spec): author-facing describes and refusals drop service-interface names, ruling dates and foreign example ids #22125 set).iomovesrequired, defaults and transform sides, never a node'sdescription, so the three readings agree on this string, and the pin's third assertion (FormViewSchema.shape.submitBehavior.descriptionequals the projected help, through thelazySchemaProxy) closes the gap from the source side. The positive control names the facts; the negative leg reuses the file'sRULING_DATEregex 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..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 withmain, so a new file is the only correct shape.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
main:.changeset/pre.jsonreadsmode: pre,tag: next;@objectstack/specis17.7.0inside thefixedgroup. A help-text-only change publishes no new or removed key, type, export or accept-set member, sopatchis the level the diff warrants, and that is what the changeset declares. TheCheck Changesetruns on the head read success.Clause-②: nowith no arm;clause2-line.mjsreads itdeclared/no/ armnull, and the claim6063214700and the changeset say the same. Against the definition (「本卡放宽接受集或扩大公开面吗」): nothing is widened and nothing narrowed — describe metadata only; the quote duty for anothat deletes a refusal does not apply, since no refusal text is deleted.no, unarmed, is the right reading.③ Boundary flags
open_questionsin the report6064111005: empty. Nothing to answer.skills/**): answered, route A stands. The queue guard's register does carry aspec-react-blocksrow ([finding]skills/*/references/_index.mdis generator-owned (gen:skill-refs) yet sits inside theskills/**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 ACCEPT6064160628read that proof failed closed in its checkout (exit 254) and kept route A of6047193742: 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: theGoverned Surface Queue Guardcheck-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.check:generated --fixin 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 gatesandType Check · debt ledgerread success at my second read;Lint & Repo GatesandType Check · workspacewere 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.6064067917); answered in ① (no hand-written page carries the sentence; the release-owned page is read-only and untouched). No review comments, no reviews.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-behaviorReviewed-by:
session_01RPo7FUd6bSnAfkWMAKi848VERDICT: PASS
objectstack-fleet commentedon Oct 9, 2026
Landed: PR #22322 →
ad381fd943(Fixes #22093, the card's last remainder). The card is closeddomain:specseat 3 (#18883) ·os-justin· sessionsession_01RPo7FUd6bSnAfkWMAKi848· 2026-10-09T00:47Z · holder of claim6063214700, closed by this act.os-zhuangapproved PR fix(spec): the submitBehavior property help carries no ruling date #22322 atacba7086d(2026-10-08T23:58Z) and enqueued it. It merged through the merge queue at 2026-10-09T00:35Z asad381fd943, which has one parent,16096e8d7b, and is an ancestor oforigin/main. GitHub closed this card on the merge.acba7086d(ACCEPT6064160628; contract review PASS6064355753).content/docs/references/api/protocol.mdx, whichmainalso moved (fix(metadata): the object read's sortability follows the caller's field permission for every caller class (#22250) #22308, other rows). This PR's own 4 changed lines there landed identically: its diff from the merge base matches the squash's diff from its parent.submitBehaviorhelp reads "… URL-escaped." in Studio, the reference docs and the publishedobjectstack-uiskill. The ruling date and spec: rule the submitBehavior.url semantics — objectui#4190 dead-ends on it #7496 live in the code comment.This act removes
pm:dispatched; the domain, area and type labels stay.Generated by Claude Code
fix(spec): author-facing describes and refusals drop service-interfac…
fix(platform-objects): sys_email field help names no service interfac…
fix(spec): the submitBehavior property help carries no ruling date (o…
test(spec): the class (e) remainder's titles state each cited decisio…