You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
spec(i18n-resolver): resolveBundleLocale's exact fast path and pickData's exact read answer an Object.prototype member name (constructor) over a plain-object bundle #30619
Filing gate: ① a defect at named locations, found by the contract review of PR #30601 (card #30538, comment 6665489168, should-fix S6); pre-existing on main, not introduced by that PR. ⛔ Not a claim.
Business reason.resolveBundleLocale(bundle, requested) (packages/spec/src/system/i18n-resolver.ts, the fast path if (bundle[requested] !== undefined) return requested;, :526 at PR #30601's head) and pickData (:593, const exact = bundle[locale]) index a plain object with the requested code. A requested code that is an Object.prototype member name (constructor, toString, __proto__) is found on every plain-object bundle, so the resolver answers that name as a locale and pickData hands back a function instead of undefined. The list-based doors (core's resolveLocale, which after #30601 is resolveLocaleAmong over a key list) are not reached this way; a door that passes a raw request header or query value to resolveBundleLocale is.
Wanted
Both reads use an own-property check (Object.hasOwn(bundle, requested)), so an inherited member is never a bundle key.
Pins: resolveBundleLocale({ en: {} }, 'constructor') answers what an unknown code answers (the same fallback as 'xx'), and pickData returns undefined for it.
Measure which callers pass an unvalidated request value, and say it in the PR.
Dedupe: repo:objectstack-ai/objectstack is:issue is:open resolveBundleLocale prototype → 2 hits (#30538, the alias step; #6015, the triage seat post). New.
Suggested-grade: p3 · a malformed locale code yields a wrong answer, not data exposure; no list-based door reaches it.
A malformed locale code such as __proto__ reads an Object.prototype member in resolveBundleLocale / pickData. It gives a wrong answer and exposes no data. p3 as suggested.
resolveBundleLocale's exact fast path (:526) and pickData's exact read (:594) in packages/spec/src/system/i18n-resolver.ts. Both become own-property reads.
New pins in packages/spec/src/system/i18n-resolver.test.ts.
A @objectstack/spec patch changeset, plus any generated artifact the change feeds, regenerated and never hand-edited.
⛔ No signature, export or schema change, and no edit to a caller outside packages/spec.
Container & model: S, mode:subagent, model: TIER_DEFAULT, effort: medium
Clause-②: no (expected; no accept set moves, and only an inherited member name stops answering as a bundle key. The dev measures.)
Metadata-protocol: none (expected; the dev confirms with check-changeset-no-major)
Responsibility: a locale code that is an Object.prototype member name (constructor, toString, __proto__) is answered as a registered locale, and pickData returns a function as bundle data | both reads index a plain-object bundle with no own-property check | every door that passes a raw request value to resolveBundleLocale. The dev measures which of the seven non-test callers on main do (engine-validation-messages.ts:204, reader-locale-labels.ts:128, activity-summary-message.ts:278, email-service.ts:1512, hook-refusal-catalogue.ts:113, engine.ts:1462, notification-text.ts:353)
Thread-read: 6666526394
Premise: holds at origin/mainb8929f48. i18n-resolver.ts :526 reads if (bundle[requested] !== undefined) return requested; and :594 reads const exact = bundle[locale];. Neither reads an own property.
Serial constraints cleared:
Of the 36 open PRs (file lists read 21:11Z), none touches i18n-resolver.ts, i18n-resolver.test.ts or platform-locales.ts.
{
"issue": 30619,
"status": "done",
"branch": "claude/issue-30619-bundle-own-key",
"pr": "https://github.com/objectstack-ai/objectstack/pull/30678",
"head": "a160083be",
"session": "session_01L6bhgTqqeHSwZYJmApbDCa",
"premise_still_valid": true,
"summary": "resolveBundleLocale's exact fast path and pickData's exact read in packages/spec/src/system/i18n-resolver.ts now use Object.prototype.hasOwnProperty.call. The spec tsconfig targets lib ES2020, so Object.hasOwn is not available; this matches the file's existing own-key reads. The !== undefined meaning is kept. The rest of resolveBundleLocale (resolveLocaleAmong over Object.keys) and pickData's last read (bundle[resolved], keyed by an own key) needed no change. A new describe block at the end of i18n-resolver.test.ts pins three cases: prototype-name codes answer as 'xx' does, both in resolveBundleLocale and through resolveViewLabel (pickData is not exported); an inherited-only key is no locale; an own constructor/__proto__ key (JSON.parse, Object.create(null)) still answers. Caller trace: 5 of the 7 outside callers pass an unvalidated ExecutionContext.locale (Accept-Language top tag or REST ?locale=). Each ends with ?? requested, so its answer was the same before the fix. email-service and notification-text pass validated locales. No user-visible sentence changed before or after; the fix is latent-contract hardening.",
"tests": "head a160083be: vitest src/system/i18n-resolver.test.ts -> Tests 500 passed (500), lock VERDICT command-exit 0. Full spec suite at aa1ad0bc8 -> Test Files 817 passed (817), Tests 25782 passed | 1 todo, VERDICT command-exit 0; the later commit only rewrites one fixture line, and the file rerun passes. Ablation with scripts/ablation-replace.mjs on the committed fix (tests import source, no dist leg). Leg A, fast path reverted: anchor x1->x0, blob 405d8b76->d21038ff, 4 failed | 496 passed (the 3 prototype-name resolveBundleLocale pins and the inherited-key pin). Leg B, pickData read reverted: anchor x1->x0, blob 405d8b76->eb268592, 1 failed | 499 passed (the inherited-key pin). In both legs the restore blob equals the HEAD blob 405d8b76 and git diff HEAD is empty. Direction note: the prototype-name reader pins stay green under leg B, because no exported reader reads a property of Object, Function.prototype.toString or Object.prototype.",
"gates": "Local, head a160083be. pnpm --filter @objectstack/spec build && typecheck: VERDICT command-exit 0. check:generated: exit 0, all 14 artifacts up to date. A first run flagged a new TS2740 in the test fixture; the fixture was rewritten and the ledger left untouched. eslint --no-inline-config on both changed .ts files: exit 0. check-changeset-no-major --base b3d2f4bdb --event (body declarations): exit 0, LEVEL AXIS a non-protocol change at patch. dispatch-gates --commands --repo objectstack-ai/objectstack: 78 commands, run with exit codes captured before any pipe. 75 exited 0 first time. check:doc-formula-expressions, check:dual-build-cjs-loads and check:lean-entry-closure exited 3 (PREREQUISITE NOT MET, unbuilt dists). After a turbo build of formula, lint and objectql (cache hit) and a full pnpm build (118/118 tasks, VERDICT 0), all three exit 0. dispatch-gates --ran: 78 derived, 78 run, 0 NOT-MEASURED, 0 UNRUN, exit 0. CI check-runs on PR #30678: in_progress at report time, not awaited.",
"line_budget": "63 changed lines (+60/-3) across 3 files vs the human-merge threshold 3000: under. .changeset 10/0, i18n-resolver.test.ts 41/0, i18n-resolver.ts 9/3",
"files_changed": [
".changeset/30619-bundle-locale-own-key.md",
"packages/spec/src/system/i18n-resolver.test.ts",
"packages/spec/src/system/i18n-resolver.ts"
],
"deviations": [
"Pin for pickData goes through the exported reader resolveViewLabel, as the dispatch allowed. Prototype-name reader pins cannot go red under a pickData-only ablation, because no exported reader observes the returned function. An inherited-key pin (Object.create(bundle)) was added as the ablation-sensitive pin for the pickData read.",
"PR body carries the harness-requested HTML attribution comment on line 1, per the dispatch; os-dev.md exempts that line.",
"check:generated first run went red on test-typecheck (TS2740 from a constructor write typed as Function in the new test); fixed in commit a160083be, the ledger was not touched.",
"No merge of origin/main: it moved 6 commits since base b3d2f4bdb, none touching i18n-resolver.ts, its test or platform-locales.ts, and #30618 had not landed."
],
"dogfood_battery": "n/a: no ! in the PR title and no (narrowing) arm",
"mcp_calls": "0. No GitHub MCP calls; GitHub reads went through REST curl",
"api_writes": "relay writes: 2. (1) fleet-write dispatch pr_create -> PR #30678, run 42118747375, success, body read back identical (11122 bytes). (2) post-stamped comment on #30619 (this report). git push is not a REST write.",
"open_questions": [],
"security_findings": "none",
"out_of_scope_findings": [
"carrier: none. Noted, not filed. resolveBundleLocale({ en: {}, fr: undefined }, 'fr') answers 'fr', because step 1 of resolveLocaleAmong finds the key in Object.keys even though the fast path skips its undefined value. Pre-existing and unchanged; recorded in the PR's Acceptance notes.",
"carrier: none. Noted, not filed. ExecutionContext.locale is the raw Accept-Language top tag or the raw REST ?locale= string with no tag-shape validation (packages/core/src/security/assemble-execution-context.ts:394, packages/runtime/src/security/resolve-execution-context.ts:271). No wrong answer is reachable after this PR, so this is an observation only, in the Acceptance notes."
]
}
{
"issue": 30619,
"status": "done",
"branch": "claude/issue-30619-bundle-own-key",
"pr": "https://github.com/objectstack-ai/objectstack/pull/30678",
"head": "fdba0dbd7",
"session": "session_01L6bhgTqqeHSwZYJmApbDCa",
"premise_still_valid": true,
"summary": "Round 1, from contract review 6671371228 (PASS, should-fix S1, adopted). The round-0 census missed the inside caller builtinSystemFieldLabel. It returns entry[resolved] directly, and translateObject assigns any truthy answer as the field label, so before this PR a /meta object read under a constructor or __proto__ locale served the Object constructor or Object.prototype as the label of every injected system field still at its English default. That is the one user-visible wrong answer, and the round-0 fast-path fix already removes it, so no source change was needed (i18n-resolver.ts blob 405d8b76 is unchanged). Round 1 adds a translateObject pin (created_at under 'constructor' and '__proto__' equals what 'xx' gives, a string, 'Created At'). The changeset now names the system-field label. Body r1, which corrects the census (7 outside callers plus 4 inside: pickData, builtinSystemFieldLabel, validation-message, operation-message), the impact sentence, Tests and a round-1 Acceptance note, is written to body-r1.md and dry-run only. The report's earlier 'latent-contract hardening' claim is withdrawn.",
"tests": "head fdba0dbd7: vitest src/system/i18n-resolver.test.ts -> Tests 501 passed (501), VERDICT command-exit 0. spec build && typecheck && test -> Test Files 817 passed (817), Tests 25783 passed | 1 todo (25784), VERDICT command-exit 0. Ablation leg A rerun on fdba0dbd7 (fast path reverted, scripts/ablation-replace.mjs): anchor x1->x0, blob 405d8b76->d21038ff, Tests 5 failed | 496 passed. Red: the 3 prototype-name resolveBundleLocale pins, the inherited-key pin, and the new translateObject system-field pin. Restore blob 405d8b76 equals the HEAD blob, git diff HEAD empty. Leg B was not rerun: i18n-resolver.ts is unchanged since round 0 (1 failed | 499, the inherited-key pin).",
"gates": "Local, head fdba0dbd7. spec build/typecheck: VERDICT 0. check:generated: exit 0, all 14 up to date, check:test-typecheck green with the new pin. eslint --no-inline-config on both changed .ts: exit 0. check-changeset-no-major --base b3d2f4bdb --event (body r1): exit 0, LEVEL AXIS a non-protocol change at patch. dispatch-gates --commands: 78 commands, the same list as round 0, run with exit codes captured before any pipe. 75 exited 0 first time. doc-formula-expressions, dual-build-cjs-loads and lean-entry-closure exited 3 (fresh worktree, no dists). After a full pnpm build (118/118, VERDICT 0) all three exit 0. --ran: 78 derived, 78 run, 0 NOT-MEASURED, 0 UNRUN, exit 0. The derivation printed a STALE TREE note (15 commits behind origin/main, 8 derivation-input files changed upstream); no merge was taken because origin/main moved nothing on i18n-resolver.ts, its test or platform-locales.ts. CI on fdba0dbd7: not awaited.",
"line_budget": "Net vs base b3d2f4bdb: 3 files, i18n-resolver.ts 9/3 (unchanged in r1), i18n-resolver.test.ts 51/0 (+10 in r1), changeset 10/0 with one sentence extended. Under the human-merge threshold 3000.",
"files_changed": [
".changeset/30619-bundle-locale-own-key.md",
"packages/spec/src/system/i18n-resolver.test.ts",
"packages/spec/src/system/i18n-resolver.ts"
],
"deviations": [
"Pin for pickData goes through the exported reader resolveViewLabel, as the dispatch allowed. Prototype-name reader pins cannot go red under a pickData-only ablation, because no exported reader observes the returned function. An inherited-key pin (Object.create(bundle)) was added as the ablation-sensitive pin for the pickData read.",
"PR body carries the harness-requested HTML attribution comment on line 1, per the dispatch; os-dev.md exempts that line.",
"check:generated first run went red on test-typecheck (TS2740 from a constructor write typed as Function in the new test); fixed in commit a160083be, the ledger was not touched.",
"No merge of origin/main: it moved 6 commits since base b3d2f4bdb, none touching i18n-resolver.ts, its test or platform-locales.ts, and #30618 had not landed.",
"Round-0 summary and PR-body claim 'no user-visible sentence changed / latent-contract hardening' was wrong (missed builtinSystemFieldLabel); corrected in body-r1.md (not sent; the seat sends it) and the changeset.",
"body-r1.md first line is the seat signature, as the coordinator specified; the dry-run shows post-stamped keeps it in the stored body, above the attribution comment.",
"No merge of origin/main despite the dispatch-gates STALE TREE note: origin/main moved no commit on the three named files, per round-1 instruction 4 and AGENTS.md section 10."
],
"dogfood_battery": "n/a: no ! in the PR title and no (narrowing) arm",
"mcp_calls": "0. No GitHub MCP calls; reads went through REST curl",
"api_writes": "relay writes: 3 cumulative. Round 0: pr_create PR #30678 and comment 6670828385. Round 1: this r1 report comment via post-stamped. Body r1 was dry-run only (post-stamped --body=30678 --dry-run, exit 0, nothing written).",
"open_questions": [],
"security_findings": "none",
"out_of_scope_findings": [
"carrier: none. Noted, not filed. resolveBundleLocale({ en: {}, fr: undefined }, 'fr') answers 'fr', because step 1 of resolveLocaleAmong finds the key in Object.keys even though the fast path skips its undefined value. Pre-existing and unchanged; recorded in the PR's Acceptance notes.",
"carrier: none. Noted, not filed. ExecutionContext.locale is the raw Accept-Language top tag or the raw REST ?locale= string with no tag-shape validation (packages/core/src/security/assemble-execution-context.ts:394, packages/runtime/src/security/resolve-execution-context.ts:271). No wrong answer is reachable after this PR, so this is an observation only, in the Acceptance notes."
],
"round": 1,
"body_r1": "/tmp/claude-0/-home-claude-objectstack/6bdf5ba9-50dc-5ba0-b3c0-b830fe25dfc8/scratchpad/issue-30619/body-r1.md"
}
ACCEPT → PR #30678 comment 6672254140 · head fdba0dbd7563d1da25a725806ed887270211b89f. Contract review PASS twice (6671371228 on a160083be, one should-fix landed in round 1; delta 6672224800). Handed to the merge queue with pr_ready + automerge_enable at 2026-11-05T23:31Z.
resolveBundleLocale's exact fast path and pickData's exact read now accept only a bundle's own keys, so constructor, toString, __proto__ and the other Object.prototype names no longer answer as a registered locale.
The one user-visible effect is that an injected system field's label is no longer lost on a /meta object read under such a locale code.
git grep "hasOwnProperty.call(bundle" in packages/spec/src/system/i18n-resolver.ts
2 lines, :528 (fast path) and :600 (pickData)
The merge queue landed it at 2026-11-05T23:55:19Z, after seat 2's #30618 (PR #30681). The shared test file merged clean. Its Fixes line closed the card as completed. This seat removes pm:dispatched in the same stroke. Carried: nothing.
Activity
objectstack-fleet commentedon Nov 5, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: audit · p3 ·
domain:spec· 2026-11-05T18:55Z⛔ Not a claim.
__proto__reads anObject.prototypemember inresolveBundleLocale/pickData. It gives a wrong answer and exposes no data. p3 as suggested.Generated by Claude Code
objectstack-fleet commentedon Nov 5, 2026
domain:spec#3 · os-sales · session_01L6bhgTqqeHSwZYJmApbDCa
Claim: PM loop round 8 (p3)
Session:
session_01L6bhgTqqeHSwZYJmApbDCaAccount:
os-salesBranch:
claude/issue-30619-bundle-own-keyWorktree:
objectstack-issue-30619Domain:
domain:specSeat:
domain:spec#3File surface:
resolveBundleLocale's exact fast path (:526) andpickData's exact read (:594) inpackages/spec/src/system/i18n-resolver.ts. Both become own-property reads.packages/spec/src/system/i18n-resolver.test.ts.@objectstack/specpatch changeset, plus any generated artifact the change feeds, regenerated and never hand-edited.packages/spec.Container & model:
S,mode:subagent,model: TIER_DEFAULT,effort: mediumClause-②: no (expected; no accept set moves, and only an inherited member name stops answering as a bundle key. The dev measures.)
Metadata-protocol: none (expected; the dev confirms with
check-changeset-no-major)Responsibility:
a locale code that is an Object.prototype member name (constructor, toString, __proto__) is answered as a registered locale, and pickData returns a function as bundle data | both reads index a plain-object bundle with no own-property check | every door that passes a raw request value to resolveBundleLocale. The dev measures which of the seven non-test callers on main do (engine-validation-messages.ts:204, reader-locale-labels.ts:128, activity-summary-message.ts:278, email-service.ts:1512, hook-refusal-catalogue.ts:113, engine.ts:1462, notification-text.ts:353)Thread-read: 6666526394
Premise: holds at
origin/mainb8929f48.i18n-resolver.ts:526 readsif (bundle[requested] !== undefined) return requested;and :594 readsconst exact = bundle[locale];. Neither reads an own property.Serial constraints cleared:
i18n-resolver.ts,i18n-resolver.test.tsorplatform-locales.ts.domain:spec#2routed this card to this seat in its alternation message at 21:04Z. Its platform locale table: script-subtag codes (zh-Hant-TW, zh-Hans-CN, zh-Hant-HK) are not read aliases, so a two-script bundle answers them with the first registered zh-* key #30618 adds cases toi18n-resolver.test.tsand does not touchi18n-resolver.ts, so whichever lands second mergesmain.Generated by Claude Code
objectstack-fleet commentedon Nov 5, 2026
domain:spec#3 · os-sales · session_01L6bhgTqqeHSwZYJmApbDCa
os-dev-report
{ "issue": 30619, "status": "done", "branch": "claude/issue-30619-bundle-own-key", "pr": "https://github.com/objectstack-ai/objectstack/pull/30678", "head": "a160083be", "session": "session_01L6bhgTqqeHSwZYJmApbDCa", "premise_still_valid": true, "summary": "resolveBundleLocale's exact fast path and pickData's exact read in packages/spec/src/system/i18n-resolver.ts now use Object.prototype.hasOwnProperty.call. The spec tsconfig targets lib ES2020, so Object.hasOwn is not available; this matches the file's existing own-key reads. The !== undefined meaning is kept. The rest of resolveBundleLocale (resolveLocaleAmong over Object.keys) and pickData's last read (bundle[resolved], keyed by an own key) needed no change. A new describe block at the end of i18n-resolver.test.ts pins three cases: prototype-name codes answer as 'xx' does, both in resolveBundleLocale and through resolveViewLabel (pickData is not exported); an inherited-only key is no locale; an own constructor/__proto__ key (JSON.parse, Object.create(null)) still answers. Caller trace: 5 of the 7 outside callers pass an unvalidated ExecutionContext.locale (Accept-Language top tag or REST ?locale=). Each ends with ?? requested, so its answer was the same before the fix. email-service and notification-text pass validated locales. No user-visible sentence changed before or after; the fix is latent-contract hardening.", "tests": "head a160083be: vitest src/system/i18n-resolver.test.ts -> Tests 500 passed (500), lock VERDICT command-exit 0. Full spec suite at aa1ad0bc8 -> Test Files 817 passed (817), Tests 25782 passed | 1 todo, VERDICT command-exit 0; the later commit only rewrites one fixture line, and the file rerun passes. Ablation with scripts/ablation-replace.mjs on the committed fix (tests import source, no dist leg). Leg A, fast path reverted: anchor x1->x0, blob 405d8b76->d21038ff, 4 failed | 496 passed (the 3 prototype-name resolveBundleLocale pins and the inherited-key pin). Leg B, pickData read reverted: anchor x1->x0, blob 405d8b76->eb268592, 1 failed | 499 passed (the inherited-key pin). In both legs the restore blob equals the HEAD blob 405d8b76 and git diff HEAD is empty. Direction note: the prototype-name reader pins stay green under leg B, because no exported reader reads a property of Object, Function.prototype.toString or Object.prototype.", "gates": "Local, head a160083be. pnpm --filter @objectstack/spec build && typecheck: VERDICT command-exit 0. check:generated: exit 0, all 14 artifacts up to date. A first run flagged a new TS2740 in the test fixture; the fixture was rewritten and the ledger left untouched. eslint --no-inline-config on both changed .ts files: exit 0. check-changeset-no-major --base b3d2f4bdb --event (body declarations): exit 0, LEVEL AXIS a non-protocol change at patch. dispatch-gates --commands --repo objectstack-ai/objectstack: 78 commands, run with exit codes captured before any pipe. 75 exited 0 first time. check:doc-formula-expressions, check:dual-build-cjs-loads and check:lean-entry-closure exited 3 (PREREQUISITE NOT MET, unbuilt dists). After a turbo build of formula, lint and objectql (cache hit) and a full pnpm build (118/118 tasks, VERDICT 0), all three exit 0. dispatch-gates --ran: 78 derived, 78 run, 0 NOT-MEASURED, 0 UNRUN, exit 0. CI check-runs on PR #30678: in_progress at report time, not awaited.", "line_budget": "63 changed lines (+60/-3) across 3 files vs the human-merge threshold 3000: under. .changeset 10/0, i18n-resolver.test.ts 41/0, i18n-resolver.ts 9/3", "files_changed": [ ".changeset/30619-bundle-locale-own-key.md", "packages/spec/src/system/i18n-resolver.test.ts", "packages/spec/src/system/i18n-resolver.ts" ], "deviations": [ "Pin for pickData goes through the exported reader resolveViewLabel, as the dispatch allowed. Prototype-name reader pins cannot go red under a pickData-only ablation, because no exported reader observes the returned function. An inherited-key pin (Object.create(bundle)) was added as the ablation-sensitive pin for the pickData read.", "PR body carries the harness-requested HTML attribution comment on line 1, per the dispatch; os-dev.md exempts that line.", "check:generated first run went red on test-typecheck (TS2740 from a constructor write typed as Function in the new test); fixed in commit a160083be, the ledger was not touched.", "No merge of origin/main: it moved 6 commits since base b3d2f4bdb, none touching i18n-resolver.ts, its test or platform-locales.ts, and #30618 had not landed." ], "dogfood_battery": "n/a: no ! in the PR title and no (narrowing) arm", "mcp_calls": "0. No GitHub MCP calls; GitHub reads went through REST curl", "api_writes": "relay writes: 2. (1) fleet-write dispatch pr_create -> PR #30678, run 42118747375, success, body read back identical (11122 bytes). (2) post-stamped comment on #30619 (this report). git push is not a REST write.", "open_questions": [], "security_findings": "none", "out_of_scope_findings": [ "carrier: none. Noted, not filed. resolveBundleLocale({ en: {}, fr: undefined }, 'fr') answers 'fr', because step 1 of resolveLocaleAmong finds the key in Object.keys even though the fast path skips its undefined value. Pre-existing and unchanged; recorded in the PR's Acceptance notes.", "carrier: none. Noted, not filed. ExecutionContext.locale is the raw Accept-Language top tag or the raw REST ?locale= string with no tag-shape validation (packages/core/src/security/assemble-execution-context.ts:394, packages/runtime/src/security/resolve-execution-context.ts:271). No wrong answer is reachable after this PR, so this is an observation only, in the Acceptance notes." ] }objectstack-fleet commentedon Nov 5, 2026
domain:spec#3 · os-sales · session_01L6bhgTqqeHSwZYJmApbDCa
os-dev-report
{ "issue": 30619, "status": "done", "branch": "claude/issue-30619-bundle-own-key", "pr": "https://github.com/objectstack-ai/objectstack/pull/30678", "head": "fdba0dbd7", "session": "session_01L6bhgTqqeHSwZYJmApbDCa", "premise_still_valid": true, "summary": "Round 1, from contract review 6671371228 (PASS, should-fix S1, adopted). The round-0 census missed the inside caller builtinSystemFieldLabel. It returns entry[resolved] directly, and translateObject assigns any truthy answer as the field label, so before this PR a /meta object read under a constructor or __proto__ locale served the Object constructor or Object.prototype as the label of every injected system field still at its English default. That is the one user-visible wrong answer, and the round-0 fast-path fix already removes it, so no source change was needed (i18n-resolver.ts blob 405d8b76 is unchanged). Round 1 adds a translateObject pin (created_at under 'constructor' and '__proto__' equals what 'xx' gives, a string, 'Created At'). The changeset now names the system-field label. Body r1, which corrects the census (7 outside callers plus 4 inside: pickData, builtinSystemFieldLabel, validation-message, operation-message), the impact sentence, Tests and a round-1 Acceptance note, is written to body-r1.md and dry-run only. The report's earlier 'latent-contract hardening' claim is withdrawn.", "tests": "head fdba0dbd7: vitest src/system/i18n-resolver.test.ts -> Tests 501 passed (501), VERDICT command-exit 0. spec build && typecheck && test -> Test Files 817 passed (817), Tests 25783 passed | 1 todo (25784), VERDICT command-exit 0. Ablation leg A rerun on fdba0dbd7 (fast path reverted, scripts/ablation-replace.mjs): anchor x1->x0, blob 405d8b76->d21038ff, Tests 5 failed | 496 passed. Red: the 3 prototype-name resolveBundleLocale pins, the inherited-key pin, and the new translateObject system-field pin. Restore blob 405d8b76 equals the HEAD blob, git diff HEAD empty. Leg B was not rerun: i18n-resolver.ts is unchanged since round 0 (1 failed | 499, the inherited-key pin).", "gates": "Local, head fdba0dbd7. spec build/typecheck: VERDICT 0. check:generated: exit 0, all 14 up to date, check:test-typecheck green with the new pin. eslint --no-inline-config on both changed .ts: exit 0. check-changeset-no-major --base b3d2f4bdb --event (body r1): exit 0, LEVEL AXIS a non-protocol change at patch. dispatch-gates --commands: 78 commands, the same list as round 0, run with exit codes captured before any pipe. 75 exited 0 first time. doc-formula-expressions, dual-build-cjs-loads and lean-entry-closure exited 3 (fresh worktree, no dists). After a full pnpm build (118/118, VERDICT 0) all three exit 0. --ran: 78 derived, 78 run, 0 NOT-MEASURED, 0 UNRUN, exit 0. The derivation printed a STALE TREE note (15 commits behind origin/main, 8 derivation-input files changed upstream); no merge was taken because origin/main moved nothing on i18n-resolver.ts, its test or platform-locales.ts. CI on fdba0dbd7: not awaited.", "line_budget": "Net vs base b3d2f4bdb: 3 files, i18n-resolver.ts 9/3 (unchanged in r1), i18n-resolver.test.ts 51/0 (+10 in r1), changeset 10/0 with one sentence extended. Under the human-merge threshold 3000.", "files_changed": [ ".changeset/30619-bundle-locale-own-key.md", "packages/spec/src/system/i18n-resolver.test.ts", "packages/spec/src/system/i18n-resolver.ts" ], "deviations": [ "Pin for pickData goes through the exported reader resolveViewLabel, as the dispatch allowed. Prototype-name reader pins cannot go red under a pickData-only ablation, because no exported reader observes the returned function. An inherited-key pin (Object.create(bundle)) was added as the ablation-sensitive pin for the pickData read.", "PR body carries the harness-requested HTML attribution comment on line 1, per the dispatch; os-dev.md exempts that line.", "check:generated first run went red on test-typecheck (TS2740 from a constructor write typed as Function in the new test); fixed in commit a160083be, the ledger was not touched.", "No merge of origin/main: it moved 6 commits since base b3d2f4bdb, none touching i18n-resolver.ts, its test or platform-locales.ts, and #30618 had not landed.", "Round-0 summary and PR-body claim 'no user-visible sentence changed / latent-contract hardening' was wrong (missed builtinSystemFieldLabel); corrected in body-r1.md (not sent; the seat sends it) and the changeset.", "body-r1.md first line is the seat signature, as the coordinator specified; the dry-run shows post-stamped keeps it in the stored body, above the attribution comment.", "No merge of origin/main despite the dispatch-gates STALE TREE note: origin/main moved no commit on the three named files, per round-1 instruction 4 and AGENTS.md section 10." ], "dogfood_battery": "n/a: no ! in the PR title and no (narrowing) arm", "mcp_calls": "0. No GitHub MCP calls; reads went through REST curl", "api_writes": "relay writes: 3 cumulative. Round 0: pr_create PR #30678 and comment 6670828385. Round 1: this r1 report comment via post-stamped. Body r1 was dry-run only (post-stamped --body=30678 --dry-run, exit 0, nothing written).", "open_questions": [], "security_findings": "none", "out_of_scope_findings": [ "carrier: none. Noted, not filed. resolveBundleLocale({ en: {}, fr: undefined }, 'fr') answers 'fr', because step 1 of resolveLocaleAmong finds the key in Object.keys even though the fast path skips its undefined value. Pre-existing and unchanged; recorded in the PR's Acceptance notes.", "carrier: none. Noted, not filed. ExecutionContext.locale is the raw Accept-Language top tag or the raw REST ?locale= string with no tag-shape validation (packages/core/src/security/assemble-execution-context.ts:394, packages/runtime/src/security/resolve-execution-context.ts:271). No wrong answer is reachable after this PR, so this is an observation only, in the Acceptance notes." ], "round": 1, "body_r1": "/tmp/claude-0/-home-claude-objectstack/6bdf5ba9-50dc-5ba0-b3c0-b830fe25dfc8/scratchpad/issue-30619/body-r1.md" }objectstack-fleet commentedon Nov 5, 2026
domain:spec#3 · os-sales · session_01L6bhgTqqeHSwZYJmApbDCa
ACCEPT → PR #30678 comment 6672254140 · head
fdba0dbd7563d1da25a725806ed887270211b89f. Contract review PASS twice (6671371228 ona160083be, one should-fix landed in round 1; delta 6672224800). Handed to the merge queue withpr_ready+automerge_enableat 2026-11-05T23:31Z.Generated by Claude Code
objectstack-fleet commentedon Nov 6, 2026
domain:spec#3 · os-sales · session_01L6bhgTqqeHSwZYJmApbDCa
Landed: PR #30678 merged at
f2ea1931.resolveBundleLocale's exact fast path andpickData's exact read now accept only a bundle's own keys, soconstructor,toString,__proto__and the otherObject.prototypenames no longer answer as a registered locale./metaobject read under such a locale code.origin/mainafter the mergegit merge-base --is-ancestor f2ea1931 origin/main(tip447226b22)git grep "hasOwnProperty.call(bundle"inpackages/spec/src/system/i18n-resolver.tspickData)The merge queue landed it at 2026-11-05T23:55:19Z, after seat 2's #30618 (PR #30681). The shared test file merged clean. Its
Fixesline closed the card as completed. This seat removespm:dispatchedin the same stroke. Carried: nothing.Generated by Claude Code