Commit cc07862
fix(automation, audit): runtime strings state each decision in words instead of a tracker number (stage 4) (#21472)
Part of #20751
Clause-②: no
**Stage 4 of the `domain:services` lane under the maintainer's A / A
ruling (5902360492): the `service-automation` and `plugin-audit`
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 10 of 10
changed sources, below).
## What this does
The two packages' refusals, prescriptions, warnings, log lines, the
`sys_automation_run` / `sys_flow_dispatch` field help and description,
and the `sys_activity` `type` help (with its `es-ES`, `ja-JP` and
`zh-CN` leaves) sent the reader to a tracker number for the reason
behind them. In form D, as stages 1 to 3 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 38 ledgered occurrences in this stage's surface (claim
`5959898258`), re-derived from the ledger on `origin/main` at
`9b7a0ef3`: `service-automation` 33 (25 pairs, 9 files), `plugin-audit`
5 (5 pairs, 5 files: `objects/sys-activity.object.ts` and its four
`translations/*.objects.generated.ts`). They sit in 37 string sites. The
sixth `plugin-audit` ledger entry, `audit-writers.ts` (one occurrence),
is in a file excluded at file level (open PR #21436) and stays for a
later stage. None of the three excluded files (`audit-writers.ts`,
`stored-metadata-body-migration.ts`,
`stored-metadata-hash-migration.test.ts`) is touched.
### Rewritten in words
Author- and administrator-visible text first, log lines last. Line
numbers are at the head.
| Where | Cited | The text now says | Decision read from |
|---|---|---|---|
| `engine.ts:196-205`, the `fieldValues` refusal prescriptions on
`create_record` and `update_record` | 2419 | "a runtime alias for it was
rejected by design: the node keeps one strict `fields` key rather than
two spellings" | 2419 is a pull request that proposed a `cfg.fields ??
cfg.fieldValues` alias in the executor; the design review declined it:
correct the metadata at the source and keep a single strict
`config.fields` contract |
| `engine.ts:210-213`, the screen field `visibleIf` refusal prescription
| 3528 | "A predicate under any other key is never read, so the field
always shows — and a `required` field meant to stay hidden then blocks
the screen from ever being submitted" | the card's root cause: a field
visibility predicate never reached the client, so a `required` field the
author meant to hide rendered unconditionally and the screen flow could
not be submitted; `visibleWhen` went into the contract and is forwarded
verbatim |
| `engine.ts:10272-10274`, the undeclared-config-key refusal | 4045 |
"the built-in node types were reconciled so every key their executors
read is declared, and a read-but-undeclared key is exactly the drift
that reconciliation removed" | 4045's closing: every built-in node
publishing a `configSchema` got a Zod written from its executor and a
two-way key-set reconciliation (CRUD, screen and map surfaced seven
read-but-undeclared keys, all declared) |
| `builtin/template.ts:192`, the unknown value-expression function error
| 11060 | "An unknown function is refused here rather than evaluated to
null, which would write the field as undefined" | the maintainer's
ruling (option A): six functions mirrored 1:1 from CEL, and the silent
`null` rewrite of an unknown function name became a loud, named error |
| `sys-automation-run.object.ts:169`, `node_type` help | 3801 | "Keys
the resume authorization gate, which decides from the paused node's type
who may continue the run (an approval pause only through its owning
service)" | the card's requirement, as `refuseGatedResume` enforces it:
the gate is keyed on what the run is parked on; an `approval` pause
continues only through `ApprovalService`, while a `screen` pause stays
open to its flow runner |
| `sys-automation-run.object.ts:234` `trigger_type` and `:288`
`trigger_record_id` help | 7533 | "rows written before run history
recorded its trigger (they were not backfilled)" | the card's ACCEPT:
trigger columns written on terminal and paused rows; pre-existing rows
carry none and rehydrate as "not recorded"; no backfill |
| `sys-automation-run.object.ts:324`, `steps_json` help | 2585 | "the
bounded per-node step log, so a finished run's per-node detail survives
a restart" | item 3 of the card: durable single-run detail, a bounded
step log persisted on terminal rows so a past run's detail survives a
restart |
| `plugin-audit` `objects/sys-activity.object.ts:116-121`, `type` help,
and its four locale leaves | 11507 | "Consumers must render an unknown
value instead of assuming this list is exhaustive: the vocabulary is
open by decision, not a gap awaiting enforcement." | the maintainer's
ruling (direction 4): the column is an open, author-extensible
vocabulary, the declaration must say so, and every closed map over it is
the bug |
| `plugin.ts:1680-1689`, the inert-connector warning | 2612, 2977 |
"entries without a `provider` are catalog descriptors (descriptor-only
contract) ... An entry that names a `provider` is a connector instance
instead: that provider's installed executor materializes it into a live
connector (ADR-0097)" | 2612's resolution (descriptor-only contract,
boot audit warning, `enabled: false` marks a catalog-only entry) and
2977's (ADR-0097 implemented: a provider-bound entry is materialized at
boot by a generic executor). The old sentence said provider-bound
instances were "tracked in" 2977, which has since landed;
`findInertDeclaredConnectors` already skips provider-bound entries,
which the new wording now says |
| `plugin.ts:1143-1146`, debug | 1928 | "(flow conditions are checked
against object fields at registration)" | 1928's closing: schema-aware
condition validation at `registerFlow` through an opt-in object-schema
resolver |
| `plugin.ts:1184-1187`, debug | 3356 | "(a user-mode run carries the
triggering user's positions and permission sets)" | 3356's resolution:
`runAs:'user'` resolves the triggering user's positions and permission
sets at run setup |
| `plugin.ts:1214-1217`, debug | 3475 | "(a lookup the start node
declares in expand is read with the run's own identity)" | 3475's plan
as landed: opt-in start-node `config.expand`, expanded engine-side as
the run's own identity so the referenced object's RLS/FLS holds |
### Citation only (the sentence already stated the decision)
- `builtin/connector-nodes.ts:72` (3017, "Dispatch is unavailable until
its upstream recovers; the platform retries automatically." — ADR-0097
quotes "the platform retries automatically", which stays verbatim).
- `builtin/parse-config.ts:112` (4277, "config does not satisfy the X
contract ... The declared contract is the node type's configSchema (the
Studio form) and the X config Zod").
- `builtin/screen-nodes.ts:336` (1870, "no function named 'X' is
registered. Register it via `defineStack({ functions })`, or fix the
name").
- `engine.ts:181`, `:184`, `:187`, `:191`, the bulk-intent guidance
(5393, "Bulk intent is `multi: true` ... so the concept keeps one name
from node config to driver call ... a predicate write is refused by the
engine rather than silently widened"; "Translating that declaration into
`options.multi` on the engine call is the executor's job").
- `engine.ts:4026` (3017, "the materializer retries with backoff").
- `engine.ts:6069`, `:6073` (3760, 1888: "its data operations will be
REFUSED ... Declare runAs:'system' ... a record-change flow fired by a
system write carries no user either (ADR-0049)").
- `engine.ts:10268` (4277, "Flow 'X' rejected: N undeclared config
key(s)").
- `engine.ts:11326` (4414, "The branch selection is IGNORED and every
out-edge is evaluated instead ... mark the fallback edge `isDefault:
true`").
- `runtime-identity.ts:113`, the `AUTOMATION_UNSCOPED_RUN_DATA_ACCESS`
refusal (1888, 3760: "refusing a data operation ... would execute
UNSCOPED ... Declare `runAs: 'system'`"; it keeps "(ADR-0049)"). Its
`code` is unchanged.
- `plugin.ts:1831`, `:2074`, `:2086`, `:2143` (3017: "pending retry
cancelled", "until a retry succeeds", "retrying with backoff, attempt
N", "next retry in Nms").
- `sys-flow-dispatch.object.ts:86` (10220, "one row per claimed dispatch
key ... so a re-scan, a rebuilt kernel or an operator replay never
re-launches a flow for a window it already delivered").
Every cited card (21: 1870, 1888, 1928, 2419, 2585, 2612, 2977, 3017,
3356, 3475, 3528, 3760, 3801, 4045, 4277, 4414, 5393, 7533, 10220,
11060, 11507) was read through REST, body and every comment, before its
string was rewritten. 2419 is a pull request; its closing comment
carries the decision. 11060 and 11507 answer 404 on the issue endpoint
while their comment threads read normally; the rulings and dev reports
in those threads carry the decisions.
### Translations
- The `es-ES`, `ja-JP` and `zh-CN` `sys_activity.fields.type.help`
leaves were byte copies of the English source, recorded as such in each
locale's `*.source-hashes.generated.ts`. No translated text was written
by hand: the three leaf values were emptied (key kept) and `node
scripts/check-i18n-bundles.mjs --write --filter=plugin-audit` (the
extract config's documented command, `--fill=default`) refilled them
from the revised source, rewrote `en`, and recorded the three new
digests. The same route the original ruling's PR took for these leaves.
- All four leaves are byte-equal to the revised source description (440
characters each, checked against the string reassembled from
`sys-activity.object.ts`). Tracker numbers left in the package's locale
bundles: 0.
## Ledger (`scripts/doc-authoring-prose-id.baseline.json`)
At dispatch no open PR held this file. While this branch was being
built, PR #21462 (`domain:spec` stage 1 of #20749) opened and took it,
so this PR waited: the branch was finished and green, and it was opened
only after #21462 merged (`7e7e64b1`, about 40 minutes of waiting). Then
`origin/main` at `7e7e64b1` was merged in (no rebase), and the ledger
was recomputed on that tree with `node scripts/check-doc-authoring.mjs
--census-ledger` (exit 0, no growth refusal) into a scratch file. The
recomputed file is byte-identical to git's textual merge of the two
sides. Against `main` the diff deletes 58 lines and adds none: exactly
the 14 file blocks of this stage. Every other row is unchanged (a
scripted comparison: 14 keys moved, all of them this stage's, each to
absent). At PR-open time no other open PR touches the file.
| | before | after |
|---|---|---|
| `service-automation` | 33 occurrences, 25 pairs, 9 files | 0 |
| `plugin-audit` | 6 occurrences, 6 pairs, 6 files | 1 occurrence, 1
pair, 1 file (`audit-writers.ts`, excluded) |
| whole ledger, on the tree first derived (`9b7a0ef3`) | 227
occurrences, 157 pairs, 62 files | 189, 127, 48 |
| whole ledger, after `#21462` (`7e7e64b1`) | 174 occurrences, 127
pairs, 53 files | 136, 97, 39 |
`pnpm check:doc-authoring` at the head: "sibling-package prose ids hold
the baseline — 118 pinned site(s) across 39 file(s), 86309 string(s)
read in 1253 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-stage4-state-the-decision.md`:
`patch` for `@objectstack/service-automation` and
`@objectstack/plugin-audit`. Measured after building: the new sentences
are in each package's built output (`service-automation` `dist/index.js`
and `dist/index.cjs`; `plugin-audit` `dist/index.js` and
`dist/index.mjs`). A TypeScript scan of every string literal and
template text in the built output finds 0 tracker ids in
`service-automation`, and 2 in `plugin-audit`, both the excluded
`audit-writers.ts` occurrence (once per build format). Control: the same
scan reads 86 in `plugin-security`'s built output.
## 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. `9b7a0ef3` against the head: 10 of 10 SAME (the
two merges from `origin/main` touched neither package). Controls on
scratch copies of `plugin.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.
## Pins
Assertions that found a message 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.
- `builtin/config-unknown-keys.test.ts:97`: the `visibleIf` prescription
by "blocks the screen from ever being submitted" instead of the id.
- `builtin/decision-branch-routing.test.ts:210`: the unclaimed-branch
warning by "The branch selection is IGNORED" instead of the id.
- `connector-degrade-cause.test.ts:185` and `:274`: the degrade error by
"retrying with backoff, attempt 1." and the husk warning by "stays
absent from the connector registry until a retry succeeds"; the three
hand-built fixture messages in the same file (`:376`, `:396`, `:407`),
which mirror the production text, drop the id too.
- `connector-descriptor-audit.test.ts:134`: the inert-connector warning
by "catalog descriptors (descriptor-only contract)".
- `degraded-register-cause.test.ts:212`: the degraded-registration
warning by "the materializer retries with backoff"; its fixture message
(`:407`) drops the id.
- `plugin-audit` `objects/sys-activity-type-open-vocabulary.test.ts`
asserts the `type` help by three markers (`built-in`, `open vocabulary`,
`ADR-0052`), all kept; no edit needed.
The five edited test files were run with the verbose reporter (5 files,
50 tests passed) and every re-pinned case is listed as passed.
## Tests
All through `scripts/pm/os-verify-lock.sh`, every verdict `VERDICT
command-exit 0`, at the head `f300a255`:
- Build: `turbo run build --filter=./packages/* --filter=./packages/*/*`
(71/71).
- `@objectstack/service-automation`: 166 files, 2053 tests passed;
`@objectstack/plugin-audit`: 38 files, 618 tests passed.
- `typecheck` for both, including `check:test-typecheck: OK` for each.
## Gates
- `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack
--commands` (no paths) at `f300a255` (24 paths vs merge base `7e7e64b1`,
195 changed lines): 74 commands, run one at a time from the worktree,
each exit code recorded before any pipe; 74 exit 0. `--ran`: "74 derived
famil(ies) accounted for — 74 run, 0 NOT-MEASURED (a DERIVED zero — all
74 recorded an exit code and none of them is 3)". The same 74 also ran
green at `1af6bed2`, before the last merge.
- `check:i18n`: "OK (9 package(s) — all bundles in sync, no undeclared
authoring keys)"; `check:i18n-stale-fill`: "OK (10 bundle set(s) — no
new stale fills, 0 baselined)"; `check-issue-citations`: "no issue
citations added against 7e7e64b (17 file(s) read)"; `check:nul-bytes`:
OK, 9807 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, 524 maps;
`check:published-files`: 69 publishable packages.
- Outside the derived set, all exit 0 at `f300a255`: 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 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 `f300a255`: exit 0.
- `origin/main` moved by two commits after the ledger recompute
(`49524f69`, `packages/rest`; `aa463223`, `packages/spec` and
object-grid surfaces). Neither touches the ledger, `service-automation`
or `plugin-audit`; the PR's CI merge ref and the queue carry them.
## Acceptance notes
Noted, not filed:
-
`packages/runtime/src/domains/automation-put-post-error-parity.test.ts`
(lines 57-70, assertion at line 247) and
`automation-register-error-class.test.ts` (lines 87-100, assertion at
line 308) each rebuild the undeclared-config-key refusal in a test fake,
copied from `engine.ts` with both old ids, and assert `toContain` of the
4277 id on their own fake's message. They stay green (the fake is
self-consistent) but no longer mirror the engine's text.
`packages/runtime` is outside this stage's surface. Carrier: none.
- `plugin-audit/src/audit-writers.ts` keeps its one ledgered occurrence
(excluded file, open PR #21436); it is left for a later stage.
- Two `plugin-audit` test files carry the 11507 id in failure-message
text; test files are outside the ledger.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01DiCSbmJrkzNhuEAier4VoJ)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 0557c2f commit cc07862
24 files changed
Lines changed: 83 additions & 112 deletions
File tree
- .changeset
- packages
- plugins/plugin-audit/src
- objects
- translations
- services/service-automation/src
- builtin
- scripts
Lines changed: 15 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
Lines changed: 2 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
117 | 117 | | |
118 | 118 | | |
119 | 119 | | |
120 | | - | |
121 | | - | |
| 120 | + | |
| 121 | + | |
122 | 122 | | |
123 | 123 | | |
124 | 124 | | |
| |||
Lines changed: 1 addition & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
122 | 122 | | |
123 | 123 | | |
124 | 124 | | |
125 | | - | |
| 125 | + | |
126 | 126 | | |
127 | 127 | | |
128 | 128 | | |
| |||
Lines changed: 1 addition & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
122 | 122 | | |
123 | 123 | | |
124 | 124 | | |
125 | | - | |
| 125 | + | |
126 | 126 | | |
127 | 127 | | |
128 | 128 | | |
| |||
Lines changed: 1 addition & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
19 | 19 | | |
20 | 20 | | |
21 | 21 | | |
22 | | - | |
| 22 | + | |
23 | 23 | | |
24 | 24 | | |
25 | 25 | | |
Lines changed: 1 addition & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
122 | 122 | | |
123 | 123 | | |
124 | 124 | | |
125 | | - | |
| 125 | + | |
126 | 126 | | |
127 | 127 | | |
128 | 128 | | |
| |||
Lines changed: 1 addition & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
18 | 18 | | |
19 | 19 | | |
20 | 20 | | |
21 | | - | |
| 21 | + | |
22 | 22 | | |
23 | 23 | | |
Lines changed: 1 addition & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
122 | 122 | | |
123 | 123 | | |
124 | 124 | | |
125 | | - | |
| 125 | + | |
126 | 126 | | |
127 | 127 | | |
128 | 128 | | |
| |||
Lines changed: 1 addition & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
18 | 18 | | |
19 | 19 | | |
20 | 20 | | |
21 | | - | |
| 21 | + | |
22 | 22 | | |
23 | 23 | | |
Lines changed: 1 addition & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
94 | 94 | | |
95 | 95 | | |
96 | 96 | | |
97 | | - | |
| 97 | + | |
98 | 98 | | |
99 | 99 | | |
100 | 100 | | |
| |||
0 commit comments