Skip to content

Commit f9bcd08

Browse files
fix(datasource, approvals): runtime strings state each decision in words instead of a tracker number (stage 3) (#21346)
Part of #20751 Clause-②: no **Stage 3 of the `domain:services` lane under the maintainer's A / A ruling (5902360492): the `service-datasource` and `plugin-approvals` strings.** The card stays open for the later stages, so this PR carries no closing keyword. Text only: no status, error `code`, field, route, export or control flow moves (AST skeleton reads SAME for 12 of 12 changed sources, below). ## What this does The two packages' refusals, warnings, log lines, datasource route-ledger notes, the generated object-draft comment, and the `sys_approval_action` / `sys_approval_delegation` field help and description (with their `es-ES`, `ja-JP` and `zh-CN` variants) sent the reader to a tracker number for the reason behind them. In form D, as stages 1 and 2 applied it, the number goes. Where the sentence already said what was decided, only the citation goes. Where it leaned on the number, it now says the decision in words. All 34 ledgered occurrences in the two packages (claim `5945630892`), re-derived from the ledger on `origin/main` at `1371dc98` and again on the merged tree at `222ecc27`: `service-datasource` 9 (9 pairs, 3 files), `plugin-approvals` 25 (23 pairs, 7 files). They sit in 32 string sites. None of them is in the three excluded files (`datasource-secret-binder.test.ts`, `sys-approval-token.object.ts`, `approval-token-internal-hash.integration.test.ts`); none of those files is touched. ### Rewritten in words Author- and administrator-visible text first, log lines last. | Where (head line) | Cited | The text now says | Decision read from | |---|---|---|---| | `plugin-approvals` `sys-approval-action.object.ts:165`, `via_override` help, and its three locale leaves | 3424 | "admitted to this action only by the privileged override, which lets a platform or organization admin act on any pending request so that one nobody in its slate can decide never stays stuck" | the card's fix comment (an admin escape hatch rather than refusing empty approvers at creation) and the `isOverrideActor` contract it landed: a platform or tenant admin may always act on a PENDING request | | `service-datasource` `datasource-credential-migration.ts:269-272`, the migration refusal `reason` | 8078, 8081 | "an alias spelling from before inline credentials were refused at publish, which no connection builder reads, or ... turso's `encryptionKey`, which has no secret slot of its own: the one slot carries the `authToken`" | 8078 (the spec half: `password` / `authToken` declared unwritable, the old alias spellings carry the refusal, `encryptionKey` left writable because neither ruled mechanism can carry it) and 8081 item 4 (the binder injects exactly one secret slot; a second slot is undecided) | | `service-datasource` `external-datasource-service.ts:925`, the generated draft's remote-primary-key comment | 10997 | "For a COMPOSITE key a driver's introspection can report only the first column, so treat the list as a lower bound" | 10997 repaired the SQLite arm (every column whose `pk` ordinal is above zero, ordered by key position, PR 11104), so the old "some drivers report only the first column" named a defect that is gone in-tree; the caveat stays because the generator renders whatever key it was given and the driver population is open (the `external-datasource-service.ts` docblock records both) | | `plugin-approvals` `approval-service.ts:1765`, the `queue` approver warning | 3508 | "because the platform has no ownership queue to expand it from (the type is deprecated and no longer offered for authoring). Route this step to a team, department or position instead." | the card's resolution: deep deprecation rather than an implementation, since there is no queue entity or member table; the routing advice is the same one the `approval-approver-type-unsupported` lint hint gives | | `plugin-approvals` `approval-service.ts:2629`, `:2636`, the live-record warnings | 3447 | "resolving approvers against the trigger snapshot instead of the live record they are normally resolved from" | the card's P1 (approvers are resolved against the live record re-read at node entry; the trigger snapshot is the fallback the code keeps when that read finds nothing or fails) | | `plugin-approvals` `approval-service.ts:3669`, the recall refusal's developer log line | 3424 | "holds no admin override for a ... request (the override reaches pending requests only)" | same as the `via_override` row | | `service-datasource` `datasource-route-ledger.ts:139`, list note | 3827 | "the retained connect verdict per datasource, so a datasource that failed to connect reports `error` here instead of looking untested" | the card's half A (`status` reports the retained connect result instead of a constant `unvalidated`) | | `service-datasource` `datasource-route-ledger.ts:149`, migrate-credential note | 8155 | "drops the inline key only once the secret is stored" | the maintainer-approved shape (b): the reference is durably written before the inline key is removed | | `service-datasource` `datasource-route-ledger.ts:161`, remote-tables note | 7744, 4249, 7955 | "both stay mounted, because renaming a live route to match a ledger would be an API break ... one failure contract (a refusal answers 400 `EXTERNAL_DATASOURCE_ERROR`, the code registered for the service that refused) and one request shape (both forward `?schema=` with the same coercion)" | 7744's dispatch and outcome (the ledger describes what is mounted; no rename), 4249's option 1 as landed (the separately registered `EXTERNAL_DATASOURCE_ERROR`), 7955's route A (forward `?schema=` with the twin's coercion) | ### Citation only (the sentence already stated the decision) - `plugin-approvals`: `sys-approval-action.object.ts:194` `attachments` help, and its three locale leaves (3266, "Files supporting this action — e.g. a signed contract or evidence"); `sys-approval-delegation.object.ts:43` description, and its three locale leaves (1322, "route this user's approver slots to a delegate within a time window"); `approval-service.ts:1782` (3807, "the slot routes to no one and the request cannot advance until someone is added or the approver is re-pointed"); `:2044` (10230), `:2113` and `:2139` (10547), `:2474` (10153), each already saying the team, member or manager is dropped because routing to them "would put approval authority over the record outside its tenant", and the truncated-read line already saying routing is left unchanged rather than risk dropping a member; `:4245` (3823, "that pause continues only through this service ... any other node type there is resumable by anyone with the run id (amended ADR-0044)"). - `service-datasource`: `external-datasource-service.ts:921` (11000, "Preserved as a COMMENT because 'ServiceObject' has no authorable key for a federated object's remote primary key: 'fields.FIELD.primaryKey' is not part of the field schema"). Every cited card (19: 8078, 8081, 3827, 4249, 7744, 7955, 8155, 10997, 11000, 10153, 10230, 10547, 3424, 3447, 3508, 3807, 3823, 3266, 1322) was read through REST, body and every comment, before its string was rewritten. 8078 is a pull request; its body carries the decision. ### Translations - `via_override` help: the `es-ES`, `ja-JP` and `zh-CN` leaves were real translations; each now carries the same decision ("un administrador de la plataforma o de la organización", "プラットフォーム管理者または組織管理者", "平台管理员或组织管理员") and no number. - `attachments` help (all three) and the `zh-CN` `sys_approval_delegation` description were real translations; each dropped its citation only. - The `es-ES` and `ja-JP` `sys_approval_delegation` descriptions were byte copies of the English source. They are now copies of the revised English, and `node scripts/check-i18n-bundles.mjs --write --filter=plugin-approvals` rewrote `en` from the object source and recorded the two new digests in the `es-ES` / `ja-JP` `*.source-hashes.generated.ts` companions. No digest and no `en` leaf was hand-edited; the merge kept every hand-written translated value. - Tracker numbers left in the package's locale bundles: 0. ## Ledger (`scripts/doc-authoring-prose-id.baseline.json`) Stage 2 (PR #21311) held this file. This branch was built while it sat in the queue, then `origin/main` (`222ecc27`, which contains `6091136e`, the stage-2 merge) was merged in, and only then was the ledger recomputed with `node scripts/check-doc-authoring.mjs --census-ledger` (exit 0, no growth refusal) into a scratch file and copied into place. The diff deletes 52 lines and adds none: exactly the 10 file blocks of the two packages. Every other row is unchanged (a scripted comparison of the 62 other keys: 0 moved). | | before (`222ecc27`) | after | |---|---|---| | `service-datasource` | 9 occurrences, 9 pairs, 3 files | 0 | | `plugin-approvals` | 25 occurrences, 23 pairs, 7 files | 0 | | whole ledger | 261 occurrences, 189 pairs, 72 files | 227 occurrences, 157 pairs, 62 files | `pnpm check:doc-authoring` at the head: "sibling-package prose ids hold the baseline — 204 pinned site(s) across 62 file(s), 85660 string(s) read in 1247 parsed source(s), no growth, no burn-down unrecorded". No gate is added or loosened; `scripts/check-doc-authoring.mjs` is untouched. ## Changeset `.changeset/20751-services-strings-stage3-state-the-decision.md`: `patch` for `@objectstack/service-datasource` and `@objectstack/plugin-approvals`. Measured after building at the head: the new author-visible sentences are in each package's built output (`plugin-approvals` `dist/index.js` and `dist/index.mjs`; `service-datasource` `dist/index.js` and `dist/index.cjs`). A TypeScript scan of every string literal and template text in the built output finds 0 tracker ids in `service-datasource`; in `plugin-approvals` its six matches are all CSS hex colours (`#2563eb`, `#64748b`) in the action-link page template, not tracker ids. Control: the same scan reads 82 in `plugin-security`'s built output and 66 in `service-automation`'s. The datasource route ledger does not ship: `DATASOURCE_ROUTE_LEDGER` and its new note text are in 0 files under `packages/services/service-datasource/dist`, so the changeset does not describe it. ## Text-only proof A TypeScript-AST skeleton of each changed non-test `.ts` file, where every string literal and template text is a placeholder, a run of adjacent string operands of a `+` chain is one string (only its embedded expressions are kept), identifiers and numbers keep their text, and comments are never read. `222ecc27` against the head: 12 of 12 SAME. Controls on scratch copies of `approval-service.ts`, each mutation's marker counted once on disk first: a one-identifier rename reads DIFF; a text-only change reads SAME; a re-split of one template into two concatenated pieces reads SAME. (A first draft of the tool wrapped every `+` chain in its own token and read `approval-service.ts` DIFF by two tokens: the `queue` warning went from one template to a three-piece chain. The corrected tool treats a chain of strings as one string, which is what the re-split control pins.) ## Pins Assertions that found a warning or comment by its tracker number now find it by what it says. No `code` or `status` assertion was touched; none of these strings is a coded refusal. - `approval-service.test.ts:3165`: the `queue` warning by `'queue'` and "no ownership queue to expand it from" instead of the id. - `approval-service.test.ts:3218`: the expanded-to-nobody warning by "cannot advance until someone is added or the approver is re-pointed" instead of the id. - `team-approver-org-screen.test.ts:223` and `team-member-org-screen.test.ts:250`: the warning found by "team 'team_b' was dropped from the approver slate" and "member(s) of team 'team_a' were dropped from the approver slate"; both test titles drop "and the card". - `external-object-draft-primary-key.test.ts:218` and `:229`: "a driver's introspection can report only the first column" and "not part of the field schema" instead of the ids; the first test's title said 10997 "is unfixed and in another lane", which stopped being true when PR 11104 landed, and now says "a driver can under-report a composite key". The `lower bound` and `no authorable key` assertions beside them are unchanged. - `external-object-draft-authorised-shape.test.ts:151` pins the comment line "Preserved as a COMMENT because 'ServiceObject' has no authorable key for a", which this PR leaves byte-identical. Every re-pinned case was run with the verbose reporter and is listed as passed. ## Tests All through `scripts/pm/os-verify-lock.sh`, every verdict `VERDICT command-exit 0`: - Build: `turbo run build` over the closure of the two packages and `@objectstack/cli` (59/59), then, after merging `origin/main`, `turbo run build --filter=./packages/* --filter=./packages/*/*` (71/71). - At the merged head `7740c0f0`: `@objectstack/service-datasource` 35 files, 707 tests passed; `@objectstack/plugin-approvals` 53 files, 824 tests passed. - `typecheck` for both, including `check:test-typecheck: OK` for `plugin-approvals`. ## Gates - `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands` (no paths) at `7740c0f0` (18 paths vs merge base `222ecc27`): 72 commands, run one at a time from the worktree, each exit code recorded before any pipe. `--ran`: "72 derived famil(ies) accounted for — 72 run, 0 NOT-MEASURED (a DERIVED zero — all 72 recorded an exit code and none of them is 3)". - `check:i18n`: "all bundles in sync, no undeclared authoring keys"; `check:i18n-stale-fill`: "no new stale fills, 0 baselined"; `check:issue-citations`: "no issue citations added against 222ecc2 (12 file(s) read)"; `check:nul-bytes`: OK, 9637 files; `check:type-check-debt`: "none above its recorded number"; `check:dual-build-cjs-loads`: 105 require entry points across 66 packages load; `check:dts-closure`: 71 built packages, 167/167; `check:sourcemap-no-sources-content`: 68 packages, 522 maps. - Outside the derived set, all exit 0: the eleven declared wide-population families (`check:init-service-contract`, `check:live-db-isolation`, `check:meta-type-normalized`, `check:optional-error-sink`, `check:resume-authority-declared`, `check:route-envelope`, `check:runner-env-posture`, `check:settings-bind-window`, `check:startup-registry-verdict`, `check:verify-stand-in`, `check:wildcard-fallthrough`) and the artifact-roster families whose roster sits under one of this PR's directories (`check-changeset-fixed`, `check-published-list-mirrors` and its self-test, `check:authz-resolver`, `check:console-injection`, `check:error-code-casing`, `check:filter-alias-parity`, `check:published-readme-exports`, `check-dts-references --self-test`; `check:engine-double-contract` and `check:i18n-stale-fill` are already in the derived set). The path-scheduled CI jobs and the type-check lanes are CI's. - `pnpm lint` (`eslint . --no-inline-config`, repo-wide, not narrowed) at `7740c0f0`: exit 0, 146 s under the lock. ## Acceptance notes Noted, not filed: - `docs/qa/platform-checklist/areas/approvals.json:1249` quotes the `queue` warning with its old tracker suffix. The part it quotes before the suffix survives verbatim in the new text, so a runner still finds the warning; the file is outside this stage's surface. Carrier: none. - `external-object-draft-primary-key.test.ts` keeps a docblock (lines 63 to 67) saying 10997 is a separate, unfixed defect in the engine lane. It is a comment above the fixture, outside the ledger; this PR changes only the title and assertion of the test that pins the caveat. Carrier: none. - `packages/lint/src/validate-approval-approvers.ts:463` carries the same `queue` citation in its lint message, and its test pins the id. `packages/lint` is outside this lane's ledger share. --- _Generated by [Claude Code](https://claude.ai/code/session_01DiCSbmJrkzNhuEAier4VoJ)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 1878ef9 commit f9bcd08

18 files changed

Lines changed: 66 additions & 96 deletions
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
---
2+
'@objectstack/service-datasource': patch
3+
'@objectstack/plugin-approvals': patch
4+
---
5+
6+
Datasource and approval refusals, warnings, field help and generated-draft comments no longer cite tracker numbers; each one states the decision behind it in words
7+
8+
Clause-②: no
9+
10+
Some strings these two packages show to operators, administrators and flow authors pointed at an issue-tracker number for the reason behind them. The number goes; where the sentence did not already say what was decided, it now does.
11+
12+
- `@objectstack/service-datasource`: the credential-migration refusal says an unbindable key is either an alias spelling from before inline credentials were refused at publish, which no connection builder reads, or turso's `encryptionKey`, which has no secret slot of its own because the one slot carries the `authToken`; the remote-primary-key comment in a generated object draft says a driver's introspection can report only the first column of a composite key, so the list is a lower bound.
13+
- `@objectstack/plugin-approvals`: the `queue` approver warning says the platform has no ownership queue to expand the type from, that the type is no longer offered for authoring, and to route the step to a team, department or position instead; the live-record warnings say approvers are being resolved against the trigger snapshot instead of the live record they are normally resolved from; the recall refusal's log line names the admin override; the `sys_approval_action` `via_override` help (in every shipped locale) says a platform or organization admin may act on any pending request, so that one nobody in its slate can decide never stays stuck; the cross-organization team, team-member and manager warnings, the expanded-to-nobody warning, the revise-window refusal, the `attachments` help and the `sys_approval_delegation` description drop their citations.
14+
15+
Text only: no status, error code, field, route or control flow moves. A client or log filter that matches the old text (for example a tracker-number suffix) needs the new spelling.

‎packages/plugins/plugin-approvals/src/approval-service.test.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3162,7 +3162,7 @@ describe('ApprovalService — queue approver is unresolved (#3508)', () => {
31623162
// No queue expansion exists: the slot is the raw `type:value` literal,
31633163
// which matches no real user id — the request routes to nobody.
31643164
expect(req.pending_approvers).toEqual(['queue:q_west']);
3165-
expect(warnings.some(([msg]) => String(msg).includes("'queue'") && String(msg).includes('#3508'))).toBe(true);
3165+
expect(warnings.some(([msg]) => String(msg).includes("'queue'") && String(msg).includes('no ownership queue to expand it from'))).toBe(true);
31663166
});
31673167
});
31683168

