Repository navigation
fix(plugin-audit): declare sys_activity.type 'scheduled' and record its writer - #11522
Conversation
…ts writer A shipped app action writes the value today — hotcrm's `schedule_meeting` action, registered on all five CRM record types, inserts `type: EVENT_STATUS === 'held' ? 'completed' : 'scheduled'` and its spec declares `eventStatus: 'planned'`, so it always takes the `scheduled` branch. Nothing accepts or rejects differently: every `sys_activity` field is `readonly: true` and `validateRecord` skips readonly fields on both the insert and the update branch, so the `invalid_option` check never runs for one. The declaration now names a value the platform already stores, the writer census records the writer, and the four generated locale bundles carry the label. Part of #11424 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01APWX2AwT3a4xDcjPCe8bk4
📓 Docs Drift CheckThis PR changes 1 package(s): 3 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 2 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 7 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 89daae467a8fad0c671ff4469fba084c6b2c46ce && git checkout 89daae467a8fad0c671ff4469fba084c6b2c46ce
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin daacc1071c69604976796f92d39448117b3b4990 980a96661de02abf94be1f64a4cecb4b08abbabf && git checkout -B drift-repro daacc1071c69604976796f92d39448117b3b4990 && git merge --no-ff 980a96661de02abf94be1f64a4cecb4b08abbabf
node scripts/docs-audit/affected-docs.mjs --json daacc1071c69604976796f92d39448117b3b4990
|
Part of #11424 — direction 1 only, and nothing else from that card.
What changed
packages/plugins/plugin-audit/src/objects/sys-activity.object.tsscheduledadded to thetypeselect's declared options, placed next tocompleted— the value it alternates with at the writerpackages/plugins/plugin-audit/src/objects/sys-activity-type-vocabulary.test.tsTYPES_WITH_WRITERSrow the census pin demands for any newly declared value, plus two bounded corrections (below)src/translations/{en,zh-CN,ja-JP,es-ES}.objects.generated.tsenleaves translated by hand (已安排/予定/Programado).changeset/sys-activity-declares-scheduled.md@objectstack/plugin-auditNothing accepts or rejects differently
Every field on
sys_activityisreadonly: true, andvalidateRecordskipsreadonly fields on both branches —
record-validator.tsL1023 (insert) andL1033 (update) are the same
if (def.system || def.readonly) continue;— so theinvalid_optioncheck that enforces a select field's declared options never runsfor one. Read in the source, not taken on trust, and then measured:
With
scheduledadded to the enum and nothing else changed, the package'sfull suite moved by exactly one assertion, and it was the census pin:
activity-type-vocabulary-enforcement.test.ts— the behavioural half, whichinserts an undeclared value into this very column and asserts it lands, against a
control object that differs only by not being
readonly— stayed green throughthat run. That is the mechanism above, observed from both sides: the behaviour
could not see this change, and only the literal inventory could.
The writer, verified rather than transcribed
The census file's own rule is that a
TYPES_WITH_WRITERSrow is a claim a writerexists at the named location, so the row was read out of the producer at
objectstack-ai/hotcrm5eee1bd(read-only clone), not copied from the card:src/actions/global.actions.ts:349—type: EVENT_STATUS === 'held' ? 'completed' : 'scheduled'SCHEDULE_MEETING_SPECdeclareseventStatus: 'planned'(L489-497), so theschedule_meetingaction always takes thescheduledbranchcrm_lead/crm_contact/crm_account/crm_opportunity/crm_caseviaactivityActionFor()(L545-567)Two bounded corrections in the same file
Both are documentation in the file the card already required editing, both are
mechanical, and both are named here rather than left to be discovered:
completedhas a second writer. The same sweep foundhotcrm src/actions/contact.actions.ts:165insertingtype: 'completed'fromthe
send_emailbody. Its census row now says so. No assertion changes.typeenum" losesthe count (it would rot again); "its key set is set-equal to this enum today",
about objectui's feed-kind map, is past-tensed to the [观察] A
selectfield's option enum is unenforceable once the field isreadonly—sys_audit_log.actiondeclares a vocabulary nothing can check #8203 census andannotated with record:activity drops every
sys_activity.type: "scheduled"row, and 10 of FeedItemType's 13 kinds have no producer at all objectui#5840 as the reason it moved —attributed to that card, explicitly not measured here, since this package
still cannot import objectui. The set-equality pin itself is untouched from
this side.
A third note records that the census's in-repo sweep has a second half it cannot
see: an app's server-side action reaches this column directly through
ctx.api.object('sys_activity').insert(...), which no grep of this repositoryfinds. That is recorded as a fact about where to look, and takes no position.
Measured at
980a966(the commit at the head of this branch)pnpm --filter @objectstack/plugin-audit test— 19 files, 314 passed (313 before; the censusit.eachgrew by one case)pnpm --filter @objectstack/plugin-audit typecheck—tsc --noEmit, cleanpnpm --filter '@objectstack/plugin-audit^...' build— dependency closure built first, so the suite ran against freshdistexit=0:check:nul-bytes,check:empty-changeset,check:cross-package-test-inputs,check:published-files,check:slot-lookup,check:test-source-alias,check:type-source-resolution,check-ci-filter-parity,check-plugin-teardown-shape,docs-audit/check-affected-docs,check:query-options-erasure,check:type-check-coverage,check:engine-double-contract,check:where-matcher— the ratchet family re-run at this commit on a clean tree--no-inline-config: 6.tsfiles linted, 0 errors; the 7th is the changeset.md, which the config does not matchNot measured here
check:i18n— NOT MEASURED, its own verdict:check-i18n-bundles: PREREQUISITE NOT MET — the workspace CLI is not built. It runs the built CLI; building that closure locally is CI's run. What is known instead: the gate takes its flags from the config's own docstring (flagsFromDocstring), and the bundles here were regenerated by that same extractor with that same documented command throughpackages/cli/bin/run-dev.js(the source entry the repo's gates use precisely so they do not depend onpackages/cli/dist), which reported✓ Generated 4 file(s). The resulting diff is four single-line insertions, one per bundle, all inside thesys_activity.typeoptions block. The untested delta isdistvs source entry into one command.check:type-check-debt— needs the whole workspace built; not run. The substance for this diff is the package's owntsc --noEmit, which is green.eslint.config.mjswhich never enables type-aware linting for any file (eslint.config.mjs:326-332, with its own recorded positive control), so this diff cannot move a verdict on a file it does not touch — but the population was not enumerated locally, so treat that as a narrowing CI closes, not a proof.Still open
Direction 1 is the whole of this PR. The card records four directions, and the
vocabulary question behind them — closed platform vocabulary or author-extensible
one — is a maintainer call that nothing here decides in either direction.
#11424 remains open.
Generated by Claude Code