Skip to content

Correct 17 false behavioral claims in skills/objectstack-i18n — sweep flight ⑧ - #13833

Merged
os-zhuang merged 2 commits into
mainfrom
claude/issue-13815-skills-sweep-i18n
Aug 31, 2026
Merged

Correct 17 false behavioral claims in skills/objectstack-i18n — sweep flight ⑧#13833
os-zhuang merged 2 commits into
mainfrom
claude/issue-13815-skills-sweep-i18n

Conversation

@huangyiirene

Copy link
Copy Markdown
Collaborator

Fixes#13815
Part of #13658

Flight ⑧ of the published-skills factual sweep: skills/objectstack-i18n/** (3 files, 807 lines at branch point). Every claim was settled against the implementing code plus an executed probe — never against another document. 17 distinct false facts across 20 landing sites; net −8 lines, −2 tokens (SKILL.md 6337/6338, evals/README.md 410/411 — both shrink, no ceiling touched).

references/_index.md is generator-owned and was not hand-edited; check:skill-refs is green against it.

Where the truth was read

Fact classImplementing code
bundle / item / config shapespackages/spec/src/system/translation.zod.ts
service contractpackages/spec/src/contracts/i18n-service.ts
shipped adapterspackages/services/service-i18n/src/{file-i18n-adapter,i18n-service-plugin}.ts · packages/core/src/fallbacks/memory-i18n.ts
authored-item syncpackages/core/src/fallbacks/authored-translation-sync.ts
CLI coverage / extractpackages/cli/src/commands/i18n/{check,extract}.ts · packages/cli/src/utils/i18n-{coverage,extract}.ts
orphan-key lintpackages/lint/src/validate-translation-references.ts
shipped examplesexamples/app-crm/src/translations/ · examples/app-todo/src/translations/

Per-item corrections

#落点beforeafter
1SKILL.md · Object-Level table"Object-level text (label is required)""Object-level text (every key optional)" — label: z.string().optional(), with a schema comment arguing partial translation is the normal state
2SKILL.md · Object-Level tableno _tabs rowadded _tabs.{tab_name} — a live authorable surface (resolveTabLabel), extracted and coverage-gated
3SKILL.md · Object-Level table_actions holds label, confirmText, successMessage, params, resultDialogdescription added — declared on the action translation shape
4SKILL.md · Object-Level table_sections holds "Form section / tab label""Form section label" — tabs are their own group, now row 2 above
5SKILL.md · "Top-level groups alongside objects"apps, messages, globalActions, dashboards, settings, metadataForms, settingsCommonpages and flows added — 10 groups on the shape, not 8
6SKILL.md · Core Concepts 1same list minus settingsCommon, and object content omits tabsboth lists brought to the shape's real membership
7SKILL.md · Authoring at Runtime"skipped by the runtime sync — a silent skip … rather than inferred from the item name"the sync falls back to a BCP-47-looking item name, then skips with an [i18n] … — skippedwarning naming the row. Not silent
8SKILL.md · "Retired: the o.* dialect""rejected at save time with a message naming the group to use instead""both doors now reject it — files included". 4 of the 10 keys are told they have no home (reports, notifications, errors, namespace), so "naming the group to use instead" was false for them
9SKILL.md · Pitfall "The Retired o.* Shape""Files registered in that shape resolve to nothing; runtime items … rejected at save time"both doors reject: defineTranslationBundlethrows on a file bundle. The file door was closed at the same time as the item door
10SKILL.md · os i18n check"reports missing object/field/option/view/action keys"every surface the extractor walks — 14 source kinds live, 5 were named
11SKILL.md · Extract skeletons"writes {locale}.objects.generated.ts … Other flags: --default-locale, --filter, --dry-run, --json"the {locale}.metadata-forms.generated.ts companion is written by default; four more flags exist (--no-merge, --no-objects-only, --metadata-forms, --source-hashes), so the list now points at --help instead of claiming to be complete
12SKILL.md · "Use both gates""Renaming a label, adding an object, or removing a spec key leaves coverage at 100%"adding an object lowers coverage — its keys join the expected set. Dropped from the trio
13SKILL.md · II18nService methodsgetLocales() / getDefaultLocale() / setDefaultLocale()setSupportedLocales() added — on the contract and implemented by both shipped adapters
14SKILL.md · II18nService optional methods"getCoverage, suggestTranslations — no shipped implementation provides"getFieldLabels added — same class exactly: declared optional, probed by both serving surfaces, implemented by no shipped provider
15SKILL.md · Diff & Coverage SchemasTranslationDiffItem = key, status, locale, sourceHash, AI fieldsoptional objectName added
16SKILL.md · orphan-key lint"object, field, view, action, param, section, app, nav item, dashboard or widget"flow screens added — the rule walks flows.{name}.screens.{node} too
17SKILL.md · Authoring Translation Bundles"mirrors the shipped example apps ({en,zh-CN}.ts + index.ts)"that is examples/app-todo alone, and it ships three locales
18SKILL.md · CRM I18n Blueprint"Bundle entry: src/translations/index.ts … Locale files: {en,zh-CN,ja-JP,es-ES}.ts"examples/app-crm has one file, crm.translation.ts, holding en + zh-CN. No index.ts, no per-locale files, no ja-JP/es-ES
19SKILL.md · CRM table"per-locale source files by convention" · "imports per-locale files" · objects.account.fields.*the CRM example does none of these; its object is crm_account
20SKILL.md · Pitfall "Ignoring Coverage Reports""Stale translations can cause confusion. Always run os i18n check"coverage cannot see staleness — this document's own extract --check section says so. Now points at the gate that can
21evals/README.md · rubric"runtime objects.* vs secondaryo.* format""retired o.* is rejected" — a grader taught the retired dialect is a live secondary format fails correct answers
22evals/README.md · rubric"ICU is experimental""no ICU engine" — the messageFormat knob was removed and nothing evaluates ICU strings

Rows 4, 6, 19 are the second landing sites of facts 2, 5 and 18; 17 distinct facts, 20 sites, plus 2 rubric rows.

Executed evidence

Two probe scripts (temporary, removed before commit — this diff is 2 markdown files). Built first: @objectstack/service-i18n..., @objectstack/lint..., @objectstack/platform-objects... (exit 0 each), so every read is against rebuilt dist, not stale declarations.

Schema/adapter probe, run from packages/services/service-i18n:

=== TranslationDataSchema top-level groups ===
["objects","apps","messages","globalActions","dashboards","pages","flows","settings","metadataForms","settingsCommon"]
=== ObjectTranslationDataSchema sub-keys ===
["label","pluralLabel","description","fields","_views","_actions","_sections","_tabs"]
=== object _actions sub-keys ===
["label","description","confirmText","successMessage","params","resultDialog"]
=== is objects.OBJ.label REQUIRED? ===
parse { objects: { task: { pluralLabel } } } (no label) -> success=true
=== retired o.* dialect ===
item.o: rejected=true :: `o` is the retired object-first dialect … use 'objects.OBJECT_NAME'
item.reports: rejected=true :: `reports` … reports have no translation group, omit them
bundle-door o: rejected=true
defineTranslationBundle({ en: { o: … } }) -> threw
=== interpolation ===
double: Welcome, Alice! single: Hi, {userName}! icu: messages.icu (key echoed)
=== contract methods on both shipped adapters ===
setSupportedLocales file=true memory=true
getFieldLabels file=false memory=false
getCoverage file=false memory=false
suggestTranslations file=false memory=false

CLI probe (tsx, packages/cli), driving the real walker and coverage detector:

=== ExpectedEntry.source kinds the walker emits ===
action 7 · app 1 · dashboard 1 · field 6 · flow 2 · globalAction 4 ·
metadataFormField 948 · metadataFormSection 150 · metadataType 54 ·
navigation 1 · object 3 · option 1 · page 1 · view 1 · widget 1
=== _tabs IS harvested ===
objects.task._tabs.urgent.label [source=view]
flows.onboard.screens.welcome.title [source=flow]
=== os i18n check reported source kinds ===
action, app, dashboard, field, globalAction, metadataForm, navigation,
object, option, page, view, widget (12 kinds from one small fixture)
=== --strict promotes non-default gaps ===
lax errors=0 warnings=783
strict errors=783 warnings=0

The non-vacuity control is satisfied many times over: facts 1, 2, 3, 5, 8, 9, 10, 13, 14 were each decided by a run, not a read.

Gates — all run at 5d16fd477 (the final commit)

Families derived from the real diff with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (exit 0; 14 families, re-derived unchanged on the final commit), plus the skill-specific gates the derivation scores silent because they compute their own population:

gateexit
check-ci-filter-parity · check-cross-package-test-inputs · check-shard-attestation0 · 0 · 0
check-skills-token-ratchet0 — SKILL.md 6337/6338 (−1), evals/README.md 410/411 (−1)
check:doc-formula-expressions · check:agent-test-spelling · check:corpus-claim-drift0 · 0 · 0
check:cross-package-test-inputs · check:doc-authoring · check:pm-governed-merges0 · 0 · 0
check:role-word · check:skill-compatibility · check:skill-frame-sync0 · 0 · 0
check:nul-bytes · check:pm-skill-ratchet · check:pm-skill-id-lint · check:skill-frame-freshness0 · 0 · 0 · 0
@objectstack/spec check:skill-examples0 — 260 marked blocks across 101 files, population non-empty (this package contributes 4 os:check fences)
@objectstack/spec check:skill-refs · check:skill-docs0 · 0
pnpm lint (repo-wide eslint . --no-inline-config)0
check-test-completeness3 — NOT MEASURED. The gate grades a saved turbo run test log and none exists locally; its own text says exit 3 "is not a red, and there is nothing here to fix"

ESLint was run whole rather than narrowed, and separately measured: both changed files report File ignored because no matching configuration was supplied — markdown is outside the linted population entirely (no files block in eslint.config.mjs names .md).

Pure skills/** diff, nothing published from any package — skip-changeset applies, matching flights ③/④/⑤ which landed the same shape with no changeset.

Governed surface

Published skills/**: this PR stays draft and is for the maintainer to merge. needs:contract-review is attached to this PR and to card #13815 in the same stroke (批 #12 clause ② CONTENT limb) and is never self-cleared.

Generated by Claude Code


Generated by Claude Code

…implementation
Flight 8 of the published-skills factual sweep (#13658). Every correction is
settled against the implementing code plus an executed probe; net -1 line.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EnE7G31tqbxN1rqpQmzurT
…en ratchet
The corrections in the previous commit were factually right but grew SKILL.md
by 124 tokens against a ceiling that only ever shrinks. Same facts, fewer
bytes: enumerations point at the authority instead of transcribing it, and
duplicated prose around the retired o.* dialect is stated once.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EnE7G31tqbxN1rqpQmzurT
@huangyiireneClaude

Copy link
Copy Markdown
CollaboratorAuthor

Contract review — PASS at head 5d16fd477

Applicability: clause-② CONTENT limb (批 #12). Both carriers attached at PR creation, delayed read-backs clean; cleared in this stroke.

Reviewer qualification, machine-read this sitting: get_sessionexternal_metadata.last_served_model = claude-fable-5 = CONTRACT_REVIEW_TIER.

Review: report + diff read; anchors independently re-measured on origin/main this hour —

  • _tabs is a live, gated slot: ObjectTranslationDataSchema declares it, packages/cli/src/utils/i18n-extract.ts:590–611 emits objects.<o>._tabs.<tab>.label for every rendered preset tab, and resolveTabLabel consumes it — the missing table row hid shipped capability;
  • pages is harvested by the same extractor (:563) — the top-level group list was under-enumerating;
  • setSupportedLocales is in the contract (packages/spec/src/contracts/i18n-service.ts:97) and implemented on BOTH shipped adapters (file adapter + packages/core/src/fallbacks/memory-i18n.ts) — the method-list omission was false;
  • The dev's parse probe disproving "label is required" ({objects:{task:{pluralLabel}}} parses green) and the LEGACY_OBJECT_FIRST_KEYS double-door rejection are executed evidence in both error directions, with the non-vacuity control satisfied many times over.

Program-significant: 8.5%/10% density — the highest measured in eight flights, and the dev's sharper class naming ("an enumeration that stopped growing when the schema did", 15 of 20 sites) supersedes the table-shape heuristic; recorded on the anchor. Out-of-scope findings verified real: #13835 (lint _tabs orphan leg missing, the accepted #11608 shape one group over) and #13837 (CLI --help under-count — the #13809 spec-twin pattern applied to a CLI surface). Budget: net −8 lines / −2 tokens, both files shrink, no ceiling touched; generator-owned index untouched, check:skill-refs green; whole-repo pnpm lint run un-narrowed, exit 0.

needs:contract-review cleared on BOTH carriers. Governed .md content: PR remains DRAFT for the maintainer's merge (os-zhuang / hotlong requested).


Generated by Claude Code

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

Labels

documentationImprovements or additions to documentationsize/sskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

skills-sweep ⑧: objectstack-i18n (807 lines, 3 files) — behavioral-claim verification, content-class execution-first

3 participants

@huangyiirene@os-zhuang@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Correct 17 false behavioral claims in skills/objectstack-i18n — sweep flight ⑧ by huangyiirene · Pull Request #13833 · objectstack-ai/objectstack · GitHub
Skip to content

Correct 17 false behavioral claims in skills/objectstack-i18n — sweep flight ⑧ - #13833

Merged
os-zhuang merged 2 commits into
mainfrom
claude/issue-13815-skills-sweep-i18n
Aug 31, 2026
Merged

Correct 17 false behavioral claims in skills/objectstack-i18n — sweep flight ⑧#13833
os-zhuang merged 2 commits into
mainfrom
claude/issue-13815-skills-sweep-i18n

Conversation

@huangyiirene

Copy link
Copy Markdown
Collaborator

Fixes#13815
Part of #13658

Flight ⑧ of the published-skills factual sweep: skills/objectstack-i18n/** (3 files, 807 lines at branch point). Every claim was settled against the implementing code plus an executed probe — never against another document. 17 distinct false facts across 20 landing sites; net −8 lines, −2 tokens (SKILL.md 6337/6338, evals/README.md 410/411 — both shrink, no ceiling touched).

references/_index.md is generator-owned and was not hand-edited; check:skill-refs is green against it.

Where the truth was read

Fact classImplementing code
bundle / item / config shapespackages/spec/src/system/translation.zod.ts
service contractpackages/spec/src/contracts/i18n-service.ts
shipped adapterspackages/services/service-i18n/src/{file-i18n-adapter,i18n-service-plugin}.ts · packages/core/src/fallbacks/memory-i18n.ts
authored-item syncpackages/core/src/fallbacks/authored-translation-sync.ts
CLI coverage / extractpackages/cli/src/commands/i18n/{check,extract}.ts · packages/cli/src/utils/i18n-{coverage,extract}.ts
orphan-key lintpackages/lint/src/validate-translation-references.ts
shipped examplesexamples/app-crm/src/translations/ · examples/app-todo/src/translations/

Per-item corrections

#落点beforeafter
1SKILL.md · Object-Level table"Object-level text (label is required)""Object-level text (every key optional)" — label: z.string().optional(), with a schema comment arguing partial translation is the normal state
2SKILL.md · Object-Level tableno _tabs rowadded _tabs.{tab_name} — a live authorable surface (resolveTabLabel), extracted and coverage-gated
3SKILL.md · Object-Level table_actions holds label, confirmText, successMessage, params, resultDialogdescription added — declared on the action translation shape
4SKILL.md · Object-Level table_sections holds "Form section / tab label""Form section label" — tabs are their own group, now row 2 above
5SKILL.md · "Top-level groups alongside objects"apps, messages, globalActions, dashboards, settings, metadataForms, settingsCommonpages and flows added — 10 groups on the shape, not 8
6SKILL.md · Core Concepts 1same list minus settingsCommon, and object content omits tabsboth lists brought to the shape's real membership
7SKILL.md · Authoring at Runtime"skipped by the runtime sync — a silent skip … rather than inferred from the item name"the sync falls back to a BCP-47-looking item name, then skips with an [i18n] … — skippedwarning naming the row. Not silent
8SKILL.md · "Retired: the o.* dialect""rejected at save time with a message naming the group to use instead""both doors now reject it — files included". 4 of the 10 keys are told they have no home (reports, notifications, errors, namespace), so "naming the group to use instead" was false for them
9SKILL.md · Pitfall "The Retired o.* Shape""Files registered in that shape resolve to nothing; runtime items … rejected at save time"both doors reject: defineTranslationBundlethrows on a file bundle. The file door was closed at the same time as the item door
10SKILL.md · os i18n check"reports missing object/field/option/view/action keys"every surface the extractor walks — 14 source kinds live, 5 were named
11SKILL.md · Extract skeletons"writes {locale}.objects.generated.ts … Other flags: --default-locale, --filter, --dry-run, --json"the {locale}.metadata-forms.generated.ts companion is written by default; four more flags exist (--no-merge, --no-objects-only, --metadata-forms, --source-hashes), so the list now points at --help instead of claiming to be complete
12SKILL.md · "Use both gates""Renaming a label, adding an object, or removing a spec key leaves coverage at 100%"adding an object lowers coverage — its keys join the expected set. Dropped from the trio
13SKILL.md · II18nService methodsgetLocales() / getDefaultLocale() / setDefaultLocale()setSupportedLocales() added — on the contract and implemented by both shipped adapters
14SKILL.md · II18nService optional methods"getCoverage, suggestTranslations — no shipped implementation provides"getFieldLabels added — same class exactly: declared optional, probed by both serving surfaces, implemented by no shipped provider
15SKILL.md · Diff & Coverage SchemasTranslationDiffItem = key, status, locale, sourceHash, AI fieldsoptional objectName added
16SKILL.md · orphan-key lint"object, field, view, action, param, section, app, nav item, dashboard or widget"flow screens added — the rule walks flows.{name}.screens.{node} too
17SKILL.md · Authoring Translation Bundles"mirrors the shipped example apps ({en,zh-CN}.ts + index.ts)"that is examples/app-todo alone, and it ships three locales
18SKILL.md · CRM I18n Blueprint"Bundle entry: src/translations/index.ts … Locale files: {en,zh-CN,ja-JP,es-ES}.ts"examples/app-crm has one file, crm.translation.ts, holding en + zh-CN. No index.ts, no per-locale files, no ja-JP/es-ES
19SKILL.md · CRM table"per-locale source files by convention" · "imports per-locale files" · objects.account.fields.*the CRM example does none of these; its object is crm_account
20SKILL.md · Pitfall "Ignoring Coverage Reports""Stale translations can cause confusion. Always run os i18n check"coverage cannot see staleness — this document's own extract --check section says so. Now points at the gate that can
21evals/README.md · rubric"runtime objects.* vs secondaryo.* format""retired o.* is rejected" — a grader taught the retired dialect is a live secondary format fails correct answers
22evals/README.md · rubric"ICU is experimental""no ICU engine" — the messageFormat knob was removed and nothing evaluates ICU strings

Rows 4, 6, 19 are the second landing sites of facts 2, 5 and 18; 17 distinct facts, 20 sites, plus 2 rubric rows.

Executed evidence

Two probe scripts (temporary, removed before commit — this diff is 2 markdown files). Built first: @objectstack/service-i18n..., @objectstack/lint..., @objectstack/platform-objects... (exit 0 each), so every read is against rebuilt dist, not stale declarations.

Schema/adapter probe, run from packages/services/service-i18n:

=== TranslationDataSchema top-level groups ===
["objects","apps","messages","globalActions","dashboards","pages","flows","settings","metadataForms","settingsCommon"]
=== ObjectTranslationDataSchema sub-keys ===
["label","pluralLabel","description","fields","_views","_actions","_sections","_tabs"]
=== object _actions sub-keys ===
["label","description","confirmText","successMessage","params","resultDialog"]
=== is objects.OBJ.label REQUIRED? ===
parse { objects: { task: { pluralLabel } } } (no label) -> success=true
=== retired o.* dialect ===
item.o: rejected=true :: `o` is the retired object-first dialect … use 'objects.OBJECT_NAME'
item.reports: rejected=true :: `reports` … reports have no translation group, omit them
bundle-door o: rejected=true
defineTranslationBundle({ en: { o: … } }) -> threw
=== interpolation ===
double: Welcome, Alice! single: Hi, {userName}! icu: messages.icu (key echoed)
=== contract methods on both shipped adapters ===
setSupportedLocales file=true memory=true
getFieldLabels file=false memory=false
getCoverage file=false memory=false
suggestTranslations file=false memory=false

CLI probe (tsx, packages/cli), driving the real walker and coverage detector:

=== ExpectedEntry.source kinds the walker emits ===
action 7 · app 1 · dashboard 1 · field 6 · flow 2 · globalAction 4 ·
metadataFormField 948 · metadataFormSection 150 · metadataType 54 ·
navigation 1 · object 3 · option 1 · page 1 · view 1 · widget 1
=== _tabs IS harvested ===
objects.task._tabs.urgent.label [source=view]
flows.onboard.screens.welcome.title [source=flow]
=== os i18n check reported source kinds ===
action, app, dashboard, field, globalAction, metadataForm, navigation,
object, option, page, view, widget (12 kinds from one small fixture)
=== --strict promotes non-default gaps ===
lax errors=0 warnings=783
strict errors=783 warnings=0

The non-vacuity control is satisfied many times over: facts 1, 2, 3, 5, 8, 9, 10, 13, 14 were each decided by a run, not a read.

Gates — all run at 5d16fd477 (the final commit)

Families derived from the real diff with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (exit 0; 14 families, re-derived unchanged on the final commit), plus the skill-specific gates the derivation scores silent because they compute their own population:

gateexit
check-ci-filter-parity · check-cross-package-test-inputs · check-shard-attestation0 · 0 · 0
check-skills-token-ratchet0 — SKILL.md 6337/6338 (−1), evals/README.md 410/411 (−1)
check:doc-formula-expressions · check:agent-test-spelling · check:corpus-claim-drift0 · 0 · 0
check:cross-package-test-inputs · check:doc-authoring · check:pm-governed-merges0 · 0 · 0
check:role-word · check:skill-compatibility · check:skill-frame-sync0 · 0 · 0
check:nul-bytes · check:pm-skill-ratchet · check:pm-skill-id-lint · check:skill-frame-freshness0 · 0 · 0 · 0
@objectstack/spec check:skill-examples0 — 260 marked blocks across 101 files, population non-empty (this package contributes 4 os:check fences)
@objectstack/spec check:skill-refs · check:skill-docs0 · 0
pnpm lint (repo-wide eslint . --no-inline-config)0
check-test-completeness3 — NOT MEASURED. The gate grades a saved turbo run test log and none exists locally; its own text says exit 3 "is not a red, and there is nothing here to fix"

ESLint was run whole rather than narrowed, and separately measured: both changed files report File ignored because no matching configuration was supplied — markdown is outside the linted population entirely (no files block in eslint.config.mjs names .md).

Pure skills/** diff, nothing published from any package — skip-changeset applies, matching flights ③/④/⑤ which landed the same shape with no changeset.

Governed surface

Published skills/**: this PR stays draft and is for the maintainer to merge. needs:contract-review is attached to this PR and to card #13815 in the same stroke (批 #12 clause ② CONTENT limb) and is never self-cleared.

Generated by Claude Code


Generated by Claude Code

…implementation
Flight 8 of the published-skills factual sweep (#13658). Every correction is
settled against the implementing code plus an executed probe; net -1 line.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EnE7G31tqbxN1rqpQmzurT
…en ratchet
The corrections in the previous commit were factually right but grew SKILL.md
by 124 tokens against a ceiling that only ever shrinks. Same facts, fewer
bytes: enumerations point at the authority instead of transcribing it, and
duplicated prose around the retired o.* dialect is stated once.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EnE7G31tqbxN1rqpQmzurT
@huangyiireneClaude

Copy link
Copy Markdown
CollaboratorAuthor

Contract review — PASS at head 5d16fd477

Applicability: clause-② CONTENT limb (批 #12). Both carriers attached at PR creation, delayed read-backs clean; cleared in this stroke.

Reviewer qualification, machine-read this sitting: get_sessionexternal_metadata.last_served_model = claude-fable-5 = CONTRACT_REVIEW_TIER.

Review: report + diff read; anchors independently re-measured on origin/main this hour —

  • _tabs is a live, gated slot: ObjectTranslationDataSchema declares it, packages/cli/src/utils/i18n-extract.ts:590–611 emits objects.<o>._tabs.<tab>.label for every rendered preset tab, and resolveTabLabel consumes it — the missing table row hid shipped capability;
  • pages is harvested by the same extractor (:563) — the top-level group list was under-enumerating;
  • setSupportedLocales is in the contract (packages/spec/src/contracts/i18n-service.ts:97) and implemented on BOTH shipped adapters (file adapter + packages/core/src/fallbacks/memory-i18n.ts) — the method-list omission was false;
  • The dev's parse probe disproving "label is required" ({objects:{task:{pluralLabel}}} parses green) and the LEGACY_OBJECT_FIRST_KEYS double-door rejection are executed evidence in both error directions, with the non-vacuity control satisfied many times over.

Program-significant: 8.5%/10% density — the highest measured in eight flights, and the dev's sharper class naming ("an enumeration that stopped growing when the schema did", 15 of 20 sites) supersedes the table-shape heuristic; recorded on the anchor. Out-of-scope findings verified real: #13835 (lint _tabs orphan leg missing, the accepted #11608 shape one group over) and #13837 (CLI --help under-count — the #13809 spec-twin pattern applied to a CLI surface). Budget: net −8 lines / −2 tokens, both files shrink, no ceiling touched; generator-owned index untouched, check:skill-refs green; whole-repo pnpm lint run un-narrowed, exit 0.

needs:contract-review cleared on BOTH carriers. Governed .md content: PR remains DRAFT for the maintainer's merge (os-zhuang / hotlong requested).


Generated by Claude Code

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

Labels

documentationImprovements or additions to documentationsize/sskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

skills-sweep ⑧: objectstack-i18n (807 lines, 3 files) — behavioral-claim verification, content-class execution-first

3 participants

@huangyiirene@os-zhuang@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Correct 17 false behavioral claims in skills/objectstack-i18n — sweep flight ⑧ by huangyiirene · Pull Request #13833 · objectstack-ai/objectstack · GitHub
Skip to content

Correct 17 false behavioral claims in skills/objectstack-i18n — sweep flight ⑧ - #13833

Merged
os-zhuang merged 2 commits into
mainfrom
claude/issue-13815-skills-sweep-i18n
Aug 31, 2026
Merged

Correct 17 false behavioral claims in skills/objectstack-i18n — sweep flight ⑧#13833
os-zhuang merged 2 commits into
mainfrom
claude/issue-13815-skills-sweep-i18n

Conversation

@huangyiirene

Copy link
Copy Markdown
Collaborator

Fixes#13815
Part of #13658

Flight ⑧ of the published-skills factual sweep: skills/objectstack-i18n/** (3 files, 807 lines at branch point). Every claim was settled against the implementing code plus an executed probe — never against another document. 17 distinct false facts across 20 landing sites; net −8 lines, −2 tokens (SKILL.md 6337/6338, evals/README.md 410/411 — both shrink, no ceiling touched).

references/_index.md is generator-owned and was not hand-edited; check:skill-refs is green against it.

Where the truth was read

Fact classImplementing code
bundle / item / config shapespackages/spec/src/system/translation.zod.ts
service contractpackages/spec/src/contracts/i18n-service.ts
shipped adapterspackages/services/service-i18n/src/{file-i18n-adapter,i18n-service-plugin}.ts · packages/core/src/fallbacks/memory-i18n.ts
authored-item syncpackages/core/src/fallbacks/authored-translation-sync.ts
CLI coverage / extractpackages/cli/src/commands/i18n/{check,extract}.ts · packages/cli/src/utils/i18n-{coverage,extract}.ts
orphan-key lintpackages/lint/src/validate-translation-references.ts
shipped examplesexamples/app-crm/src/translations/ · examples/app-todo/src/translations/

Per-item corrections

#落点beforeafter
1SKILL.md · Object-Level table"Object-level text (label is required)""Object-level text (every key optional)" — label: z.string().optional(), with a schema comment arguing partial translation is the normal state
2SKILL.md · Object-Level tableno _tabs rowadded _tabs.{tab_name} — a live authorable surface (resolveTabLabel), extracted and coverage-gated
3SKILL.md · Object-Level table_actions holds label, confirmText, successMessage, params, resultDialogdescription added — declared on the action translation shape
4SKILL.md · Object-Level table_sections holds "Form section / tab label""Form section label" — tabs are their own group, now row 2 above
5SKILL.md · "Top-level groups alongside objects"apps, messages, globalActions, dashboards, settings, metadataForms, settingsCommonpages and flows added — 10 groups on the shape, not 8
6SKILL.md · Core Concepts 1same list minus settingsCommon, and object content omits tabsboth lists brought to the shape's real membership
7SKILL.md · Authoring at Runtime"skipped by the runtime sync — a silent skip … rather than inferred from the item name"the sync falls back to a BCP-47-looking item name, then skips with an [i18n] … — skippedwarning naming the row. Not silent
8SKILL.md · "Retired: the o.* dialect""rejected at save time with a message naming the group to use instead""both doors now reject it — files included". 4 of the 10 keys are told they have no home (reports, notifications, errors, namespace), so "naming the group to use instead" was false for them
9SKILL.md · Pitfall "The Retired o.* Shape""Files registered in that shape resolve to nothing; runtime items … rejected at save time"both doors reject: defineTranslationBundlethrows on a file bundle. The file door was closed at the same time as the item door
10SKILL.md · os i18n check"reports missing object/field/option/view/action keys"every surface the extractor walks — 14 source kinds live, 5 were named
11SKILL.md · Extract skeletons"writes {locale}.objects.generated.ts … Other flags: --default-locale, --filter, --dry-run, --json"the {locale}.metadata-forms.generated.ts companion is written by default; four more flags exist (--no-merge, --no-objects-only, --metadata-forms, --source-hashes), so the list now points at --help instead of claiming to be complete
12SKILL.md · "Use both gates""Renaming a label, adding an object, or removing a spec key leaves coverage at 100%"adding an object lowers coverage — its keys join the expected set. Dropped from the trio
13SKILL.md · II18nService methodsgetLocales() / getDefaultLocale() / setDefaultLocale()setSupportedLocales() added — on the contract and implemented by both shipped adapters
14SKILL.md · II18nService optional methods"getCoverage, suggestTranslations — no shipped implementation provides"getFieldLabels added — same class exactly: declared optional, probed by both serving surfaces, implemented by no shipped provider
15SKILL.md · Diff & Coverage SchemasTranslationDiffItem = key, status, locale, sourceHash, AI fieldsoptional objectName added
16SKILL.md · orphan-key lint"object, field, view, action, param, section, app, nav item, dashboard or widget"flow screens added — the rule walks flows.{name}.screens.{node} too
17SKILL.md · Authoring Translation Bundles"mirrors the shipped example apps ({en,zh-CN}.ts + index.ts)"that is examples/app-todo alone, and it ships three locales
18SKILL.md · CRM I18n Blueprint"Bundle entry: src/translations/index.ts … Locale files: {en,zh-CN,ja-JP,es-ES}.ts"examples/app-crm has one file, crm.translation.ts, holding en + zh-CN. No index.ts, no per-locale files, no ja-JP/es-ES
19SKILL.md · CRM table"per-locale source files by convention" · "imports per-locale files" · objects.account.fields.*the CRM example does none of these; its object is crm_account
20SKILL.md · Pitfall "Ignoring Coverage Reports""Stale translations can cause confusion. Always run os i18n check"coverage cannot see staleness — this document's own extract --check section says so. Now points at the gate that can
21evals/README.md · rubric"runtime objects.* vs secondaryo.* format""retired o.* is rejected" — a grader taught the retired dialect is a live secondary format fails correct answers
22evals/README.md · rubric"ICU is experimental""no ICU engine" — the messageFormat knob was removed and nothing evaluates ICU strings

Rows 4, 6, 19 are the second landing sites of facts 2, 5 and 18; 17 distinct facts, 20 sites, plus 2 rubric rows.

Executed evidence

Two probe scripts (temporary, removed before commit — this diff is 2 markdown files). Built first: @objectstack/service-i18n..., @objectstack/lint..., @objectstack/platform-objects... (exit 0 each), so every read is against rebuilt dist, not stale declarations.

Schema/adapter probe, run from packages/services/service-i18n:

=== TranslationDataSchema top-level groups ===
["objects","apps","messages","globalActions","dashboards","pages","flows","settings","metadataForms","settingsCommon"]
=== ObjectTranslationDataSchema sub-keys ===
["label","pluralLabel","description","fields","_views","_actions","_sections","_tabs"]
=== object _actions sub-keys ===
["label","description","confirmText","successMessage","params","resultDialog"]
=== is objects.OBJ.label REQUIRED? ===
parse { objects: { task: { pluralLabel } } } (no label) -> success=true
=== retired o.* dialect ===
item.o: rejected=true :: `o` is the retired object-first dialect … use 'objects.OBJECT_NAME'
item.reports: rejected=true :: `reports` … reports have no translation group, omit them
bundle-door o: rejected=true
defineTranslationBundle({ en: { o: … } }) -> threw
=== interpolation ===
double: Welcome, Alice! single: Hi, {userName}! icu: messages.icu (key echoed)
=== contract methods on both shipped adapters ===
setSupportedLocales file=true memory=true
getFieldLabels file=false memory=false
getCoverage file=false memory=false
suggestTranslations file=false memory=false

CLI probe (tsx, packages/cli), driving the real walker and coverage detector:

=== ExpectedEntry.source kinds the walker emits ===
action 7 · app 1 · dashboard 1 · field 6 · flow 2 · globalAction 4 ·
metadataFormField 948 · metadataFormSection 150 · metadataType 54 ·
navigation 1 · object 3 · option 1 · page 1 · view 1 · widget 1
=== _tabs IS harvested ===
objects.task._tabs.urgent.label [source=view]
flows.onboard.screens.welcome.title [source=flow]
=== os i18n check reported source kinds ===
action, app, dashboard, field, globalAction, metadataForm, navigation,
object, option, page, view, widget (12 kinds from one small fixture)
=== --strict promotes non-default gaps ===
lax errors=0 warnings=783
strict errors=783 warnings=0

The non-vacuity control is satisfied many times over: facts 1, 2, 3, 5, 8, 9, 10, 13, 14 were each decided by a run, not a read.

Gates — all run at 5d16fd477 (the final commit)

Families derived from the real diff with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (exit 0; 14 families, re-derived unchanged on the final commit), plus the skill-specific gates the derivation scores silent because they compute their own population:

gateexit
check-ci-filter-parity · check-cross-package-test-inputs · check-shard-attestation0 · 0 · 0
check-skills-token-ratchet0 — SKILL.md 6337/6338 (−1), evals/README.md 410/411 (−1)
check:doc-formula-expressions · check:agent-test-spelling · check:corpus-claim-drift0 · 0 · 0
check:cross-package-test-inputs · check:doc-authoring · check:pm-governed-merges0 · 0 · 0
check:role-word · check:skill-compatibility · check:skill-frame-sync0 · 0 · 0
check:nul-bytes · check:pm-skill-ratchet · check:pm-skill-id-lint · check:skill-frame-freshness0 · 0 · 0 · 0
@objectstack/spec check:skill-examples0 — 260 marked blocks across 101 files, population non-empty (this package contributes 4 os:check fences)
@objectstack/spec check:skill-refs · check:skill-docs0 · 0
pnpm lint (repo-wide eslint . --no-inline-config)0
check-test-completeness3 — NOT MEASURED. The gate grades a saved turbo run test log and none exists locally; its own text says exit 3 "is not a red, and there is nothing here to fix"

ESLint was run whole rather than narrowed, and separately measured: both changed files report File ignored because no matching configuration was supplied — markdown is outside the linted population entirely (no files block in eslint.config.mjs names .md).

Pure skills/** diff, nothing published from any package — skip-changeset applies, matching flights ③/④/⑤ which landed the same shape with no changeset.

Governed surface

Published skills/**: this PR stays draft and is for the maintainer to merge. needs:contract-review is attached to this PR and to card #13815 in the same stroke (批 #12 clause ② CONTENT limb) and is never self-cleared.

Generated by Claude Code


Generated by Claude Code

…implementation
Flight 8 of the published-skills factual sweep (#13658). Every correction is
settled against the implementing code plus an executed probe; net -1 line.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EnE7G31tqbxN1rqpQmzurT
…en ratchet
The corrections in the previous commit were factually right but grew SKILL.md
by 124 tokens against a ceiling that only ever shrinks. Same facts, fewer
bytes: enumerations point at the authority instead of transcribing it, and
duplicated prose around the retired o.* dialect is stated once.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EnE7G31tqbxN1rqpQmzurT
@huangyiireneClaude

Copy link
Copy Markdown
CollaboratorAuthor

Contract review — PASS at head 5d16fd477

Applicability: clause-② CONTENT limb (批 #12). Both carriers attached at PR creation, delayed read-backs clean; cleared in this stroke.

Reviewer qualification, machine-read this sitting: get_sessionexternal_metadata.last_served_model = claude-fable-5 = CONTRACT_REVIEW_TIER.

Review: report + diff read; anchors independently re-measured on origin/main this hour —

  • _tabs is a live, gated slot: ObjectTranslationDataSchema declares it, packages/cli/src/utils/i18n-extract.ts:590–611 emits objects.<o>._tabs.<tab>.label for every rendered preset tab, and resolveTabLabel consumes it — the missing table row hid shipped capability;
  • pages is harvested by the same extractor (:563) — the top-level group list was under-enumerating;
  • setSupportedLocales is in the contract (packages/spec/src/contracts/i18n-service.ts:97) and implemented on BOTH shipped adapters (file adapter + packages/core/src/fallbacks/memory-i18n.ts) — the method-list omission was false;
  • The dev's parse probe disproving "label is required" ({objects:{task:{pluralLabel}}} parses green) and the LEGACY_OBJECT_FIRST_KEYS double-door rejection are executed evidence in both error directions, with the non-vacuity control satisfied many times over.

Program-significant: 8.5%/10% density — the highest measured in eight flights, and the dev's sharper class naming ("an enumeration that stopped growing when the schema did", 15 of 20 sites) supersedes the table-shape heuristic; recorded on the anchor. Out-of-scope findings verified real: #13835 (lint _tabs orphan leg missing, the accepted #11608 shape one group over) and #13837 (CLI --help under-count — the #13809 spec-twin pattern applied to a CLI surface). Budget: net −8 lines / −2 tokens, both files shrink, no ceiling touched; generator-owned index untouched, check:skill-refs green; whole-repo pnpm lint run un-narrowed, exit 0.

needs:contract-review cleared on BOTH carriers. Governed .md content: PR remains DRAFT for the maintainer's merge (os-zhuang / hotlong requested).


Generated by Claude Code

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

Labels

documentationImprovements or additions to documentationsize/sskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

skills-sweep ⑧: objectstack-i18n (807 lines, 3 files) — behavioral-claim verification, content-class execution-first

3 participants

@huangyiirene@os-zhuang@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Correct 17 false behavioral claims in skills/objectstack-i18n — sweep flight ⑧ by huangyiirene · Pull Request #13833 · objectstack-ai/objectstack · GitHub
Skip to content

Correct 17 false behavioral claims in skills/objectstack-i18n — sweep flight ⑧ - #13833

Merged
os-zhuang merged 2 commits into
mainfrom
claude/issue-13815-skills-sweep-i18n
Aug 31, 2026
Merged

Correct 17 false behavioral claims in skills/objectstack-i18n — sweep flight ⑧#13833
os-zhuang merged 2 commits into
mainfrom
claude/issue-13815-skills-sweep-i18n

Conversation

@huangyiirene

Copy link
Copy Markdown
Collaborator

Fixes#13815
Part of #13658

Flight ⑧ of the published-skills factual sweep: skills/objectstack-i18n/** (3 files, 807 lines at branch point). Every claim was settled against the implementing code plus an executed probe — never against another document. 17 distinct false facts across 20 landing sites; net −8 lines, −2 tokens (SKILL.md 6337/6338, evals/README.md 410/411 — both shrink, no ceiling touched).

references/_index.md is generator-owned and was not hand-edited; check:skill-refs is green against it.

Where the truth was read

Fact classImplementing code
bundle / item / config shapespackages/spec/src/system/translation.zod.ts
service contractpackages/spec/src/contracts/i18n-service.ts
shipped adapterspackages/services/service-i18n/src/{file-i18n-adapter,i18n-service-plugin}.ts · packages/core/src/fallbacks/memory-i18n.ts
authored-item syncpackages/core/src/fallbacks/authored-translation-sync.ts
CLI coverage / extractpackages/cli/src/commands/i18n/{check,extract}.ts · packages/cli/src/utils/i18n-{coverage,extract}.ts
orphan-key lintpackages/lint/src/validate-translation-references.ts
shipped examplesexamples/app-crm/src/translations/ · examples/app-todo/src/translations/

Per-item corrections

#落点beforeafter
1SKILL.md · Object-Level table"Object-level text (label is required)""Object-level text (every key optional)" — label: z.string().optional(), with a schema comment arguing partial translation is the normal state
2SKILL.md · Object-Level tableno _tabs rowadded _tabs.{tab_name} — a live authorable surface (resolveTabLabel), extracted and coverage-gated
3SKILL.md · Object-Level table_actions holds label, confirmText, successMessage, params, resultDialogdescription added — declared on the action translation shape
4SKILL.md · Object-Level table_sections holds "Form section / tab label""Form section label" — tabs are their own group, now row 2 above
5SKILL.md · "Top-level groups alongside objects"apps, messages, globalActions, dashboards, settings, metadataForms, settingsCommonpages and flows added — 10 groups on the shape, not 8
6SKILL.md · Core Concepts 1same list minus settingsCommon, and object content omits tabsboth lists brought to the shape's real membership
7SKILL.md · Authoring at Runtime"skipped by the runtime sync — a silent skip … rather than inferred from the item name"the sync falls back to a BCP-47-looking item name, then skips with an [i18n] … — skippedwarning naming the row. Not silent
8SKILL.md · "Retired: the o.* dialect""rejected at save time with a message naming the group to use instead""both doors now reject it — files included". 4 of the 10 keys are told they have no home (reports, notifications, errors, namespace), so "naming the group to use instead" was false for them
9SKILL.md · Pitfall "The Retired o.* Shape""Files registered in that shape resolve to nothing; runtime items … rejected at save time"both doors reject: defineTranslationBundlethrows on a file bundle. The file door was closed at the same time as the item door
10SKILL.md · os i18n check"reports missing object/field/option/view/action keys"every surface the extractor walks — 14 source kinds live, 5 were named
11SKILL.md · Extract skeletons"writes {locale}.objects.generated.ts … Other flags: --default-locale, --filter, --dry-run, --json"the {locale}.metadata-forms.generated.ts companion is written by default; four more flags exist (--no-merge, --no-objects-only, --metadata-forms, --source-hashes), so the list now points at --help instead of claiming to be complete
12SKILL.md · "Use both gates""Renaming a label, adding an object, or removing a spec key leaves coverage at 100%"adding an object lowers coverage — its keys join the expected set. Dropped from the trio
13SKILL.md · II18nService methodsgetLocales() / getDefaultLocale() / setDefaultLocale()setSupportedLocales() added — on the contract and implemented by both shipped adapters
14SKILL.md · II18nService optional methods"getCoverage, suggestTranslations — no shipped implementation provides"getFieldLabels added — same class exactly: declared optional, probed by both serving surfaces, implemented by no shipped provider
15SKILL.md · Diff & Coverage SchemasTranslationDiffItem = key, status, locale, sourceHash, AI fieldsoptional objectName added
16SKILL.md · orphan-key lint"object, field, view, action, param, section, app, nav item, dashboard or widget"flow screens added — the rule walks flows.{name}.screens.{node} too
17SKILL.md · Authoring Translation Bundles"mirrors the shipped example apps ({en,zh-CN}.ts + index.ts)"that is examples/app-todo alone, and it ships three locales
18SKILL.md · CRM I18n Blueprint"Bundle entry: src/translations/index.ts … Locale files: {en,zh-CN,ja-JP,es-ES}.ts"examples/app-crm has one file, crm.translation.ts, holding en + zh-CN. No index.ts, no per-locale files, no ja-JP/es-ES
19SKILL.md · CRM table"per-locale source files by convention" · "imports per-locale files" · objects.account.fields.*the CRM example does none of these; its object is crm_account
20SKILL.md · Pitfall "Ignoring Coverage Reports""Stale translations can cause confusion. Always run os i18n check"coverage cannot see staleness — this document's own extract --check section says so. Now points at the gate that can
21evals/README.md · rubric"runtime objects.* vs secondaryo.* format""retired o.* is rejected" — a grader taught the retired dialect is a live secondary format fails correct answers
22evals/README.md · rubric"ICU is experimental""no ICU engine" — the messageFormat knob was removed and nothing evaluates ICU strings

Rows 4, 6, 19 are the second landing sites of facts 2, 5 and 18; 17 distinct facts, 20 sites, plus 2 rubric rows.

Executed evidence

Two probe scripts (temporary, removed before commit — this diff is 2 markdown files). Built first: @objectstack/service-i18n..., @objectstack/lint..., @objectstack/platform-objects... (exit 0 each), so every read is against rebuilt dist, not stale declarations.

Schema/adapter probe, run from packages/services/service-i18n:

=== TranslationDataSchema top-level groups ===
["objects","apps","messages","globalActions","dashboards","pages","flows","settings","metadataForms","settingsCommon"]
=== ObjectTranslationDataSchema sub-keys ===
["label","pluralLabel","description","fields","_views","_actions","_sections","_tabs"]
=== object _actions sub-keys ===
["label","description","confirmText","successMessage","params","resultDialog"]
=== is objects.OBJ.label REQUIRED? ===
parse { objects: { task: { pluralLabel } } } (no label) -> success=true
=== retired o.* dialect ===
item.o: rejected=true :: `o` is the retired object-first dialect … use 'objects.OBJECT_NAME'
item.reports: rejected=true :: `reports` … reports have no translation group, omit them
bundle-door o: rejected=true
defineTranslationBundle({ en: { o: … } }) -> threw
=== interpolation ===
double: Welcome, Alice! single: Hi, {userName}! icu: messages.icu (key echoed)
=== contract methods on both shipped adapters ===
setSupportedLocales file=true memory=true
getFieldLabels file=false memory=false
getCoverage file=false memory=false
suggestTranslations file=false memory=false

CLI probe (tsx, packages/cli), driving the real walker and coverage detector:

=== ExpectedEntry.source kinds the walker emits ===
action 7 · app 1 · dashboard 1 · field 6 · flow 2 · globalAction 4 ·
metadataFormField 948 · metadataFormSection 150 · metadataType 54 ·
navigation 1 · object 3 · option 1 · page 1 · view 1 · widget 1
=== _tabs IS harvested ===
objects.task._tabs.urgent.label [source=view]
flows.onboard.screens.welcome.title [source=flow]
=== os i18n check reported source kinds ===
action, app, dashboard, field, globalAction, metadataForm, navigation,
object, option, page, view, widget (12 kinds from one small fixture)
=== --strict promotes non-default gaps ===
lax errors=0 warnings=783
strict errors=783 warnings=0

The non-vacuity control is satisfied many times over: facts 1, 2, 3, 5, 8, 9, 10, 13, 14 were each decided by a run, not a read.

Gates — all run at 5d16fd477 (the final commit)

Families derived from the real diff with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (exit 0; 14 families, re-derived unchanged on the final commit), plus the skill-specific gates the derivation scores silent because they compute their own population:

gateexit
check-ci-filter-parity · check-cross-package-test-inputs · check-shard-attestation0 · 0 · 0
check-skills-token-ratchet0 — SKILL.md 6337/6338 (−1), evals/README.md 410/411 (−1)
check:doc-formula-expressions · check:agent-test-spelling · check:corpus-claim-drift0 · 0 · 0
check:cross-package-test-inputs · check:doc-authoring · check:pm-governed-merges0 · 0 · 0
check:role-word · check:skill-compatibility · check:skill-frame-sync0 · 0 · 0
check:nul-bytes · check:pm-skill-ratchet · check:pm-skill-id-lint · check:skill-frame-freshness0 · 0 · 0 · 0
@objectstack/spec check:skill-examples0 — 260 marked blocks across 101 files, population non-empty (this package contributes 4 os:check fences)
@objectstack/spec check:skill-refs · check:skill-docs0 · 0
pnpm lint (repo-wide eslint . --no-inline-config)0
check-test-completeness3 — NOT MEASURED. The gate grades a saved turbo run test log and none exists locally; its own text says exit 3 "is not a red, and there is nothing here to fix"

ESLint was run whole rather than narrowed, and separately measured: both changed files report File ignored because no matching configuration was supplied — markdown is outside the linted population entirely (no files block in eslint.config.mjs names .md).

Pure skills/** diff, nothing published from any package — skip-changeset applies, matching flights ③/④/⑤ which landed the same shape with no changeset.

Governed surface

Published skills/**: this PR stays draft and is for the maintainer to merge. needs:contract-review is attached to this PR and to card #13815 in the same stroke (批 #12 clause ② CONTENT limb) and is never self-cleared.

Generated by Claude Code


Generated by Claude Code

…implementation
Flight 8 of the published-skills factual sweep (#13658). Every correction is
settled against the implementing code plus an executed probe; net -1 line.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EnE7G31tqbxN1rqpQmzurT
…en ratchet
The corrections in the previous commit were factually right but grew SKILL.md
by 124 tokens against a ceiling that only ever shrinks. Same facts, fewer
bytes: enumerations point at the authority instead of transcribing it, and
duplicated prose around the retired o.* dialect is stated once.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EnE7G31tqbxN1rqpQmzurT
@huangyiireneClaude

Copy link
Copy Markdown
CollaboratorAuthor

Contract review — PASS at head 5d16fd477

Applicability: clause-② CONTENT limb (批 #12). Both carriers attached at PR creation, delayed read-backs clean; cleared in this stroke.

Reviewer qualification, machine-read this sitting: get_sessionexternal_metadata.last_served_model = claude-fable-5 = CONTRACT_REVIEW_TIER.

Review: report + diff read; anchors independently re-measured on origin/main this hour —

  • _tabs is a live, gated slot: ObjectTranslationDataSchema declares it, packages/cli/src/utils/i18n-extract.ts:590–611 emits objects.<o>._tabs.<tab>.label for every rendered preset tab, and resolveTabLabel consumes it — the missing table row hid shipped capability;
  • pages is harvested by the same extractor (:563) — the top-level group list was under-enumerating;
  • setSupportedLocales is in the contract (packages/spec/src/contracts/i18n-service.ts:97) and implemented on BOTH shipped adapters (file adapter + packages/core/src/fallbacks/memory-i18n.ts) — the method-list omission was false;
  • The dev's parse probe disproving "label is required" ({objects:{task:{pluralLabel}}} parses green) and the LEGACY_OBJECT_FIRST_KEYS double-door rejection are executed evidence in both error directions, with the non-vacuity control satisfied many times over.

Program-significant: 8.5%/10% density — the highest measured in eight flights, and the dev's sharper class naming ("an enumeration that stopped growing when the schema did", 15 of 20 sites) supersedes the table-shape heuristic; recorded on the anchor. Out-of-scope findings verified real: #13835 (lint _tabs orphan leg missing, the accepted #11608 shape one group over) and #13837 (CLI --help under-count — the #13809 spec-twin pattern applied to a CLI surface). Budget: net −8 lines / −2 tokens, both files shrink, no ceiling touched; generator-owned index untouched, check:skill-refs green; whole-repo pnpm lint run un-narrowed, exit 0.

needs:contract-review cleared on BOTH carriers. Governed .md content: PR remains DRAFT for the maintainer's merge (os-zhuang / hotlong requested).


Generated by Claude Code

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

Labels

documentationImprovements or additions to documentationsize/sskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

skills-sweep ⑧: objectstack-i18n (807 lines, 3 files) — behavioral-claim verification, content-class execution-first

3 participants

@huangyiirene@os-zhuang@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' Correct 17 false behavioral claims in skills/objectstack-i18n — sweep flight ⑧ by huangyiirene · Pull Request #13833 · objectstack-ai/objectstack · GitHub
Skip to content

Correct 17 false behavioral claims in skills/objectstack-i18n — sweep flight ⑧ - #13833

Merged
os-zhuang merged 2 commits into
mainfrom
claude/issue-13815-skills-sweep-i18n
Aug 31, 2026
Merged

Correct 17 false behavioral claims in skills/objectstack-i18n — sweep flight ⑧#13833
os-zhuang merged 2 commits into
mainfrom
claude/issue-13815-skills-sweep-i18n

Conversation

@huangyiirene

Copy link
Copy Markdown
Collaborator

Fixes#13815
Part of #13658

Flight ⑧ of the published-skills factual sweep: skills/objectstack-i18n/** (3 files, 807 lines at branch point). Every claim was settled against the implementing code plus an executed probe — never against another document. 17 distinct false facts across 20 landing sites; net −8 lines, −2 tokens (SKILL.md 6337/6338, evals/README.md 410/411 — both shrink, no ceiling touched).

references/_index.md is generator-owned and was not hand-edited; check:skill-refs is green against it.

Where the truth was read

Fact classImplementing code
bundle / item / config shapespackages/spec/src/system/translation.zod.ts
service contractpackages/spec/src/contracts/i18n-service.ts
shipped adapterspackages/services/service-i18n/src/{file-i18n-adapter,i18n-service-plugin}.ts · packages/core/src/fallbacks/memory-i18n.ts
authored-item syncpackages/core/src/fallbacks/authored-translation-sync.ts
CLI coverage / extractpackages/cli/src/commands/i18n/{check,extract}.ts · packages/cli/src/utils/i18n-{coverage,extract}.ts
orphan-key lintpackages/lint/src/validate-translation-references.ts
shipped examplesexamples/app-crm/src/translations/ · examples/app-todo/src/translations/

Per-item corrections

#落点beforeafter
1SKILL.md · Object-Level table"Object-level text (label is required)""Object-level text (every key optional)" — label: z.string().optional(), with a schema comment arguing partial translation is the normal state
2SKILL.md · Object-Level tableno _tabs rowadded _tabs.{tab_name} — a live authorable surface (resolveTabLabel), extracted and coverage-gated
3SKILL.md · Object-Level table_actions holds label, confirmText, successMessage, params, resultDialogdescription added — declared on the action translation shape
4SKILL.md · Object-Level table_sections holds "Form section / tab label""Form section label" — tabs are their own group, now row 2 above
5SKILL.md · "Top-level groups alongside objects"apps, messages, globalActions, dashboards, settings, metadataForms, settingsCommonpages and flows added — 10 groups on the shape, not 8
6SKILL.md · Core Concepts 1same list minus settingsCommon, and object content omits tabsboth lists brought to the shape's real membership
7SKILL.md · Authoring at Runtime"skipped by the runtime sync — a silent skip … rather than inferred from the item name"the sync falls back to a BCP-47-looking item name, then skips with an [i18n] … — skippedwarning naming the row. Not silent
8SKILL.md · "Retired: the o.* dialect""rejected at save time with a message naming the group to use instead""both doors now reject it — files included". 4 of the 10 keys are told they have no home (reports, notifications, errors, namespace), so "naming the group to use instead" was false for them
9SKILL.md · Pitfall "The Retired o.* Shape""Files registered in that shape resolve to nothing; runtime items … rejected at save time"both doors reject: defineTranslationBundlethrows on a file bundle. The file door was closed at the same time as the item door
10SKILL.md · os i18n check"reports missing object/field/option/view/action keys"every surface the extractor walks — 14 source kinds live, 5 were named
11SKILL.md · Extract skeletons"writes {locale}.objects.generated.ts … Other flags: --default-locale, --filter, --dry-run, --json"the {locale}.metadata-forms.generated.ts companion is written by default; four more flags exist (--no-merge, --no-objects-only, --metadata-forms, --source-hashes), so the list now points at --help instead of claiming to be complete
12SKILL.md · "Use both gates""Renaming a label, adding an object, or removing a spec key leaves coverage at 100%"adding an object lowers coverage — its keys join the expected set. Dropped from the trio
13SKILL.md · II18nService methodsgetLocales() / getDefaultLocale() / setDefaultLocale()setSupportedLocales() added — on the contract and implemented by both shipped adapters
14SKILL.md · II18nService optional methods"getCoverage, suggestTranslations — no shipped implementation provides"getFieldLabels added — same class exactly: declared optional, probed by both serving surfaces, implemented by no shipped provider
15SKILL.md · Diff & Coverage SchemasTranslationDiffItem = key, status, locale, sourceHash, AI fieldsoptional objectName added
16SKILL.md · orphan-key lint"object, field, view, action, param, section, app, nav item, dashboard or widget"flow screens added — the rule walks flows.{name}.screens.{node} too
17SKILL.md · Authoring Translation Bundles"mirrors the shipped example apps ({en,zh-CN}.ts + index.ts)"that is examples/app-todo alone, and it ships three locales
18SKILL.md · CRM I18n Blueprint"Bundle entry: src/translations/index.ts … Locale files: {en,zh-CN,ja-JP,es-ES}.ts"examples/app-crm has one file, crm.translation.ts, holding en + zh-CN. No index.ts, no per-locale files, no ja-JP/es-ES
19SKILL.md · CRM table"per-locale source files by convention" · "imports per-locale files" · objects.account.fields.*the CRM example does none of these; its object is crm_account
20SKILL.md · Pitfall "Ignoring Coverage Reports""Stale translations can cause confusion. Always run os i18n check"coverage cannot see staleness — this document's own extract --check section says so. Now points at the gate that can
21evals/README.md · rubric"runtime objects.* vs secondaryo.* format""retired o.* is rejected" — a grader taught the retired dialect is a live secondary format fails correct answers
22evals/README.md · rubric"ICU is experimental""no ICU engine" — the messageFormat knob was removed and nothing evaluates ICU strings

Rows 4, 6, 19 are the second landing sites of facts 2, 5 and 18; 17 distinct facts, 20 sites, plus 2 rubric rows.

Executed evidence

Two probe scripts (temporary, removed before commit — this diff is 2 markdown files). Built first: @objectstack/service-i18n..., @objectstack/lint..., @objectstack/platform-objects... (exit 0 each), so every read is against rebuilt dist, not stale declarations.

Schema/adapter probe, run from packages/services/service-i18n:

=== TranslationDataSchema top-level groups ===
["objects","apps","messages","globalActions","dashboards","pages","flows","settings","metadataForms","settingsCommon"]
=== ObjectTranslationDataSchema sub-keys ===
["label","pluralLabel","description","fields","_views","_actions","_sections","_tabs"]
=== object _actions sub-keys ===
["label","description","confirmText","successMessage","params","resultDialog"]
=== is objects.OBJ.label REQUIRED? ===
parse { objects: { task: { pluralLabel } } } (no label) -> success=true
=== retired o.* dialect ===
item.o: rejected=true :: `o` is the retired object-first dialect … use 'objects.OBJECT_NAME'
item.reports: rejected=true :: `reports` … reports have no translation group, omit them
bundle-door o: rejected=true
defineTranslationBundle({ en: { o: … } }) -> threw
=== interpolation ===
double: Welcome, Alice! single: Hi, {userName}! icu: messages.icu (key echoed)
=== contract methods on both shipped adapters ===
setSupportedLocales file=true memory=true
getFieldLabels file=false memory=false
getCoverage file=false memory=false
suggestTranslations file=false memory=false

CLI probe (tsx, packages/cli), driving the real walker and coverage detector:

=== ExpectedEntry.source kinds the walker emits ===
action 7 · app 1 · dashboard 1 · field 6 · flow 2 · globalAction 4 ·
metadataFormField 948 · metadataFormSection 150 · metadataType 54 ·
navigation 1 · object 3 · option 1 · page 1 · view 1 · widget 1
=== _tabs IS harvested ===
objects.task._tabs.urgent.label [source=view]
flows.onboard.screens.welcome.title [source=flow]
=== os i18n check reported source kinds ===
action, app, dashboard, field, globalAction, metadataForm, navigation,
object, option, page, view, widget (12 kinds from one small fixture)
=== --strict promotes non-default gaps ===
lax errors=0 warnings=783
strict errors=783 warnings=0

The non-vacuity control is satisfied many times over: facts 1, 2, 3, 5, 8, 9, 10, 13, 14 were each decided by a run, not a read.

Gates — all run at 5d16fd477 (the final commit)

Families derived from the real diff with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (exit 0; 14 families, re-derived unchanged on the final commit), plus the skill-specific gates the derivation scores silent because they compute their own population:

gateexit
check-ci-filter-parity · check-cross-package-test-inputs · check-shard-attestation0 · 0 · 0
check-skills-token-ratchet0 — SKILL.md 6337/6338 (−1), evals/README.md 410/411 (−1)
check:doc-formula-expressions · check:agent-test-spelling · check:corpus-claim-drift0 · 0 · 0
check:cross-package-test-inputs · check:doc-authoring · check:pm-governed-merges0 · 0 · 0
check:role-word · check:skill-compatibility · check:skill-frame-sync0 · 0 · 0
check:nul-bytes · check:pm-skill-ratchet · check:pm-skill-id-lint · check:skill-frame-freshness0 · 0 · 0 · 0
@objectstack/spec check:skill-examples0 — 260 marked blocks across 101 files, population non-empty (this package contributes 4 os:check fences)
@objectstack/spec check:skill-refs · check:skill-docs0 · 0
pnpm lint (repo-wide eslint . --no-inline-config)0
check-test-completeness3 — NOT MEASURED. The gate grades a saved turbo run test log and none exists locally; its own text says exit 3 "is not a red, and there is nothing here to fix"

ESLint was run whole rather than narrowed, and separately measured: both changed files report File ignored because no matching configuration was supplied — markdown is outside the linted population entirely (no files block in eslint.config.mjs names .md).

Pure skills/** diff, nothing published from any package — skip-changeset applies, matching flights ③/④/⑤ which landed the same shape with no changeset.

Governed surface

Published skills/**: this PR stays draft and is for the maintainer to merge. needs:contract-review is attached to this PR and to card #13815 in the same stroke (批 #12 clause ② CONTENT limb) and is never self-cleared.

Generated by Claude Code


Generated by Claude Code

…implementation
Flight 8 of the published-skills factual sweep (#13658). Every correction is
settled against the implementing code plus an executed probe; net -1 line.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EnE7G31tqbxN1rqpQmzurT
…en ratchet
The corrections in the previous commit were factually right but grew SKILL.md
by 124 tokens against a ceiling that only ever shrinks. Same facts, fewer
bytes: enumerations point at the authority instead of transcribing it, and
duplicated prose around the retired o.* dialect is stated once.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EnE7G31tqbxN1rqpQmzurT
@huangyiireneClaude

Copy link
Copy Markdown
CollaboratorAuthor

Contract review — PASS at head 5d16fd477

Applicability: clause-② CONTENT limb (批 #12). Both carriers attached at PR creation, delayed read-backs clean; cleared in this stroke.

Reviewer qualification, machine-read this sitting: get_sessionexternal_metadata.last_served_model = claude-fable-5 = CONTRACT_REVIEW_TIER.

Review: report + diff read; anchors independently re-measured on origin/main this hour —

  • _tabs is a live, gated slot: ObjectTranslationDataSchema declares it, packages/cli/src/utils/i18n-extract.ts:590–611 emits objects.<o>._tabs.<tab>.label for every rendered preset tab, and resolveTabLabel consumes it — the missing table row hid shipped capability;
  • pages is harvested by the same extractor (:563) — the top-level group list was under-enumerating;
  • setSupportedLocales is in the contract (packages/spec/src/contracts/i18n-service.ts:97) and implemented on BOTH shipped adapters (file adapter + packages/core/src/fallbacks/memory-i18n.ts) — the method-list omission was false;
  • The dev's parse probe disproving "label is required" ({objects:{task:{pluralLabel}}} parses green) and the LEGACY_OBJECT_FIRST_KEYS double-door rejection are executed evidence in both error directions, with the non-vacuity control satisfied many times over.

Program-significant: 8.5%/10% density — the highest measured in eight flights, and the dev's sharper class naming ("an enumeration that stopped growing when the schema did", 15 of 20 sites) supersedes the table-shape heuristic; recorded on the anchor. Out-of-scope findings verified real: #13835 (lint _tabs orphan leg missing, the accepted #11608 shape one group over) and #13837 (CLI --help under-count — the #13809 spec-twin pattern applied to a CLI surface). Budget: net −8 lines / −2 tokens, both files shrink, no ceiling touched; generator-owned index untouched, check:skill-refs green; whole-repo pnpm lint run un-narrowed, exit 0.

needs:contract-review cleared on BOTH carriers. Governed .md content: PR remains DRAFT for the maintainer's merge (os-zhuang / hotlong requested).


Generated by Claude Code

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

Labels

documentationImprovements or additions to documentationsize/sskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

skills-sweep ⑧: objectstack-i18n (807 lines, 3 files) — behavioral-claim verification, content-class execution-first

3 participants

@huangyiirene@os-zhuang@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Correct 17 false behavioral claims in skills/objectstack-i18n — sweep flight ⑧ by huangyiirene · Pull Request #13833 · objectstack-ai/objectstack · GitHub
Skip to content

Correct 17 false behavioral claims in skills/objectstack-i18n — sweep flight ⑧ - #13833

Merged
os-zhuang merged 2 commits into
mainfrom
claude/issue-13815-skills-sweep-i18n
Aug 31, 2026
Merged

Correct 17 false behavioral claims in skills/objectstack-i18n — sweep flight ⑧#13833
os-zhuang merged 2 commits into
mainfrom
claude/issue-13815-skills-sweep-i18n

Conversation

@huangyiirene

Copy link
Copy Markdown
Collaborator

Fixes#13815
Part of #13658

Flight ⑧ of the published-skills factual sweep: skills/objectstack-i18n/** (3 files, 807 lines at branch point). Every claim was settled against the implementing code plus an executed probe — never against another document. 17 distinct false facts across 20 landing sites; net −8 lines, −2 tokens (SKILL.md 6337/6338, evals/README.md 410/411 — both shrink, no ceiling touched).

references/_index.md is generator-owned and was not hand-edited; check:skill-refs is green against it.

Where the truth was read

Fact classImplementing code
bundle / item / config shapespackages/spec/src/system/translation.zod.ts
service contractpackages/spec/src/contracts/i18n-service.ts
shipped adapterspackages/services/service-i18n/src/{file-i18n-adapter,i18n-service-plugin}.ts · packages/core/src/fallbacks/memory-i18n.ts
authored-item syncpackages/core/src/fallbacks/authored-translation-sync.ts
CLI coverage / extractpackages/cli/src/commands/i18n/{check,extract}.ts · packages/cli/src/utils/i18n-{coverage,extract}.ts
orphan-key lintpackages/lint/src/validate-translation-references.ts
shipped examplesexamples/app-crm/src/translations/ · examples/app-todo/src/translations/

Per-item corrections

#落点beforeafter
1SKILL.md · Object-Level table"Object-level text (label is required)""Object-level text (every key optional)" — label: z.string().optional(), with a schema comment arguing partial translation is the normal state
2SKILL.md · Object-Level tableno _tabs rowadded _tabs.{tab_name} — a live authorable surface (resolveTabLabel), extracted and coverage-gated
3SKILL.md · Object-Level table_actions holds label, confirmText, successMessage, params, resultDialogdescription added — declared on the action translation shape
4SKILL.md · Object-Level table_sections holds "Form section / tab label""Form section label" — tabs are their own group, now row 2 above
5SKILL.md · "Top-level groups alongside objects"apps, messages, globalActions, dashboards, settings, metadataForms, settingsCommonpages and flows added — 10 groups on the shape, not 8
6SKILL.md · Core Concepts 1same list minus settingsCommon, and object content omits tabsboth lists brought to the shape's real membership
7SKILL.md · Authoring at Runtime"skipped by the runtime sync — a silent skip … rather than inferred from the item name"the sync falls back to a BCP-47-looking item name, then skips with an [i18n] … — skippedwarning naming the row. Not silent
8SKILL.md · "Retired: the o.* dialect""rejected at save time with a message naming the group to use instead""both doors now reject it — files included". 4 of the 10 keys are told they have no home (reports, notifications, errors, namespace), so "naming the group to use instead" was false for them
9SKILL.md · Pitfall "The Retired o.* Shape""Files registered in that shape resolve to nothing; runtime items … rejected at save time"both doors reject: defineTranslationBundlethrows on a file bundle. The file door was closed at the same time as the item door
10SKILL.md · os i18n check"reports missing object/field/option/view/action keys"every surface the extractor walks — 14 source kinds live, 5 were named
11SKILL.md · Extract skeletons"writes {locale}.objects.generated.ts … Other flags: --default-locale, --filter, --dry-run, --json"the {locale}.metadata-forms.generated.ts companion is written by default; four more flags exist (--no-merge, --no-objects-only, --metadata-forms, --source-hashes), so the list now points at --help instead of claiming to be complete
12SKILL.md · "Use both gates""Renaming a label, adding an object, or removing a spec key leaves coverage at 100%"adding an object lowers coverage — its keys join the expected set. Dropped from the trio
13SKILL.md · II18nService methodsgetLocales() / getDefaultLocale() / setDefaultLocale()setSupportedLocales() added — on the contract and implemented by both shipped adapters
14SKILL.md · II18nService optional methods"getCoverage, suggestTranslations — no shipped implementation provides"getFieldLabels added — same class exactly: declared optional, probed by both serving surfaces, implemented by no shipped provider
15SKILL.md · Diff & Coverage SchemasTranslationDiffItem = key, status, locale, sourceHash, AI fieldsoptional objectName added
16SKILL.md · orphan-key lint"object, field, view, action, param, section, app, nav item, dashboard or widget"flow screens added — the rule walks flows.{name}.screens.{node} too
17SKILL.md · Authoring Translation Bundles"mirrors the shipped example apps ({en,zh-CN}.ts + index.ts)"that is examples/app-todo alone, and it ships three locales
18SKILL.md · CRM I18n Blueprint"Bundle entry: src/translations/index.ts … Locale files: {en,zh-CN,ja-JP,es-ES}.ts"examples/app-crm has one file, crm.translation.ts, holding en + zh-CN. No index.ts, no per-locale files, no ja-JP/es-ES
19SKILL.md · CRM table"per-locale source files by convention" · "imports per-locale files" · objects.account.fields.*the CRM example does none of these; its object is crm_account
20SKILL.md · Pitfall "Ignoring Coverage Reports""Stale translations can cause confusion. Always run os i18n check"coverage cannot see staleness — this document's own extract --check section says so. Now points at the gate that can
21evals/README.md · rubric"runtime objects.* vs secondaryo.* format""retired o.* is rejected" — a grader taught the retired dialect is a live secondary format fails correct answers
22evals/README.md · rubric"ICU is experimental""no ICU engine" — the messageFormat knob was removed and nothing evaluates ICU strings

Rows 4, 6, 19 are the second landing sites of facts 2, 5 and 18; 17 distinct facts, 20 sites, plus 2 rubric rows.

Executed evidence

Two probe scripts (temporary, removed before commit — this diff is 2 markdown files). Built first: @objectstack/service-i18n..., @objectstack/lint..., @objectstack/platform-objects... (exit 0 each), so every read is against rebuilt dist, not stale declarations.

Schema/adapter probe, run from packages/services/service-i18n:

=== TranslationDataSchema top-level groups ===
["objects","apps","messages","globalActions","dashboards","pages","flows","settings","metadataForms","settingsCommon"]
=== ObjectTranslationDataSchema sub-keys ===
["label","pluralLabel","description","fields","_views","_actions","_sections","_tabs"]
=== object _actions sub-keys ===
["label","description","confirmText","successMessage","params","resultDialog"]
=== is objects.OBJ.label REQUIRED? ===
parse { objects: { task: { pluralLabel } } } (no label) -> success=true
=== retired o.* dialect ===
item.o: rejected=true :: `o` is the retired object-first dialect … use 'objects.OBJECT_NAME'
item.reports: rejected=true :: `reports` … reports have no translation group, omit them
bundle-door o: rejected=true
defineTranslationBundle({ en: { o: … } }) -> threw
=== interpolation ===
double: Welcome, Alice! single: Hi, {userName}! icu: messages.icu (key echoed)
=== contract methods on both shipped adapters ===
setSupportedLocales file=true memory=true
getFieldLabels file=false memory=false
getCoverage file=false memory=false
suggestTranslations file=false memory=false

CLI probe (tsx, packages/cli), driving the real walker and coverage detector:

=== ExpectedEntry.source kinds the walker emits ===
action 7 · app 1 · dashboard 1 · field 6 · flow 2 · globalAction 4 ·
metadataFormField 948 · metadataFormSection 150 · metadataType 54 ·
navigation 1 · object 3 · option 1 · page 1 · view 1 · widget 1
=== _tabs IS harvested ===
objects.task._tabs.urgent.label [source=view]
flows.onboard.screens.welcome.title [source=flow]
=== os i18n check reported source kinds ===
action, app, dashboard, field, globalAction, metadataForm, navigation,
object, option, page, view, widget (12 kinds from one small fixture)
=== --strict promotes non-default gaps ===
lax errors=0 warnings=783
strict errors=783 warnings=0

The non-vacuity control is satisfied many times over: facts 1, 2, 3, 5, 8, 9, 10, 13, 14 were each decided by a run, not a read.

Gates — all run at 5d16fd477 (the final commit)

Families derived from the real diff with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (exit 0; 14 families, re-derived unchanged on the final commit), plus the skill-specific gates the derivation scores silent because they compute their own population:

gateexit
check-ci-filter-parity · check-cross-package-test-inputs · check-shard-attestation0 · 0 · 0
check-skills-token-ratchet0 — SKILL.md 6337/6338 (−1), evals/README.md 410/411 (−1)
check:doc-formula-expressions · check:agent-test-spelling · check:corpus-claim-drift0 · 0 · 0
check:cross-package-test-inputs · check:doc-authoring · check:pm-governed-merges0 · 0 · 0
check:role-word · check:skill-compatibility · check:skill-frame-sync0 · 0 · 0
check:nul-bytes · check:pm-skill-ratchet · check:pm-skill-id-lint · check:skill-frame-freshness0 · 0 · 0 · 0
@objectstack/spec check:skill-examples0 — 260 marked blocks across 101 files, population non-empty (this package contributes 4 os:check fences)
@objectstack/spec check:skill-refs · check:skill-docs0 · 0
pnpm lint (repo-wide eslint . --no-inline-config)0
check-test-completeness3 — NOT MEASURED. The gate grades a saved turbo run test log and none exists locally; its own text says exit 3 "is not a red, and there is nothing here to fix"

ESLint was run whole rather than narrowed, and separately measured: both changed files report File ignored because no matching configuration was supplied — markdown is outside the linted population entirely (no files block in eslint.config.mjs names .md).

Pure skills/** diff, nothing published from any package — skip-changeset applies, matching flights ③/④/⑤ which landed the same shape with no changeset.

Governed surface

Published skills/**: this PR stays draft and is for the maintainer to merge. needs:contract-review is attached to this PR and to card #13815 in the same stroke (批 #12 clause ② CONTENT limb) and is never self-cleared.

Generated by Claude Code


Generated by Claude Code

…implementation
Flight 8 of the published-skills factual sweep (#13658). Every correction is
settled against the implementing code plus an executed probe; net -1 line.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EnE7G31tqbxN1rqpQmzurT
…en ratchet
The corrections in the previous commit were factually right but grew SKILL.md
by 124 tokens against a ceiling that only ever shrinks. Same facts, fewer
bytes: enumerations point at the authority instead of transcribing it, and
duplicated prose around the retired o.* dialect is stated once.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EnE7G31tqbxN1rqpQmzurT
@huangyiireneClaude

Copy link
Copy Markdown
CollaboratorAuthor

Contract review — PASS at head 5d16fd477

Applicability: clause-② CONTENT limb (批 #12). Both carriers attached at PR creation, delayed read-backs clean; cleared in this stroke.

Reviewer qualification, machine-read this sitting: get_sessionexternal_metadata.last_served_model = claude-fable-5 = CONTRACT_REVIEW_TIER.

Review: report + diff read; anchors independently re-measured on origin/main this hour —

  • _tabs is a live, gated slot: ObjectTranslationDataSchema declares it, packages/cli/src/utils/i18n-extract.ts:590–611 emits objects.<o>._tabs.<tab>.label for every rendered preset tab, and resolveTabLabel consumes it — the missing table row hid shipped capability;
  • pages is harvested by the same extractor (:563) — the top-level group list was under-enumerating;
  • setSupportedLocales is in the contract (packages/spec/src/contracts/i18n-service.ts:97) and implemented on BOTH shipped adapters (file adapter + packages/core/src/fallbacks/memory-i18n.ts) — the method-list omission was false;
  • The dev's parse probe disproving "label is required" ({objects:{task:{pluralLabel}}} parses green) and the LEGACY_OBJECT_FIRST_KEYS double-door rejection are executed evidence in both error directions, with the non-vacuity control satisfied many times over.

Program-significant: 8.5%/10% density — the highest measured in eight flights, and the dev's sharper class naming ("an enumeration that stopped growing when the schema did", 15 of 20 sites) supersedes the table-shape heuristic; recorded on the anchor. Out-of-scope findings verified real: #13835 (lint _tabs orphan leg missing, the accepted #11608 shape one group over) and #13837 (CLI --help under-count — the #13809 spec-twin pattern applied to a CLI surface). Budget: net −8 lines / −2 tokens, both files shrink, no ceiling touched; generator-owned index untouched, check:skill-refs green; whole-repo pnpm lint run un-narrowed, exit 0.

needs:contract-review cleared on BOTH carriers. Governed .md content: PR remains DRAFT for the maintainer's merge (os-zhuang / hotlong requested).


Generated by Claude Code

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

Labels

documentationImprovements or additions to documentationsize/sskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

skills-sweep ⑧: objectstack-i18n (807 lines, 3 files) — behavioral-claim verification, content-class execution-first

3 participants

@huangyiirene@os-zhuang@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Correct 17 false behavioral claims in skills/objectstack-i18n — sweep flight ⑧ by huangyiirene · Pull Request #13833 · objectstack-ai/objectstack · GitHub
Skip to content

Correct 17 false behavioral claims in skills/objectstack-i18n — sweep flight ⑧ - #13833

Merged
os-zhuang merged 2 commits into
mainfrom
claude/issue-13815-skills-sweep-i18n
Aug 31, 2026
Merged

Correct 17 false behavioral claims in skills/objectstack-i18n — sweep flight ⑧#13833
os-zhuang merged 2 commits into
mainfrom
claude/issue-13815-skills-sweep-i18n

Conversation

@huangyiirene

Copy link
Copy Markdown
Collaborator

Fixes#13815
Part of #13658

Flight ⑧ of the published-skills factual sweep: skills/objectstack-i18n/** (3 files, 807 lines at branch point). Every claim was settled against the implementing code plus an executed probe — never against another document. 17 distinct false facts across 20 landing sites; net −8 lines, −2 tokens (SKILL.md 6337/6338, evals/README.md 410/411 — both shrink, no ceiling touched).

references/_index.md is generator-owned and was not hand-edited; check:skill-refs is green against it.

Where the truth was read

Fact classImplementing code
bundle / item / config shapespackages/spec/src/system/translation.zod.ts
service contractpackages/spec/src/contracts/i18n-service.ts
shipped adapterspackages/services/service-i18n/src/{file-i18n-adapter,i18n-service-plugin}.ts · packages/core/src/fallbacks/memory-i18n.ts
authored-item syncpackages/core/src/fallbacks/authored-translation-sync.ts
CLI coverage / extractpackages/cli/src/commands/i18n/{check,extract}.ts · packages/cli/src/utils/i18n-{coverage,extract}.ts
orphan-key lintpackages/lint/src/validate-translation-references.ts
shipped examplesexamples/app-crm/src/translations/ · examples/app-todo/src/translations/

Per-item corrections

#落点beforeafter
1SKILL.md · Object-Level table"Object-level text (label is required)""Object-level text (every key optional)" — label: z.string().optional(), with a schema comment arguing partial translation is the normal state
2SKILL.md · Object-Level tableno _tabs rowadded _tabs.{tab_name} — a live authorable surface (resolveTabLabel), extracted and coverage-gated
3SKILL.md · Object-Level table_actions holds label, confirmText, successMessage, params, resultDialogdescription added — declared on the action translation shape
4SKILL.md · Object-Level table_sections holds "Form section / tab label""Form section label" — tabs are their own group, now row 2 above
5SKILL.md · "Top-level groups alongside objects"apps, messages, globalActions, dashboards, settings, metadataForms, settingsCommonpages and flows added — 10 groups on the shape, not 8
6SKILL.md · Core Concepts 1same list minus settingsCommon, and object content omits tabsboth lists brought to the shape's real membership
7SKILL.md · Authoring at Runtime"skipped by the runtime sync — a silent skip … rather than inferred from the item name"the sync falls back to a BCP-47-looking item name, then skips with an [i18n] … — skippedwarning naming the row. Not silent
8SKILL.md · "Retired: the o.* dialect""rejected at save time with a message naming the group to use instead""both doors now reject it — files included". 4 of the 10 keys are told they have no home (reports, notifications, errors, namespace), so "naming the group to use instead" was false for them
9SKILL.md · Pitfall "The Retired o.* Shape""Files registered in that shape resolve to nothing; runtime items … rejected at save time"both doors reject: defineTranslationBundlethrows on a file bundle. The file door was closed at the same time as the item door
10SKILL.md · os i18n check"reports missing object/field/option/view/action keys"every surface the extractor walks — 14 source kinds live, 5 were named
11SKILL.md · Extract skeletons"writes {locale}.objects.generated.ts … Other flags: --default-locale, --filter, --dry-run, --json"the {locale}.metadata-forms.generated.ts companion is written by default; four more flags exist (--no-merge, --no-objects-only, --metadata-forms, --source-hashes), so the list now points at --help instead of claiming to be complete
12SKILL.md · "Use both gates""Renaming a label, adding an object, or removing a spec key leaves coverage at 100%"adding an object lowers coverage — its keys join the expected set. Dropped from the trio
13SKILL.md · II18nService methodsgetLocales() / getDefaultLocale() / setDefaultLocale()setSupportedLocales() added — on the contract and implemented by both shipped adapters
14SKILL.md · II18nService optional methods"getCoverage, suggestTranslations — no shipped implementation provides"getFieldLabels added — same class exactly: declared optional, probed by both serving surfaces, implemented by no shipped provider
15SKILL.md · Diff & Coverage SchemasTranslationDiffItem = key, status, locale, sourceHash, AI fieldsoptional objectName added
16SKILL.md · orphan-key lint"object, field, view, action, param, section, app, nav item, dashboard or widget"flow screens added — the rule walks flows.{name}.screens.{node} too
17SKILL.md · Authoring Translation Bundles"mirrors the shipped example apps ({en,zh-CN}.ts + index.ts)"that is examples/app-todo alone, and it ships three locales
18SKILL.md · CRM I18n Blueprint"Bundle entry: src/translations/index.ts … Locale files: {en,zh-CN,ja-JP,es-ES}.ts"examples/app-crm has one file, crm.translation.ts, holding en + zh-CN. No index.ts, no per-locale files, no ja-JP/es-ES
19SKILL.md · CRM table"per-locale source files by convention" · "imports per-locale files" · objects.account.fields.*the CRM example does none of these; its object is crm_account
20SKILL.md · Pitfall "Ignoring Coverage Reports""Stale translations can cause confusion. Always run os i18n check"coverage cannot see staleness — this document's own extract --check section says so. Now points at the gate that can
21evals/README.md · rubric"runtime objects.* vs secondaryo.* format""retired o.* is rejected" — a grader taught the retired dialect is a live secondary format fails correct answers
22evals/README.md · rubric"ICU is experimental""no ICU engine" — the messageFormat knob was removed and nothing evaluates ICU strings

Rows 4, 6, 19 are the second landing sites of facts 2, 5 and 18; 17 distinct facts, 20 sites, plus 2 rubric rows.

Executed evidence

Two probe scripts (temporary, removed before commit — this diff is 2 markdown files). Built first: @objectstack/service-i18n..., @objectstack/lint..., @objectstack/platform-objects... (exit 0 each), so every read is against rebuilt dist, not stale declarations.

Schema/adapter probe, run from packages/services/service-i18n:

=== TranslationDataSchema top-level groups ===
["objects","apps","messages","globalActions","dashboards","pages","flows","settings","metadataForms","settingsCommon"]
=== ObjectTranslationDataSchema sub-keys ===
["label","pluralLabel","description","fields","_views","_actions","_sections","_tabs"]
=== object _actions sub-keys ===
["label","description","confirmText","successMessage","params","resultDialog"]
=== is objects.OBJ.label REQUIRED? ===
parse { objects: { task: { pluralLabel } } } (no label) -> success=true
=== retired o.* dialect ===
item.o: rejected=true :: `o` is the retired object-first dialect … use 'objects.OBJECT_NAME'
item.reports: rejected=true :: `reports` … reports have no translation group, omit them
bundle-door o: rejected=true
defineTranslationBundle({ en: { o: … } }) -> threw
=== interpolation ===
double: Welcome, Alice! single: Hi, {userName}! icu: messages.icu (key echoed)
=== contract methods on both shipped adapters ===
setSupportedLocales file=true memory=true
getFieldLabels file=false memory=false
getCoverage file=false memory=false
suggestTranslations file=false memory=false

CLI probe (tsx, packages/cli), driving the real walker and coverage detector:

=== ExpectedEntry.source kinds the walker emits ===
action 7 · app 1 · dashboard 1 · field 6 · flow 2 · globalAction 4 ·
metadataFormField 948 · metadataFormSection 150 · metadataType 54 ·
navigation 1 · object 3 · option 1 · page 1 · view 1 · widget 1
=== _tabs IS harvested ===
objects.task._tabs.urgent.label [source=view]
flows.onboard.screens.welcome.title [source=flow]
=== os i18n check reported source kinds ===
action, app, dashboard, field, globalAction, metadataForm, navigation,
object, option, page, view, widget (12 kinds from one small fixture)
=== --strict promotes non-default gaps ===
lax errors=0 warnings=783
strict errors=783 warnings=0

The non-vacuity control is satisfied many times over: facts 1, 2, 3, 5, 8, 9, 10, 13, 14 were each decided by a run, not a read.

Gates — all run at 5d16fd477 (the final commit)

Families derived from the real diff with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (exit 0; 14 families, re-derived unchanged on the final commit), plus the skill-specific gates the derivation scores silent because they compute their own population:

gateexit
check-ci-filter-parity · check-cross-package-test-inputs · check-shard-attestation0 · 0 · 0
check-skills-token-ratchet0 — SKILL.md 6337/6338 (−1), evals/README.md 410/411 (−1)
check:doc-formula-expressions · check:agent-test-spelling · check:corpus-claim-drift0 · 0 · 0
check:cross-package-test-inputs · check:doc-authoring · check:pm-governed-merges0 · 0 · 0
check:role-word · check:skill-compatibility · check:skill-frame-sync0 · 0 · 0
check:nul-bytes · check:pm-skill-ratchet · check:pm-skill-id-lint · check:skill-frame-freshness0 · 0 · 0 · 0
@objectstack/spec check:skill-examples0 — 260 marked blocks across 101 files, population non-empty (this package contributes 4 os:check fences)
@objectstack/spec check:skill-refs · check:skill-docs0 · 0
pnpm lint (repo-wide eslint . --no-inline-config)0
check-test-completeness3 — NOT MEASURED. The gate grades a saved turbo run test log and none exists locally; its own text says exit 3 "is not a red, and there is nothing here to fix"

ESLint was run whole rather than narrowed, and separately measured: both changed files report File ignored because no matching configuration was supplied — markdown is outside the linted population entirely (no files block in eslint.config.mjs names .md).

Pure skills/** diff, nothing published from any package — skip-changeset applies, matching flights ③/④/⑤ which landed the same shape with no changeset.

Governed surface

Published skills/**: this PR stays draft and is for the maintainer to merge. needs:contract-review is attached to this PR and to card #13815 in the same stroke (批 #12 clause ② CONTENT limb) and is never self-cleared.

Generated by Claude Code


Generated by Claude Code

…implementation
Flight 8 of the published-skills factual sweep (#13658). Every correction is
settled against the implementing code plus an executed probe; net -1 line.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EnE7G31tqbxN1rqpQmzurT
…en ratchet
The corrections in the previous commit were factually right but grew SKILL.md
by 124 tokens against a ceiling that only ever shrinks. Same facts, fewer
bytes: enumerations point at the authority instead of transcribing it, and
duplicated prose around the retired o.* dialect is stated once.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EnE7G31tqbxN1rqpQmzurT
@huangyiireneClaude

Copy link
Copy Markdown
CollaboratorAuthor

Contract review — PASS at head 5d16fd477

Applicability: clause-② CONTENT limb (批 #12). Both carriers attached at PR creation, delayed read-backs clean; cleared in this stroke.

Reviewer qualification, machine-read this sitting: get_sessionexternal_metadata.last_served_model = claude-fable-5 = CONTRACT_REVIEW_TIER.

Review: report + diff read; anchors independently re-measured on origin/main this hour —

  • _tabs is a live, gated slot: ObjectTranslationDataSchema declares it, packages/cli/src/utils/i18n-extract.ts:590–611 emits objects.<o>._tabs.<tab>.label for every rendered preset tab, and resolveTabLabel consumes it — the missing table row hid shipped capability;
  • pages is harvested by the same extractor (:563) — the top-level group list was under-enumerating;
  • setSupportedLocales is in the contract (packages/spec/src/contracts/i18n-service.ts:97) and implemented on BOTH shipped adapters (file adapter + packages/core/src/fallbacks/memory-i18n.ts) — the method-list omission was false;
  • The dev's parse probe disproving "label is required" ({objects:{task:{pluralLabel}}} parses green) and the LEGACY_OBJECT_FIRST_KEYS double-door rejection are executed evidence in both error directions, with the non-vacuity control satisfied many times over.

Program-significant: 8.5%/10% density — the highest measured in eight flights, and the dev's sharper class naming ("an enumeration that stopped growing when the schema did", 15 of 20 sites) supersedes the table-shape heuristic; recorded on the anchor. Out-of-scope findings verified real: #13835 (lint _tabs orphan leg missing, the accepted #11608 shape one group over) and #13837 (CLI --help under-count — the #13809 spec-twin pattern applied to a CLI surface). Budget: net −8 lines / −2 tokens, both files shrink, no ceiling touched; generator-owned index untouched, check:skill-refs green; whole-repo pnpm lint run un-narrowed, exit 0.

needs:contract-review cleared on BOTH carriers. Governed .md content: PR remains DRAFT for the maintainer's merge (os-zhuang / hotlong requested).


Generated by Claude Code

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

Labels

documentationImprovements or additions to documentationsize/sskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

skills-sweep ⑧: objectstack-i18n (807 lines, 3 files) — behavioral-claim verification, content-class execution-first

3 participants

@huangyiirene@os-zhuang@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); Correct 17 false behavioral claims in skills/objectstack-i18n — sweep flight ⑧ by huangyiirene · Pull Request #13833 · objectstack-ai/objectstack · GitHub
Skip to content

Correct 17 false behavioral claims in skills/objectstack-i18n — sweep flight ⑧ - #13833

Merged
os-zhuang merged 2 commits into
mainfrom
claude/issue-13815-skills-sweep-i18n
Aug 31, 2026
Merged

Correct 17 false behavioral claims in skills/objectstack-i18n — sweep flight ⑧#13833
os-zhuang merged 2 commits into
mainfrom
claude/issue-13815-skills-sweep-i18n

Conversation

@huangyiirene

Copy link
Copy Markdown
Collaborator

Fixes#13815
Part of #13658

Flight ⑧ of the published-skills factual sweep: skills/objectstack-i18n/** (3 files, 807 lines at branch point). Every claim was settled against the implementing code plus an executed probe — never against another document. 17 distinct false facts across 20 landing sites; net −8 lines, −2 tokens (SKILL.md 6337/6338, evals/README.md 410/411 — both shrink, no ceiling touched).

references/_index.md is generator-owned and was not hand-edited; check:skill-refs is green against it.

Where the truth was read

Fact classImplementing code
bundle / item / config shapespackages/spec/src/system/translation.zod.ts
service contractpackages/spec/src/contracts/i18n-service.ts
shipped adapterspackages/services/service-i18n/src/{file-i18n-adapter,i18n-service-plugin}.ts · packages/core/src/fallbacks/memory-i18n.ts
authored-item syncpackages/core/src/fallbacks/authored-translation-sync.ts
CLI coverage / extractpackages/cli/src/commands/i18n/{check,extract}.ts · packages/cli/src/utils/i18n-{coverage,extract}.ts
orphan-key lintpackages/lint/src/validate-translation-references.ts
shipped examplesexamples/app-crm/src/translations/ · examples/app-todo/src/translations/

Per-item corrections

#落点beforeafter
1SKILL.md · Object-Level table"Object-level text (label is required)""Object-level text (every key optional)" — label: z.string().optional(), with a schema comment arguing partial translation is the normal state
2SKILL.md · Object-Level tableno _tabs rowadded _tabs.{tab_name} — a live authorable surface (resolveTabLabel), extracted and coverage-gated
3SKILL.md · Object-Level table_actions holds label, confirmText, successMessage, params, resultDialogdescription added — declared on the action translation shape
4SKILL.md · Object-Level table_sections holds "Form section / tab label""Form section label" — tabs are their own group, now row 2 above
5SKILL.md · "Top-level groups alongside objects"apps, messages, globalActions, dashboards, settings, metadataForms, settingsCommonpages and flows added — 10 groups on the shape, not 8
6SKILL.md · Core Concepts 1same list minus settingsCommon, and object content omits tabsboth lists brought to the shape's real membership
7SKILL.md · Authoring at Runtime"skipped by the runtime sync — a silent skip … rather than inferred from the item name"the sync falls back to a BCP-47-looking item name, then skips with an [i18n] … — skippedwarning naming the row. Not silent
8SKILL.md · "Retired: the o.* dialect""rejected at save time with a message naming the group to use instead""both doors now reject it — files included". 4 of the 10 keys are told they have no home (reports, notifications, errors, namespace), so "naming the group to use instead" was false for them
9SKILL.md · Pitfall "The Retired o.* Shape""Files registered in that shape resolve to nothing; runtime items … rejected at save time"both doors reject: defineTranslationBundlethrows on a file bundle. The file door was closed at the same time as the item door
10SKILL.md · os i18n check"reports missing object/field/option/view/action keys"every surface the extractor walks — 14 source kinds live, 5 were named
11SKILL.md · Extract skeletons"writes {locale}.objects.generated.ts … Other flags: --default-locale, --filter, --dry-run, --json"the {locale}.metadata-forms.generated.ts companion is written by default; four more flags exist (--no-merge, --no-objects-only, --metadata-forms, --source-hashes), so the list now points at --help instead of claiming to be complete
12SKILL.md · "Use both gates""Renaming a label, adding an object, or removing a spec key leaves coverage at 100%"adding an object lowers coverage — its keys join the expected set. Dropped from the trio
13SKILL.md · II18nService methodsgetLocales() / getDefaultLocale() / setDefaultLocale()setSupportedLocales() added — on the contract and implemented by both shipped adapters
14SKILL.md · II18nService optional methods"getCoverage, suggestTranslations — no shipped implementation provides"getFieldLabels added — same class exactly: declared optional, probed by both serving surfaces, implemented by no shipped provider
15SKILL.md · Diff & Coverage SchemasTranslationDiffItem = key, status, locale, sourceHash, AI fieldsoptional objectName added
16SKILL.md · orphan-key lint"object, field, view, action, param, section, app, nav item, dashboard or widget"flow screens added — the rule walks flows.{name}.screens.{node} too
17SKILL.md · Authoring Translation Bundles"mirrors the shipped example apps ({en,zh-CN}.ts + index.ts)"that is examples/app-todo alone, and it ships three locales
18SKILL.md · CRM I18n Blueprint"Bundle entry: src/translations/index.ts … Locale files: {en,zh-CN,ja-JP,es-ES}.ts"examples/app-crm has one file, crm.translation.ts, holding en + zh-CN. No index.ts, no per-locale files, no ja-JP/es-ES
19SKILL.md · CRM table"per-locale source files by convention" · "imports per-locale files" · objects.account.fields.*the CRM example does none of these; its object is crm_account
20SKILL.md · Pitfall "Ignoring Coverage Reports""Stale translations can cause confusion. Always run os i18n check"coverage cannot see staleness — this document's own extract --check section says so. Now points at the gate that can
21evals/README.md · rubric"runtime objects.* vs secondaryo.* format""retired o.* is rejected" — a grader taught the retired dialect is a live secondary format fails correct answers
22evals/README.md · rubric"ICU is experimental""no ICU engine" — the messageFormat knob was removed and nothing evaluates ICU strings

Rows 4, 6, 19 are the second landing sites of facts 2, 5 and 18; 17 distinct facts, 20 sites, plus 2 rubric rows.

Executed evidence

Two probe scripts (temporary, removed before commit — this diff is 2 markdown files). Built first: @objectstack/service-i18n..., @objectstack/lint..., @objectstack/platform-objects... (exit 0 each), so every read is against rebuilt dist, not stale declarations.

Schema/adapter probe, run from packages/services/service-i18n:

=== TranslationDataSchema top-level groups ===
["objects","apps","messages","globalActions","dashboards","pages","flows","settings","metadataForms","settingsCommon"]
=== ObjectTranslationDataSchema sub-keys ===
["label","pluralLabel","description","fields","_views","_actions","_sections","_tabs"]
=== object _actions sub-keys ===
["label","description","confirmText","successMessage","params","resultDialog"]
=== is objects.OBJ.label REQUIRED? ===
parse { objects: { task: { pluralLabel } } } (no label) -> success=true
=== retired o.* dialect ===
item.o: rejected=true :: `o` is the retired object-first dialect … use 'objects.OBJECT_NAME'
item.reports: rejected=true :: `reports` … reports have no translation group, omit them
bundle-door o: rejected=true
defineTranslationBundle({ en: { o: … } }) -> threw
=== interpolation ===
double: Welcome, Alice! single: Hi, {userName}! icu: messages.icu (key echoed)
=== contract methods on both shipped adapters ===
setSupportedLocales file=true memory=true
getFieldLabels file=false memory=false
getCoverage file=false memory=false
suggestTranslations file=false memory=false

CLI probe (tsx, packages/cli), driving the real walker and coverage detector:

=== ExpectedEntry.source kinds the walker emits ===
action 7 · app 1 · dashboard 1 · field 6 · flow 2 · globalAction 4 ·
metadataFormField 948 · metadataFormSection 150 · metadataType 54 ·
navigation 1 · object 3 · option 1 · page 1 · view 1 · widget 1
=== _tabs IS harvested ===
objects.task._tabs.urgent.label [source=view]
flows.onboard.screens.welcome.title [source=flow]
=== os i18n check reported source kinds ===
action, app, dashboard, field, globalAction, metadataForm, navigation,
object, option, page, view, widget (12 kinds from one small fixture)
=== --strict promotes non-default gaps ===
lax errors=0 warnings=783
strict errors=783 warnings=0

The non-vacuity control is satisfied many times over: facts 1, 2, 3, 5, 8, 9, 10, 13, 14 were each decided by a run, not a read.

Gates — all run at 5d16fd477 (the final commit)

Families derived from the real diff with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (exit 0; 14 families, re-derived unchanged on the final commit), plus the skill-specific gates the derivation scores silent because they compute their own population:

gateexit
check-ci-filter-parity · check-cross-package-test-inputs · check-shard-attestation0 · 0 · 0
check-skills-token-ratchet0 — SKILL.md 6337/6338 (−1), evals/README.md 410/411 (−1)
check:doc-formula-expressions · check:agent-test-spelling · check:corpus-claim-drift0 · 0 · 0
check:cross-package-test-inputs · check:doc-authoring · check:pm-governed-merges0 · 0 · 0
check:role-word · check:skill-compatibility · check:skill-frame-sync0 · 0 · 0
check:nul-bytes · check:pm-skill-ratchet · check:pm-skill-id-lint · check:skill-frame-freshness0 · 0 · 0 · 0
@objectstack/spec check:skill-examples0 — 260 marked blocks across 101 files, population non-empty (this package contributes 4 os:check fences)
@objectstack/spec check:skill-refs · check:skill-docs0 · 0
pnpm lint (repo-wide eslint . --no-inline-config)0
check-test-completeness3 — NOT MEASURED. The gate grades a saved turbo run test log and none exists locally; its own text says exit 3 "is not a red, and there is nothing here to fix"

ESLint was run whole rather than narrowed, and separately measured: both changed files report File ignored because no matching configuration was supplied — markdown is outside the linted population entirely (no files block in eslint.config.mjs names .md).

Pure skills/** diff, nothing published from any package — skip-changeset applies, matching flights ③/④/⑤ which landed the same shape with no changeset.

Governed surface

Published skills/**: this PR stays draft and is for the maintainer to merge. needs:contract-review is attached to this PR and to card #13815 in the same stroke (批 #12 clause ② CONTENT limb) and is never self-cleared.

Generated by Claude Code


Generated by Claude Code

…implementation
Flight 8 of the published-skills factual sweep (#13658). Every correction is
settled against the implementing code plus an executed probe; net -1 line.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EnE7G31tqbxN1rqpQmzurT
…en ratchet
The corrections in the previous commit were factually right but grew SKILL.md
by 124 tokens against a ceiling that only ever shrinks. Same facts, fewer
bytes: enumerations point at the authority instead of transcribing it, and
duplicated prose around the retired o.* dialect is stated once.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EnE7G31tqbxN1rqpQmzurT
@huangyiireneClaude

Copy link
Copy Markdown
CollaboratorAuthor

Contract review — PASS at head 5d16fd477

Applicability: clause-② CONTENT limb (批 #12). Both carriers attached at PR creation, delayed read-backs clean; cleared in this stroke.

Reviewer qualification, machine-read this sitting: get_sessionexternal_metadata.last_served_model = claude-fable-5 = CONTRACT_REVIEW_TIER.

Review: report + diff read; anchors independently re-measured on origin/main this hour —

  • _tabs is a live, gated slot: ObjectTranslationDataSchema declares it, packages/cli/src/utils/i18n-extract.ts:590–611 emits objects.<o>._tabs.<tab>.label for every rendered preset tab, and resolveTabLabel consumes it — the missing table row hid shipped capability;
  • pages is harvested by the same extractor (:563) — the top-level group list was under-enumerating;
  • setSupportedLocales is in the contract (packages/spec/src/contracts/i18n-service.ts:97) and implemented on BOTH shipped adapters (file adapter + packages/core/src/fallbacks/memory-i18n.ts) — the method-list omission was false;
  • The dev's parse probe disproving "label is required" ({objects:{task:{pluralLabel}}} parses green) and the LEGACY_OBJECT_FIRST_KEYS double-door rejection are executed evidence in both error directions, with the non-vacuity control satisfied many times over.

Program-significant: 8.5%/10% density — the highest measured in eight flights, and the dev's sharper class naming ("an enumeration that stopped growing when the schema did", 15 of 20 sites) supersedes the table-shape heuristic; recorded on the anchor. Out-of-scope findings verified real: #13835 (lint _tabs orphan leg missing, the accepted #11608 shape one group over) and #13837 (CLI --help under-count — the #13809 spec-twin pattern applied to a CLI surface). Budget: net −8 lines / −2 tokens, both files shrink, no ceiling touched; generator-owned index untouched, check:skill-refs green; whole-repo pnpm lint run un-narrowed, exit 0.

needs:contract-review cleared on BOTH carriers. Governed .md content: PR remains DRAFT for the maintainer's merge (os-zhuang / hotlong requested).


Generated by Claude Code

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

Labels

documentationImprovements or additions to documentationsize/sskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

skills-sweep ⑧: objectstack-i18n (807 lines, 3 files) — behavioral-claim verification, content-class execution-first

3 participants

@huangyiirene@os-zhuang@claude