@@ -3215,7 +3215,7 @@ describe('ApprovalService — a graph approver that expands to nobody warns (#38
32153215
expect(req.pending_approvers).toEqual([`${type}:${value}`]);
32163216
const hit = warnings.find(([msg]) => String(msg).includes('expanded to nobody'));
32173217
expect(hit, `no warning for ${type}`).toBeTruthy();
3218-
expect(String(hit[0])).toContain('#3807');
3218+
expect(String(hit[0])).toContain('cannot advance until someone is added or the approver is re-pointed');
32193219
expect(hit[1]).toMatchObject({ type, value, organizationId: 't1' });
32203220
});
32213221

‎packages/plugins/plugin-approvals/src/approval-service.ts‎

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1762,7 +1762,9 @@ export class ApprovalService implements IApprovalService {
17621762
// least visible to operators.
17631763
if (type === 'queue') {
17641764
this.logger?.warn?.(
1765-
`[approvals] approver type 'queue' is not implemented — the slot resolves to nobody (#3508)`,
1765+
`[approvals] approver type 'queue' is not implemented — the slot resolves to nobody, because the `
1766+
+ `platform has no ownership queue to expand it from (the type is deprecated and no longer offered `
1767+
+ `for authoring). Route this step to a team, department or position instead.`,
17661768
{ value: a.value },
17671769
);
17681770
} else if (GRAPH_APPROVER_TYPES.has(type)) {
@@ -1777,7 +1779,7 @@ export class ApprovalService implements IApprovalService {
17771779
// stops being invisible.
17781780
this.logger?.warn?.(
17791781
`[approvals] approver '${type}:${a.value}' expanded to nobody — the slot routes to no one `
1780-
+ `and the request cannot advance until someone is added or the approver is re-pointed (#3807)`,
1782+
+ `and the request cannot advance until someone is added or the approver is re-pointed`,
17811783
{ type, value: a.value, organizationId: organizationId ?? null },
17821784
);
17831785
}
@@ -2039,7 +2041,7 @@ export class ApprovalService implements IApprovalService {
20392041
if (!teamOrg) return false; // no tenancy fact on this team
20402042
if (teamOrg === requestOrg) return false; // it is this org's team — route as before
20412043
this.logger?.warn?.(
2042-
`[approvals] #10230: team '${teamId}' was dropped from the approver slate — `
2044+
`[approvals] team '${teamId}' was dropped from the approver slate — `
20432045
+ `'sys_team.organization_id' is '${teamOrg}', not the request's organization `
20442046
+ `'${requestOrg}', so routing this approval to its members would put approval `
20452047
+ `authority over the record outside its tenant. Point the approver at a team in `
@@ -2108,7 +2110,7 @@ export class ApprovalService implements IApprovalService {
21082110
if ((rows?.length ?? 0) >= MEMBER_SCREEN_READ_LIMIT) {
21092111
// Possibly truncated ⇒ the evidence is incomplete ⇒ no evidence.
21102112
this.logger?.warn?.(
2111-
`[approvals] #10547: the membership screen for team '${teamId}' read `
2113+
`[approvals] the membership screen for team '${teamId}' read `
21122114
+ `${rows.length} 'sys_member' rows, at or above its ${MEMBER_SCREEN_READ_LIMIT}-row `
21132115
+ `cap, so the result may be truncated. Routing is left unchanged rather than risk `
21142116
+ `dropping a member whose proof of membership fell outside the read.`,
@@ -2134,7 +2136,7 @@ export class ApprovalService implements IApprovalService {
21342136
}
21352137
if (dropped.length) {
21362138
this.logger?.warn?.(
2137-
`[approvals] #10547: ${dropped.length} member(s) of team '${teamId}' were dropped from `
2139+
`[approvals] ${dropped.length} member(s) of team '${teamId}' were dropped from `
21382140
+ `the approver slate — ${dropped.map(d => `'${d.userId}'`).join(', ')} hold membership `
21392141
+ `in other organization(s), none of them the request's organization '${requestOrg}', so `
21402142
+ `routing this approval to them would put approval authority over the record outside its `
@@ -2469,7 +2471,7 @@ export class ApprovalService implements IApprovalService {
24692471
if (!orgs.length) return false; // no tenancy fact recorded for this user
24702472
if (orgs.includes(requestOrg)) return false; // he is a member here — route as before
24712473
this.logger?.warn?.(
2472-
`[approvals] #10153: manager '${managerId}' was dropped from the approver slate — `
2474+
`[approvals] manager '${managerId}' was dropped from the approver slate — `
24732475
+ `'sys_user.manager_id' points across an organization boundary. He holds membership in `
24742476
+ `${orgs.length} organization(s), none of them the request's organization '${requestOrg}', `
24752477
+ `so routing this approval to him would put approval authority over the record outside its `
@@ -2624,13 +2626,15 @@ export class ApprovalService implements IApprovalService {
26242626
if (live) return live;
26252627
this.logger?.warn?.(
26262628
`[approvals] live record ${object}/${recordId} not found at node entry — `
2627-
+ 'resolving approvers against the trigger snapshot (#3447 fallback).',
2629+
+ 'resolving approvers against the trigger snapshot instead of the live record they are '
2630+
+ 'normally resolved from.',
26282631
{ object, recordId },
26292632
);
26302633
} catch (err: any) {
26312634
this.logger?.warn?.(
26322635
`[approvals] live record re-read failed for ${object}/${recordId}: ${err?.message ?? err} — `
2633-
+ 'resolving approvers against the trigger snapshot (#3447 fallback).',
2636+
+ 'resolving approvers against the trigger snapshot instead of the live record they are '
2637+
+ 'normally resolved from.',
26342638
);
26352639
}
26362640
return fallback ?? {};
@@ -3662,7 +3666,7 @@ export class ApprovalService implements IApprovalService {
36623666
// id), kept where a developer reads them and a user never does.
36633667
const developerMessage =
36643668
`[approvals] recall refused: actor '${actorId}' is not the submitter of request `
3665-
+ `'${requestId}' (submitter '${String(raw.submitter_id)}') and holds no #3424 override `
3669+
+ `'${requestId}' (submitter '${String(raw.submitter_id)}') and holds no admin override `
36663670
+ `for a '${raw.status}' request (the override reaches pending requests only)`;
36673671
this.logger?.warn?.(developerMessage, {
36683672
request: requestId,
@@ -4238,7 +4242,7 @@ export class ApprovalService implements IApprovalService {
42384242
(targetType === undefined ? ' which the flow does not declare' : ` of type '${targetType || '(untyped)'}'`) +
42394243
`, but the revise window must be an '${APPROVAL_REVISE_NODE_TYPE}' node — that pause continues only ` +
42404244
'through this service (submitter-only, audited, and refusing a colliding pending request), and any ' +
4241-
`other node type there is resumable by anyone with the run id (amended ADR-0044, #3823). Fix the flow: ` +
4245+
`other node type there is resumable by anyone with the run id (amended ADR-0044). Fix the flow: ` +
42424246
`set node '${target || '<revise target>'}' to type '${APPROVAL_REVISE_NODE_TYPE}'.`,
42434247
);
42444248
}

‎packages/plugins/plugin-approvals/src/sys-approval-action.object.ts‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -162,8 +162,9 @@ export const SysApprovalAction = ObjectSchema.create({
162162
required: false,
163163
group: 'Action',
164164
description:
165-
'True when the actor was admitted to this action only by the privileged-override path (#3424) — '
166-
+ 'they held no slot in the request’s pending-approver slate.',
165+
'True when the actor held no slot in the request’s pending-approver slate and was admitted to '
166+
+ 'this action only by the privileged override, which lets a platform or organization admin act '
167+
+ 'on any pending request so that one nobody in its slate can decide never stays stuck.',
167168
}),
168169

169170
// Structured hand-off parties for `action: 'reassign'` (#4365). Before
@@ -190,7 +191,7 @@ export const SysApprovalAction = ObjectSchema.create({
190191
required: false,
191192
multiple: true,
192193
group: 'Action',
193-
description: 'Files supporting this action — e.g. a signed contract or evidence (#3266).',
194+
description: 'Files supporting this action — e.g. a signed contract or evidence.',
194195
}),
195196

196197
created_at: Field.datetime({

‎packages/plugins/plugin-approvals/src/sys-approval-delegation.object.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ export const SysApprovalDelegation = ObjectSchema.create({
4040
// needed — RLS/permission sets are the authz.
4141
managedBy: 'system-data',
4242
description:
43-
'Self-service out-of-office rule: route this user\'s approver slots to a delegate within a time window (#1322 M1).',
43+
'Self-service out-of-office rule: route this user\'s approver slots to a delegate within a time window.',
4444
// [ADR-0079] The record title is `display_title`, a text formula over the
4545
// same two columns `titleFormat` names. With no pointer declared, the
4646
// registry's designate-only pass stamped `nameField: 'id'` (the first

‎packages/plugins/plugin-approvals/src/team-approver-org-screen.test.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -218,9 +218,9 @@ describe('#10230 team approver org screen', () => {
218218
expect(engine._reads.filter(r => r === 'sys_team')).toEqual([]);
219219
});
220220

221-
it('T7 — the drop is loud: the warning names the team, both organizations and the card', async () => {
221+
it('T7 — the drop is loud: the warning names the team and both organizations', async () => {
222222
await svc.openNodeRequest(input([TEAM_B]), CTX_A);
223-
const hit = warnings.find(([msg]) => String(msg).includes('#10230'));
223+
const hit = warnings.find(([msg]) => String(msg).includes("team 'team_b' was dropped from the approver slate"));
224224
console.log('[PROBE T7] warning =', hit ? String(hit[0]).slice(0, 90) : 'NONE');
225225
expect(hit).toBeTruthy();
226226
expect(hit![1]).toMatchObject({

‎packages/plugins/plugin-approvals/src/team-member-org-screen.test.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -245,9 +245,9 @@ describe('#10547 team MEMBER org screen', () => {
245245
expect(req.pending_approvers).toEqual(['u0', 'u1', 'u2', 'u3', 'u4']);
246246
});
247247

248-
it('M9 — the drop is loud: the warning names the users, both organizations and the card', async () => {
248+
it('M9 — the drop is loud: the warning names the users and both organizations', async () => {
249249
await svc.openNodeRequest(input([TEAM_A]), CTX_A);
250-
const hit = warnings.find(([msg]) => String(msg).includes('#10547'));
250+
const hit = warnings.find(([msg]) => String(msg).includes("member(s) of team 'team_a' were dropped from the approver slate"));
251251
console.log('[PROBE M9] warning =', hit ? String(hit[0]).slice(0, 100) : 'NONE');
252252
expect(hit).toBeTruthy();
253253
expect(String(hit![0])).toContain(ORG_A);

‎packages/plugins/plugin-approvals/src/translations/en.objects.generated.ts‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ export const enObjects: NonNullable<TranslationData['objects']> = {
260260
},
261261
via_override: {
262262
label: "Via Admin Override",
263-
help: "True when the actor was admitted to this action only by the privileged-override path (#3424) — they held no slot in the request’s pending-approver slate."
263+
help: "True when the actor held no slot in the request’s pending-approver slate and was admitted to this action only by the privileged override, which lets a platform or organization admin act on any pending request so that one nobody in its slate can decide never stays stuck."
264264
},
265265
reassign_from: {
266266
label: "Reassigned From",
@@ -272,7 +272,7 @@ export const enObjects: NonNullable<TranslationData['objects']> = {
272272
},
273273
attachments: {
274274
label: "Attachments",
275-
help: "Files supporting this action — e.g. a signed contract or evidence (#3266)."
275+
help: "Files supporting this action — e.g. a signed contract or evidence."
276276
},
277277
created_at: {
278278
label: "Created At"
@@ -297,7 +297,7 @@ export const enObjects: NonNullable<TranslationData['objects']> = {
297297
sys_approval_delegation: {
298298
label: "Approval Delegation",
299299
pluralLabel: "Approval Delegations",
300-
description: "Self-service out-of-office rule: route this user's approver slots to a delegate within a time window (#1322 M1).",
300+
description: "Self-service out-of-office rule: route this user's approver slots to a delegate within a time window.",
301301
fields: {
302302
id: {
303303
label: "Delegation ID"

‎packages/plugins/plugin-approvals/src/translations/es-ES.objects.generated.ts‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ export const esESObjects: NonNullable<TranslationData['objects']> = {
260260
},
261261
via_override: {
262262
label: "Mediante anulación de administrador",
263-
help: "Verdadero cuando el actor fue admitido en esta acción únicamente por la vía de anulación privilegiada (#3424): no ocupaba ningún puesto en la lista de aprobadores pendientes de la solicitud."
263+
help: "Verdadero cuando el actor no ocupaba ningún puesto en la lista de aprobadores pendientes de la solicitud y fue admitido en esta acción únicamente por la anulación privilegiada, que permite a un administrador de la plataforma o de la organización actuar sobre cualquier solicitud pendiente para que una que nadie de su lista puede decidir nunca quede bloqueada."
264264
},
265265
reassign_from: {
266266
label: "Reasignado de",
@@ -272,7 +272,7 @@ export const esESObjects: NonNullable<TranslationData['objects']> = {
272272
},
273273
attachments: {
274274
label: "Adjuntos",
275-
help: "Archivos que respaldan esta acción, p. ej. un contrato firmado o pruebas (#3266)."
275+
help: "Archivos que respaldan esta acción, p. ej. un contrato firmado o pruebas."
276276
},
277277
created_at: {
278278
label: "Creado el"
@@ -297,7 +297,7 @@ export const esESObjects: NonNullable<TranslationData['objects']> = {
297297
sys_approval_delegation: {
298298
label: "Approval Delegation",
299299
pluralLabel: "Approval Delegations",
300-
description: "Self-service out-of-office rule: route this user's approver slots to a delegate within a time window (#1322 M1).",
300+
description: "Self-service out-of-office rule: route this user's approver slots to a delegate within a time window.",
301301
fields: {
302302
id: {
303303
label: "Delegation ID"

‎packages/plugins/plugin-approvals/src/translations/es-ES.source-hashes.generated.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export const esESGeneratedSourceHashes: Readonly<Record<string, string>> = {
2222
"objects.sys_approval_delegation._views.active.emptyState.message": "1095d61c017b6db2",
2323
"objects.sys_approval_delegation._views.active.emptyState.title": "799d28e51d88963e",
2424
"objects.sys_approval_delegation._views.active.label": "eee107cf4e466779",
25-
"objects.sys_approval_delegation.description": "432b0435aa15f6b9",
25+
"objects.sys_approval_delegation.description": "517790acf02a372d",
2626
"objects.sys_approval_delegation.fields.created_at.label": "1f02d416befb595b",
2727
"objects.sys_approval_delegation.fields.delegate_id.help": "9cfc641f7b0b04f9",
2828
"objects.sys_approval_delegation.fields.delegate_id.label": "afd6d8733dc5bc14",

0 commit comments

Comments
 (0)