Repository navigation
docs(changeset): correct pending v18 changesets that later train landings made false, in place (deliberate correction) - #23126
Conversation
…ace to what main does The #19939 value-slot entries listed the date macros, the run user and positions S1 to S5 later made value slots as still read by the single brace; on main only a CRUD filter value reads it. Each list now names that one position, and each supersede clause that quoted the old lists is dropped. The storage-scope entry stops saying stored public files are not touched: the operator sweep rewrites their scope to user. Claude-Session: https://claude.ai/code/session_012uFegdfR6K6uqvLzt7XsdZ Co-authored-by: Claude <noreply@anthropic.com>
…pending entries in place The text-slot entries prescribed computing a date or the run user through a value-slot spelling the value slots now refuse, and listed positions as single-brace that are value slots, text slots or literals on main. The notify entries said its title and message read the single brace; they render double-brace holes. The node-config entry said http interpolates before it parses; it parses as authored. The unmanaged-install entries said no door calls the import and that the copy keeps an authored lock. Each sentence now states main, and every supersede clause that quoted the corrected text is dropped. Claude-Session: https://claude.ai/code/session_012uFegdfR6K6uqvLzt7XsdZ Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012uFegdfR6K6uqvLzt7XsdZ Co-authored-by: Claude <noreply@anthropic.com>
|
Generated by Claude Code |
Contract reviewServed-tier: Read: card #22586 (body and all 12 comments; the dispatching seat's ACCEPT ① Derived judgmentsAccept-set and public-surface changes implied by the diff: none. The file list is 21 rows, every one Invariants measured on base vs post for all 21 files. Frontmatter bump block md5-identical 21/21. The twelve landings the PR cites are all ancestors of Every edited note, every rewritten sentence. Row numbers follow the PR body's table. TRUE: the AFTER text states what Note 1 —
Note 2 —
Note 3 —
Note 4 —
Note 5 — Note 6 — Note 7 — Note 8 — Note 9 — Note 10 —
Note 11 —
Note 12 — Note 13 — Note 14 —
Note 15 —
Note 16 — Note 17 —
Note 18 — Note 19 —
Note 20 —
Note 21 — Cross-references, swept on the post-PR text of all 490 pending files. A phrase sweep (
Check-runs on ② Semver level
③ Boundary flagsDev report
No escalation to the maintainer is owed by this record beyond what the landing rules already reserve: this PR is not governed ( Implemented-by: VERDICT: PASS |
Fixes #22586
Clause-②: no (pending release text only; no accept set or public surface changes)
What this does
Edits 21 pending
.changeset/*.mdfiles in place so that each sentence states whatmaindoes now. Every one of them is unconsumed (.changeset/pre.jsonismode: pre,tag: next, 0 consumed changesets, read onorigin/mainbcebd8409), so whatever they say when the Version Packages PR #21988 (18.0.0-next.0) merges is frozen into every package's CHANGELOG. Today that release would print both the false sentence and the later entry's correction of it.No new changeset, no
CHANGELOG.md, nocontent/docs/releases/, no.changeset/pre.json, no code. Measured on every edited file against basec9b5b24b0: the frontmatter bump block, theClause-②line and the ADR-0087 marker are byte-identical (md5 of the extracted lines), and no control byte is present.check-empty-changesetis red on purpose: DELIBERATE CORRECTIONscripts/check-empty-changeset.mjs(ruling D on #17712) refuses a diff that modifies a changeset present on the merge base. It names two classes with opposite remedies: COLLISION (restore theirs, rename yours) and DELIBERATE CORRECTION ("do NOT restore it -- say so on the PR and get it confirmed; restoring it from the base would put the false sentence back"). This PR is the second class by design, for all 21 files: each file is a pending note whose sentence a later landing on the samenexttrain made false. Nothing here is restored to make the gate green. The gate stays red until the correction is confirmed; the claim on #22586 names that confirmation as an at-tier contract review on the same head.Corrections, per file
BEFORE is the base text, AFTER is this PR's text, and the last column is the landing that made BEFORE false (sha, PR). "This PR" means the sentence quoted text that another row corrects in place, so it would have become false here.
…elides text left unchanged.{$User.PATH}is this body's spelling of the files' own placeholder (the body sanitizer eats angle-bracket fragments); the files keep theirs.22443-storage-scope-public-retired.md:30publicare not touched. They download exactly as they did: …publicdownload exactly as they did: … Their stored file records are rewritten to scopeuserby the one-time operator sweep@objectstack/service-storageexports, which changes no access: the storage key and the bytes stay as they are.96e4be482(#22552), thesys_filescope sweep19939-flow-value-slot-template-dialect-refused.md:21-26{$User.PATH}. The flow CEL scope binds no user. A string whose tokens include one of these is not refused. Text slots (notifytitle/message, a screendescription, …) andfiltervalues keep the template dialect.filtervalue keeps the template dialect; a text slot (notifytitle/message, a screendescription, …) reads{{ }}holes and refuses a single-brace token.6a06e3b00(#22563); date macrosd85615ddd(#22635); text slots2b61f2d9d(#22315):32(FROM → TO row 1)has(record.owner) ? record.owner : null,has(vars.x) ? vars.x : null(writesnull)vars:has(vars.record) && has(vars.record.owner) ? vars.record.owner : null,has(vars.x) ? vars.x : null(writesnull)d85615ddd(#22635), the step-by-step guard (guardOf):41(census){$User.Id},examples/app-todo); … 71 refused (…) and 20 kept (15 date macros, 5{$User.Id}).{$User.Id}(examples/app-todo), which the run-user refusal on this line refuses and migrates; … 71 refused by this change (…) and 20 that the date-macro and run-user refusals on this line refuse (15 date macros, 5{$User.Id}).6a06e3b00(#22563),d85615ddd(#22635)19939-flow-value-slot-run-user-refused.md:22{NOW()}/{TODAY() ± N}(CEL has no string form for a Timestamp yet). A string that mixes a date macro with any other token, a$Userpath included, is still kept whole.{$User.*}keeps resolving where the single-brace dialect still lives — afiltervalue, anotifyrecipientsentry. The value-slot retirement's entry earlier on this line lists{$User.PATH}among the spellings still accepted, and the text-slot entries compute the run user through it; this entry supersedes those lines.{$User.*}keeps resolving where the single-brace dialect still lives, a CRUDfiltervalue.d85615ddd(#22635); recipients111ffff55(#22926); supersede clause: this PR (rows 2, 20-22):32(row 5, "what changes")current_user != null ? current_user.id : null, which renders nothing where the template didmain:36examples/app-showcase's{$User.Id}is anotifyrecipientsentry, which is not a value slot, and is unchanged.examples/app-showcase's{$User.Id}, anotifyrecipientsentry, is migrated tocurrent_userwith thenotifyvalue slots on this line.111ffff55(#22926):44{{ }}hole, and every other position keeps the single brace.{{ }}hole, the hint at a node's literal names the value itself, and every other position keeps the single brace.111ffff55(#22926),968acc895(#23062):45current_user, and the date macros still read until CEL can write them.current_user.d85615ddd(#22635)19939-flow-value-slot-date-macros-refused.md:27:41(row 9, "what changes"):47filtervalue, anotifyrecipientsentry, anhttpbody, asubflowinput. The value-slot retirement's earlier entries on this line list the date macros as still accepted, and the text-slot entry computes a date through them; this entry supersedes those lines.filtervalue.f66fdc797(#22715); recipients111ffff55(#22926); http body968acc895(#23062); supersede: this PR (rows 2, 5, 20)19939-flow-callee-input-value-slots.md:32maporloopcollection, afiltervalue, anotifyrecipientsentry, anhttpbody, a screen'sdefaults. The value-slot retirement's earlier changesets on this line listsubflow.inputamong those positions; this one supersedes that line.filtervalue.12b9daf74(#22832); collection9fdb12752(#22883); recipients111ffff55(#22926); http body968acc895(#23062); supersede: this PR (rows 12, 19)19939-flow-screen-value-slots.md:41maporloopcollection, afiltervalue, anotifyrecipientsentry, anhttpbody. The value-slot retirement's earlier changesets on this line list a screen'sdefaultsamong those positions; this one supersedes that line.filtervalue.9fdb12752(#22883); recipients111ffff55(#22926); http body968acc895(#23062); supersede: this PR (rows 13, 19)19939-flow-collection-value-slots.md:38filtervalue, anotifyrecipientsentry, anhttpbody. The value-slot retirement's earlier changesets on this line list amaporloopcollectionamong those positions; this one supersedes that line.filtervalue.111ffff55(#22926); http body968acc895(#23062); supersede: this PR (rows 13, 14, 19)19939-flow-notify-value-slots.md:44filtervalue, anhttpbody. The value-slot retirement's earlier changesets on this line, and the text-slot changeset, listrecipients,actionUrl,sourceId,payloadandtemplateDataamong those positions; this one supersedes that line.filtervalue.968acc895(#23062); supersede: this PR (rows 5, 12-15, 19)19939-flow-http-slots.md:44filtervalue. The notify changeset on this line lists anhttpbody among those positions; this one supersedes that line.filtervalue.22110-flow-text-slot-double-brace.md:20actionUrl111ffff55(#22926); httpurlandheaders968acc895(#23062):FLOW_NODE_TEXT_SLOTSholds eight:24recipients,actionUrl,sourceId,payload,templateDatavalues, a screen'srecordId/defaults/ fielddefaultValue,subflow.input,script.inputs,map.input,http,loop/mapcollection,filter— and the value slots are CEL's.filtervalue keeps the single-brace dialect, and the value slots are CEL's.f66fdc797(#22715),12b9daf74(#22832),9fdb12752(#22883),111ffff55(#22926),968acc895(#23062):35(FROM → TO row 4)assignmentnode, whose value slot still reads that spelling —assignments: { due: '{TODAY() + 7}' }— then'Due {{ due }}'assignmentnode's CEL value envelope —assignments: { due: { dialect: 'cel', source: 'isoDate(daysFromNow(7))' }, by: { dialect: 'cel', source: 'current_user.id' } }— then'Due {{ due }}','By {{ by }}'6a06e3b00(#22563),d85615ddd(#22635); the AFTER istextSlotTemplateRefusal's remedy onmain22477-flow-text-slot-dollar-root-refused.md:22{{ $User.PATH }}is the sentence{$User.PATH}gets: compute the value into a variable with anassignmentnode, whose value slot still reads that spelling, then write the variable as a hole.{{ $User.PATH }}is the sentence{$User.PATH}gets: for$User.Id, compute the run user's id into a variable with anassignmentnode's CEL value envelope (current_user.id), then write the variable as a hole; any other$Userpath never resolved, and the refusal says how to read the user record by that id.6a06e3b00(#22563):33assignmentnode first,assignments: { by: '{$User.Id}' }, thenmessage: 'By {{ by }}'assignmentnode first,assignments: { by: { dialect: 'cel', source: 'current_user.id' } }, thenmessage: 'By {{ by }}'6a06e3b00(#22563)22507-screen-copy-engine-pick-spec.md:15titleis not judged by the text-slot rule yet, so a single-brace token in it is drawn as literal text, as it was before.d973c34cd(#22673)22627-flow-screen-title-translation-text-slot.md:13titleis not judged by the text-slot rule yet; that describes the face before this change.15213-unmanaged-import-verb.md:10installModesdeclares the modes a package permits.c7d60378f(#22916):14dataandtranslationsare left to the install door, which applies them after the copy as it does for a managed install; …translationsare copied too, each locale of each bundle as onetranslationitem, and an unmanaged install loads no seeddata; …c7d60378f(#22916)15213-install-modes.md:12_lock) keeps that lock on the copy as written today, and a follow-up on #15213 strips it per #22971's ruling A.2d21b9c89(#23075):1415213-unmanaged-import-verb, in this same release. … (the whole paragraph)_lock, which keeps that lock",2d21b9c89(#23075)15213-unmanaged-lock-strip.md:1415213-install-modes, in this same release. … (the whole paragraph)21898-flow-builtin-node-config-values-refused.md:19httpinterpolates its config before it parses, so only anhttpslot sees the token's resolved value. Every other builtin parses its config as authored, so a token in one of its number or boolean slots (…) still fails at its first run, exactly as before — write a literal there;httpnode'stimeoutMsanddurablerefuse the token itself at the build doors);968acc895(#23062):20http, any value with a token inside it, andsigningSecret(the credential channel may supply it);http,signingSecret(the credential channel may supply it);968acc895(#23062):RUN_RESOLVED_KEYSishttp: ['signingSecret'], and the http token carve-out went with the interpolation:32timeoutMs: 5000,durable: true— or, onhttpalone, a sole-token template such astimeoutMs: '{timeout}':httpinterpolates before it parses, so the token resolves to its value's type firsttimeoutMs: 5000,durable: true— a literal only:httpparses its config as authored, and a{token}there is refused at the build doors968acc895(#23062)21982-flow-script-subflow-config-undeclared-keys-refused.md:30config: { function: 'f', inputs: { taskId: '{record.id}' } }config: { function: 'f', inputs: { taskId: { dialect: 'cel', source: 'record.id' } } }f66fdc797(#22715): a{…}token inscript.inputsis refused22054-notify-title-template-input.md:24{token}({record.name}). A{{var}}is not a placeholder here: the inner{var}resolves and the outer braces stay in the text, for a bare string and an envelope alike.{{ }}holes ({{ record.name }}), for a bare string and an envelope alike, and a single-brace{token}in them is refused.2b61f2d9d(#22315):25{token}interpolation in place of "sent verbatim".{{ }}holes in place of "sent verbatim".2b61f2d9d(#22315)22081-notify-refusal-single-brace.md:5title/messagerefusal now prescribes'{record.name}', the single-brace spelling the notify executor reads. It used to prescribe the shared template sentence's'{{record.name}}', which the build'sflow-double-brace-interpolationrule then flagged on the same node and the notify renderer sent inside a stray pair of braces.title/messagerefusal now names the key and prescribes'{{ record.name }}', the{{ }}hole the notify executor renders. It used to answer with the shared template sentence, which names no key.2b61f2d9d(#22315):NOTIFY_TEMPLATE_PLACEHOLDER = '{{ record.name }}'lands there (git log -S):10'{record.name}'or{ dialect: 'template', source: '{record.name}' }, and says why: the notify executor interpolates single-brace{token}placeholders, and a doubled brace keeps its outer braces in the sent text. The branch issue … carries the same sentence, so no{{…}}prescription reaches the author on these two keys.'{{ record.name }}'or{ dialect: 'template', source: '{{ record.name }}' }, and says why: the notify executor renders{{ }}template holes, and a single-brace token is not one. The branch issue … carries the same sentence.2b61f2d9d(#22315):12{{record.x}}for the formula template engine and the messaging, email and i18n renderers,{record.x}for a notify node'stitle/message, and either fortitleFormat.{{record.x}}for the formula template engine, the messaging, email and i18n renderers and a notify node'stitle/message, and either fortitleFormat.2b61f2d9d(#22315): thetmpldocblock onmain22290-value-slot-remedy-cel-claimed-head.md:11has(vars.list.tags) ? vars.list.tags : null.vars, like any other head:has(vars.list) && has(vars.list.tags) ? vars.list.tags : null.d85615ddd(#22635):guardOfinflow-value-slot-template.tsWhat
maindoes, measured atc9b5b24b0(the facts behind the AFTER column):interpolateFilterinservice-automation/src/builtin/template.tsis the only single-brace interpolator still called ("Only filter blocks use this"), from the CRUDfilterhand-off incrud-nodes.ts; the twointerpolate()calls left run on token-free text.FLOW_NODE_TEXT_SLOTSlists eight slots.textSlotTemplateRefusalprescribescurrent_user.idandisoDate(daysFromNow(7))through anassignmentCEL envelope.examples/carries no$Usertoken; the showcase recipient readscurrent_user.Cross-references between pending entries
Every clause that quoted another pending entry, found by phrase (
supersede,earlier entry,earlier changeset,published earlier,this same release,companion entry, …) across all 486 pending files::22and:32(rows 5, 6); date-macros:27,:41and:47(rows 10-12); S1 to S5's "still lives" clauses (rows 13-17);22627:13(row 24);15213-install-modes.md:14(row 28);15213-unmanaged-lock-strip.md:14(row 29).22443-sys-file-public-scope-rewrite.md:55quotes the D3 entry's earlier reason ("said that files already stored with scope public are not touched"), a change to18.storage-scope-public-retired.tsthis release makes. date-macros:40maps "the guard an earlier refusal named", and:17says a mixed string "used to be kept whole".15213-unmanaged-lock-strip.md:12begins "Until now an item locked with_lockwas copied with that lock". All four describe the code before that change.15953-verify-parent-write-reach-family,22402-option-gate-fails-closed,22428-field-existence-every-spelling,22445-update-preview-stored-row,22481-attached-block-served-rows,22579-migrate-telemetry-siblingand22581-migrate-reads-env-filesquote none of the files above. Each already flags the earlier sentence in order.Sweep: what was read, and what stays as written
19939-*files,22110,22477, the two22443-*files, the five22507-*files,22627, and the four15213-*files. Then a grep of all 486 pending files for the brace dialects and slot names (63 hits, plus 25 more on slot names), reading every flow entry among them. That sweep added21898,21982-…-script-subflow…,22054,22081and22290, each falsified by a train landing above. I bounded the sweep to sentences those landings falsified, as triage's direction scopes it. Other pending text is not judged here.22443-sys-file-public-scope-rewrite;22507-screen-copy-engine-pick-{automation,cli,lint}and22507-flow-options-toasts-translation;15213-readonly-package-remedy;21982-flow-builtin-node-config-undeclared-keys-refused(keys inside a free-form map are still never judged);22301-verify-evaluate-condition-door:12(evaluateConditionstill reads a template string);22344,22502,22572({read.id}and "a single-brace token in a value position" still exist in a CRUDfilter); the22161lint slices.22110:8and22477:6list the five text slots that change created. They are not framed as exhaustive, and the notify and http entries state the three added since; only the count "the five" (row 18) contradicted them. (b) S4:17and S5:19print a last-key guard on a field of the triggerrecord, which is bound there, so pass 3's absent-variable reasoning does not reach them. (c)15213-unmanaged-import-verb.md:6and:10("editable from then on", "is fully editable") are true again onmainsince the lock strip (2d21b9c89). (d)15213-unmanaged-import-verb.md:14refuses "a body carrying … code (functions, …)". S2 stopped refusing an empty container, which carries no code, so I read it as true.22081:12's clause "the generated expression reference page says a template slot's fix is written in the spelling its renderer reads". It is left as written.Verification
Gates were derived with
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackon HEAD88fa8fe1b(this branch merged withorigin/mainbcebd8409; the delta vsorigin/mainis exactly these 21 files, +36 / -46). That gave 20 commands, and all 20 ran on88fa8fe1b.--ranreconciliation: "20 derived, 20 run, 0 NOT-MEASURED, 0 UNRUN", with exit codes recorded.node scripts/check-empty-changeset.mjs --base origin/main, exit 1. It prints 21::errorlines, one per edited file, and each one says "exists on the merge base and was not added by this PR … DELIBERATE CORRECTION -- your change may have made this PENDING release note false, and you rewrote it in the same stroke. Remedy: do NOT restore it -- say so on the PR and get it confirmed".check-adr-0087-registration --base origin/main("this PR adds no declared-breaking changeset (21 non-breaking changeset(s) seen)") and its--self-test(548 assertions);check-changeset-no-major --base origin/main("This diff introduces nomajorbump") and its--self-test(401);check-closing-keyword-parityand--self-test;check-comment-mask-corpus(8926 files, 0 disagree);check-empty-changeset --self-test(170);release-rehearsal-clone --self-test;release-pending-publish --self-test(92 cases);check:changeset-gate-self-tests;check:driver-memory-census;check:gitlink-declared;check:nul-bytes(11157 files, no raw control bytes);check:objectui-changeset;check:pm-changeset-deadline-census;check:published-files;check:refd-timer-probe;check:watch-hint-literal.node scripts/check-changeset-fixed.mjs, the one roster family whose roster lives under.changeset/. Exit 0.check:doc-authoringis not in the derivation for.changeset/**and its script names no changeset path, so it does not read these files.Generated by Claude Code