Repository navigation
Survey + ADR: the platform customization model for packaged metadata — regimes per type, one activation ledger (chartered on #11665) #12049
Description
Activity
os-support-ai commented
on Aug 25, 2026 CollaboratorAuthorMore actionsClaim: maintainer direct-dispatch (decision-inbox PM session)
Session:session_01KWRU3s15AJz7PGW7a7wdCh
Branch:claude/issue-12049-customization-model-adr(for the ADR draft PR; the survey half is comment-only)
Worktree:objectstack-issue-12049(dev-side, per worktree-first)
Domain: cross-cutting design (direct charter — audit quote in the card body, verbatim 「要整体评估除了流程还有哪些需要自定义的也有类似的问题,开始写adr」)
File surface:docs/adr/**(one new ADR, DRAFT PR only — governed) + a survey comment on this card; ⛔ no product code, nopackages/spec, no edits to #11665
Container & model:L design,mode:subagent,model: claude-fable-5— a platform-wide contract/protocol document is the heaviest class (PM discretion under the 2026-08-10 three-tier ruling; measured-unavailability fallback: opus, never lower)
Clause-②: no — a direction document; the implementation cards it spawns will carry their own declarations
Serial constraints cleared: none —docs/adr/**new file, no in-flight claim touches the customization model; the #11665 implementation is deliberately not started (it is Blocked-by this card)
Generated by Claude Code
Survey: post-install customization across every authorable metadata type
Deliverable 1 of this card. Dev seat, session
561db75b-4090-5fd3-bb06-accf7af9f8eb, branch
claude/issue-12049-customization-model-adr. Every claim names the file/line it was read from,
pinned toorigin/mainat0b048393faa98151600598bcebf2ad905ee7021f. Static reads only, with a
positive control through the same instrument wherever a zero is asserted. The ADR (Deliverable 2)
cites this comment.NOT MEASURED, declared rather than assumed:
objectstack-ai/hotcrm(out of this card's scope
— itsopportunity_approvalexemplar is cited from #11665, not re-measured). What the objectui
React designer renders (one text-level zero over the local../objectuicheckout at2ecc9c7cb2
is stated in §3.5 as a text zero, not a render fact). No runtime experiment was run.
1. The census — 27 declared types, plus one dynamic-kind channel
DEFAULT_METADATA_TYPE_REGISTRY(packages/spec/src/kernel/metadata-plugin.zod.ts:654) is the
authoritative census, by its own header: "This array is the TOTAL universe of declared metadata
types (#8586): the only production writer of the manager's type registry issetTypeRegistry(...),
and no channel extends it." Mechanical count over the array body: 27 entries —object · field · hook · seed · mapping | view · page · dashboard · app · action · report ·
dataset | flow · job | datasource · external_catalog · api · translation · email_template ·
doc · book | permission · position · capability | agent · tool · skillOne channel sits beside the census, not inside it: a manifest's
contributes.kindsregisters kind
descriptors as ITEMS of thekindtype (same header,metadata-plugin.zod.ts:648-652). Measured
specimen:connector— the stack'sconnectors:entries are registered under kind'connector'
(packages/metadata/src/plugin.ts:98; consumed by
packages/services/service-automation/src/plugin.ts:290-299). Dynamic-kind items ride the same
storage and the same package provenance; they are not separately flagged for overlay/create, so the
model the ADR writes must state what regime an undeclared kind defaults to.The five-type org-overlay pin holds:
protocol.org-scoped-write-refused.test.ts:539-543derives
orgOverridablefrom the registry and pins ittoEqual(['view', 'dashboard', 'report', 'translation', 'email_template'])— by identity, not count.2. What a customer can actually do today — the write door, derived mechanically
The runtime write gate judges type flags × item provenance
(packages/metadata-protocol/src/protocol.ts:13227-13260): an item that exists as a packaged
artifact requiresallowOrgOverrideto be written at all ("writing here would overlay code-shipped
behaviour"); a brand-new name requiresallowRuntimeCreate; a type with both flagsfalseis
refused on every kernel (NOT_CREATABLE/NOT_OVERRIDABLE, #5086 —protocol.ts:11355-11388);
an org-scoped write on a non-allowOrgOverridetype is refused separately (#6190 family,
protocol.ts:11471-11487). Partitioning the 27 rows by their flags (5 + 17 + 5 = 27):Tier Types (by identity) A packaged item can be… A — org-overlayable ( allowOrgOverride: true)view, dashboard, report, translation, email_template overlaid env-wide AND per-org (ADR-0005) B — runtime-create only ( allowRuntimeCreate: true, orgfalse)object, hook, seed, mapping, page, app, action, dataset, flow, datasource, external_catalog, doc, book, permission, position, tool, skill not customized at all — any write against the packaged item answers 403 NOT_OVERRIDABLE; only brand-NEW items can be authoredC — code-only (both false)field, job, api, capability, agent nothing — no runtime write channel exists ( OS_METADATA_WRITABLEoperator hatch aside)Tier B is where the whole problem lives: seventeen types where the platform simultaneously ships
packaged items and refuses every post-install change to them, with authoring of a sibling item
fully open — the exact double-fire / silent-shadow setup #11665 measured forflow.3. The mechanisms — four real, one paper
3.1 Org overlay (ADR-0005) — five presentation types, live
The read path exists only for tier A (
loadMetaFromDbhydratesorganization_id IS NULL; per-org
overlays load on demand forallowOrgOverridetypes only —
packages/metadata-core/src/meta-write-org-scope.ts:16-24, verified verbatim). For every other
type an org-scoped row is a phantom write — works until restart, then silently gone; measured
specimensflow(triggers stop firing) andobject(every record 404s). This is the #6190 wall
the card restates: no behavioral type may be "fixed" by flippingallowOrgOverride.3.2 Clone-to-customize + lock — permission sets only, landed (#11513)
The one shipped instance of the behavioral regime, all identities verified present on this pin:
- Lock: a Studio/API save targeting a package-declared set refuses 403 naming the clone path
(packages/plugins/plugin-security/src/packaged-permission-set-lock.ts— header: "The clone is
an ordinary org-owned set with no upgrade linkage, so upgrades keep flowing to the base
untouched. No silent overlay row is ever minted again."). - Clone: a row action on the data door demanding a new name
(sys-permission-set.object.ts:115-152); whole-definition-copy is the lesson of Theclone_permission_setaction copies only 2 of the 6 definition facets, so a clone silently drops system permissions, RLS and tab permissions #11703 (a
param-list clone silently dropped three of six facets). - The activation split: deactivating a packaged set is row state, not a definition write —
the{ active }patch is carved out of the lock by name
(permission-set-projection.ts:1128-1145,[#4669]). This carve-out is the precedent the
generic ledger generalizes: "switched off" is operational data-plane state per artifact, never a
metadata write. - Drift surface:
permission-set-drift.tscovers only the enforced copy vs its own artifact
(overlay_shadow / provenance_skip); clone-vs-base drift is deliberately absent (the ServiceNow
layer, recorded-not-chartered).
3.3 Extend —
objectExtensions+ navigation contributions: real, general, package-grainThis is the mechanism the dispatch asked to measure for a third-regime slot, and it is real —
but it is not the auth one (§3.4):ObjectExtensionSchema(packages/spec/src/data/object.zod.ts:2920-2980): a package declares
objectExtensions: [{ extend: '<target>', fields, validations, indexes, label… }]against an
object owned by another package; the loader registers it as contributor kind'extend'
and merges at boot (packages/objectql/src/engine.ts:4529-4547; merge carries exactly
fields/label/pluralLabel/description/validations/indexes — the schema's own guidance refuses
actions/hooks/listViews through this door and names the top-level alternative).- The UI analog:
NavigationContributionSchema(ADR-0029 D7,packages/spec/src/ui/app.zod.ts)
injects nav items into an app the contributor does not own. - Reach: the mechanism rides the package-install door —
POST /packagesroutes through
protocol.installPackage→registry.installPackage(manifest)
(packages/runtime/src/domains/packages.ts:281-313), the same primitive that registers
extensions — so post-install extension of a packaged object is possible by installing/authoring
another package, at install grain. No per-org dimension, no ledger, no upgrade linkage
(the extension package survives base upgrades untouched). - Exemplar pull: showcase ships them (
objectExtensions: allObjectExtensions,
examples/app-showcase/objectstack.config.ts:192) and the mechanism has a published hand-written
doc page (content/docs/data-modeling/object-extensions.mdx).
3.4 Managed extension fields (plugin-auth) — measured: NOT a customization regime
MANAGED_EXTENSION_FIELDS(packages/plugins/plugin-auth/src/managed-extension-fields.ts:57-125)
is a build-time constant answering a different question: which columns on the four
better-auth-managed objects (sys_user,sys_organization,sys_api_key,sys_invitation)
belong to ObjectStack rather than to the embedded library (ADR-0105 D7 / ADR-0092 D2), plus a
hard-coded editable subset. No runtime write channel mints entries, no org dimension exists, and
it faces exactly four sys objects. The PM assumption that this might be the third regime is
falsified — the extend slot belongs to §3.3. (The name collision discipline in its header is
still worth citing in the ADR as prior art for "extension must never collide with base surface".)3.5 The paper mechanism — a three-layer customization protocol with zero consumers
packages/spec/src/kernel/metadata-customization.zod.tsdeclares a full
system/platform/user three-layer overlay protocol —MetadataOverlaySchema, per-field
FieldChangeSchema(originalValue/currentValue/changedBy),lockedFields/customizableFields,
3-way merge on package upgrade. It is exported (packages/spec/api-surface/kernel.json:213) and
published as reference documentation
(content/docs/references/kernel/metadata-customization.mdx). Consumers:POSITIVE CONTROL grep MetadataOverlaySchema|CustomizationOriginSchema|FieldChangeSchema → finds the definitions in packages/spec/src and the api-surface row ZERO the same grep across packages/** excluding spec (framework runtime): 0 matches ZERO the same grep across the local ../objectui checkout @ 2ecc9c7cb2: 0 matchesThe real overlay implementation (
sys_metadata+organization_id, ADR-0005) shares no code with
it. A declared-but-unenforced protocol surface publishing the exact ServiceNow-style layer the
#11513 ruling left unchartered is ADR-0049 territory; filed unassigned as #12057 (finding),
and the ADR must state its disposition so the paper protocol cannot be mistaken for the model.4. Per-type survey
Class: B behavioral (runs with side effects) · P presentational (render-time) ·
S structural (schema/wiring) · C content. "Packaged today" cites in-repo deliverables
(platform packages +examples/); file-pattern counts under-measure inline stack declarations, so
stack keys are cited where patterns miss. "Pull" = authoring pull in the in-repo exemplars
(showcase/CRM/todo); hotcrm NOT MEASURED.Type Class Packaged today (specimen) Post-install customization of a packaged item, today Exemplar pull Doc promise touching it object S 78 *.object.tsin packages (sys_permission_set…), 26 in examples⛔ 403; extend via §3.3 package grain high (26 + extensions) F6 "objects … then customize in Studio" — unkeepable for fields-on-packaged field S inside objects ⛔ code-only spelling retired (#7893); via owning object only, which is ⛔ for packaged n/a — hook B 2 example *.hook.ts(opportunity.hook.ts…) + showcasehooks: allHooks; runtime hooks use sandboxed bodies (packages/runtime/src/sandbox/body-runner.ts:303)⛔ 403 on packaged; new hooks open yes — seed C all three examples ship stack data:seeds (ShowcaseSeedData,CrmSeedData)moot — applied once; post-install the rows are ordinary records yes F6 "seed data included" — true mapping S showcase mappings: allMappings⛔ overlay; clone-by-authoring free (new name) yes import-mappings.mdx:85documents the negative honestlyview P 10 example *.view.ts+ platform✅ org overlay (tier A) high metadata-service.mdx:328— truepage P 21 example pages + 4 platform ⛔ 403; new pages open; nav repoint needs app edit (⛔ on packaged apps) high F6 "customize in Studio" — false for packaged pages dashboard P 5 examples + 1 platform ✅ org overlay yes F6 — true app P platform Studio/Setup apps; 2 examples ⛔ 403 on packaged; nav contributions open (§3.3) yes — action B 2 platform + 2 example ⛔ 403 (was the #6283 phantom shape); new actions open (sandbox bodies) yes — report P 1 example + 1 platform ✅ org overlay low — dataset P/S 4 example datasets ⛔ 403; new datasets open yes — flow B 4 example *.flow.ts(showcase + CRM); hotcrm cited, NOT re-measured⛔ 403 (F1/F3 verified below); no clone action exists (#11665 §4.2) yes F6 "flows … then customize in Studio" — false, the motivating breach job B showcase jobs: allJobs⛔ code-only (#4509 — handler resolves only through the compiled bundle) yes — datasource S 2 example datasources ⛔ on code-defined (origin gating); runtime-created via wizard open (ADR-0015) yes — external_catalog S never packaged by design (derived snapshot, registry comment) moot n/a — api B showcase apis: allApis⛔ code-only (#5488 — a saved runtime row was never served) yes — translation C showcase translations ✅ org overlay yes — email_template C showcase emailTemplates: allEmails✅ org overlay yes email-templates.mdx:213documents overlay-winsdoc C packages ship docs/*.md items ⛔ overlay; new docs open low — book C/P showcase books: allBooks⛔ 403 (rolled back #6483 — Studio drag-edit refused) yes — permission B stack permissions:(showcasepermission-sets.ts); plugin-materialized sets✅ clone + lock + row-state deactivate (§3.2) — the landed regime instance yes — position B showcase positions.ts⛔ 403 on packaged; new positions open yes — capability B showcase capabilities.ts+ plugin bootstrap⛔ code-only (ADR-0066 D1 — minting grant targets at runtime is the defect) yes — agent B platform ships exactly two (ADR-0063 §2) ⛔ code-only, deliberate ("the code is the record") none (closed) — tool B (runtime-creatable; no in-repo packaged *.tool.tsspecimen)⛔ 403 on packaged; new tools open none found — skill B skills/catalog ships to customer projects⛔ 403 on packaged; new skills open catalog — 5. The published-promise measurements (the F6 family)
Two shipped pages promise post-install customization of packaged apps generically:
content/docs/capabilities/integrations.mdx:17— "install complete apps (HotCRM among them)
with one click: objects, views, flows, dashboards, and seed data included, then customize in
Studio" (verified verbatim; Design: post-install customization of packaged flows — clone-to-customize + org-level takeover (supersedes the org-tunable-parameters framing) #11665's F6).content/docs/build-without-code.mdx:37— "template apps such as HotCRM install with one click
and appear alongside your own apps, ready to customize in Studio" (a second specimen, not
previously recorded).
Against §2: the promise is keepable today for views/dashboards (tier A), for no tier-B type,
and the flows half is the measured breach #11665 chartered. The honest negatives exist too
(import-mappings.mdx:85), so the doc corpus knows how to say "no" — the promise pages just don't.6. Spot-checks of #11665's load-bearing facts on this pin
Fact Verdict Evidence F1 — the on/off switch is a field of the packaged artifact holds flow.zod.ts:641status: z.enum(['draft','active','obsolete','invalid'])F3 — org-scoped rows of non-overlay types are phantoms holds meta-write-org-scope.ts:16-24read verbatimF4 — only record-change triggers carry an org holds grep `tenantId F5 — singleposture = one logical tenant; multi-org is entitlement-gatedholds tenancy-posture.ts:12-16, 26-30five-overlay identity pin holds test line 543, §1 F2 (env-wide flowEnabledmap = the #10243 leak)cited, not re-measured runtime state, no static read adds anything §2.2 same-name shadow (listItems no precedence) holds, fix in flight draft PR #12026 ( claude/issue-11997-packaged-flow-name-shadow) — not landed on this pin; the ADR's C1 (new name mandatory) must not depend on the shadow persisting7. What the evidence sets the regime count at
Three live regimes plus a code-only tier, and one paper protocol to retire or converge:
- Overlay (presentational): the five tier-A types — live, unchanged.
- Clone + takeover (behavioral): landed for
permission; chartered forflow(Design: post-install customization of packaged flows — clone-to-customize + org-level takeover (supersedes the org-tunable-parameters framing) #11665);
structurally applicable to every tier-B behavioral type (hook, action, tool, skill, position)
as pull appears. This is the family the generic activation ledger serves. - Extend (structural):
objectExtensions+ navigation contributions — live, package-grain,
additive, no ledger required (the customization IS a package; provenance and upgrade isolation
come from package identity). - Code-only tier (field, job, api, capability, agent): customization = ship a new package
version; deliberately outside the model.
The managed-extension-fields mechanism is not a regime (§3.4). The three-layer spec protocol is
not a regime either — it is paper (§3.5) and needs an explicit disposition in the ADR.
Generated by Claude Code
- Lock: a Studio/API save targeting a package-declared set refuses 403 naming the clone path
{ "issue": 12049, "status": "done", "branch": "claude/issue-12049-customization-model-adr", "pr": "https://github.com/objectstack-ai/objectstack/pull/12063", "premise_still_valid": true, "summary": "Survey posted as issue comment 5406807988 (27-type census, write-door tier partition, four real mechanisms + one paper one, per-type table, doc-promise measurements, F1/F3/F4/F5 spot-checks at origin/main 0b048393). ADR-0126 drafted as docs/adr/0126-packaged-metadata-customization-model.md on draft PR #12063 (Part of #12049): three regimes by artifact behavior, sys_metadata_activation generic ledger, install-level operator-gated write authority with reserved org column, the #6190/sole-definition-ledger/upgrade-vs-choice walls, flow worked example carrying the 2026-08-25 tentative directions marked settled-only-by-merge. PM-assumption verdicts: registry census confirmed authoritative (plus dynamic-kind channel); managed-extension-fields FALSIFIED as a regime (build-time auth ownership declaration) - the extend regime slot belongs to objectExtensions/ADR-0029-D7 nav contributions, which are real, general, packaged-object-facing, package-grain; #11665 F1/F3/F4/F5 and the five-type pin all hold on this pin.", "files_changed": [ "docs/adr/0126-packaged-metadata-customization-model.md (added, 363 lines; the only file in the diff)" ], "gates_run": [ "node scripts/pm/dispatch-gates.mjs (no paths; stderr header: objectstack-ai/objectstack at 7ca6f94) -> derived 5 families", "pnpm check:adr-anchors -> exit 0 (self-test + scan)", "pnpm check:doc-authoring -> 'doc authoring guard: 390 files clean - no bare metadata literals.'", "pnpm --filter @objectstack/lint run check:doc-formula-expressions -> '22 record-scoped formula example(s) across 422 files / 1449 TS blocks judged clean' (verify-lock VERDICT command-exit 0)", "pnpm check:pm-governed-merges -> 'check-governed-merges --self-test: 129 assertions'", "node scripts/check-adr-links.mjs -> 'check-adr-links: 554 relative link destination(s) under docs/adr/ resolve'", "pnpm check:nul-bytes -> 'check-nul-bytes: OK (scanned 6696 text file(s))'", "all gate runs at HEAD 7ca6f94 (the final and only commit); heavy steps (install, builds) serialized through scripts/pm/os-verify-lock.sh, max hold 4m57s, waited 0s" ], "tests": "Docs-only diff; no package tests owed. Gate evidence above; exits captured before any pipe (cmd > log 2>&1; EXIT=$?), verdict lines quoted from the gates' own output.", "deviations": [ "Global GitHub search API is unavailable in this session (repository-scoped endpoints only); dedup for the finding ran as repo-scoped REST listing of all 377 open issues + local keyword grep instead of search - declared narrowing: closed issues were not swept.", "Review request to os-zhuang succeeded (HTTP 201, requested_reviewers read back) - the author-identity 422 fallback was not needed.", "No changeset; skip-changeset applied via additive POST and read back AFTER the size-labeler wrote (labels: size/m, skip-changeset) - the ADR-0124/PR #9856 precedent.", "Branch commit carries no card-relationship trailer (squash rule); the Part of declaration lives in the PR body only." ], "open_questions": [], "out_of_scope_findings": [ "filed as #12057: spec ships a three-layer metadata-customization protocol (MetadataOverlaySchema, field-level change tracking) with zero consumers; published reference docs describe an unimplemented customization architecture (finding label, unassigned, Blocked-by #12049)" ] }
Generated by Claude Code
os-support-ai commented
on Aug 25, 2026 CollaboratorAuthorMore actionsPM acceptance — both deliverables verified; awaiting human merge of the ADR.
Session:
session_01KWRU3s15AJz7PGW7a7wdCh(the chartering PM session). Terminal report = comment 5406965521, read back intact.Deliverable 1 (survey) — comment 5406807988, accepted: 27-type census from
DEFAULT_METADATA_TYPE_REGISTRYwith claims pinned toorigin/main@0b048393; write-door tier partition (5 org-overlayable / 17 runtime-create-only / 5 code-only); four real mechanisms + one paper one; per-type table; doc-promise measurements (the F6 family, plus a second specimenbuild-without-code.mdx:37not previously recorded); #11665's F1/F3/F4/F5 and the five-type overlay pin all hold on this pin. The card's⚠️ was answered by measurement, not assumption: managed-extension-fields is falsified as a regime (a build-time auth ownership declaration, ADR-0105 D7 / ADR-0092 D2); the extend-regime slot belongs toobjectExtensions+ ADR-0029 D7 navigation contributions — regime count stays three, plus the code-only tier.Deliverable 2 (ADR) — draft PR #12063, single file
docs/adr/0126-packaged-metadata-customization-model.md(+363), accepted as the decision vehicle: three regimes by artifact behavior; one genericsys_metadata_activationdata-plane ledger (definitions stay insys_metadata, sole definition ledger); install-level operator-gated write authority with the org column reserved; the #6190 phantom-overlay, sole-definition-ledger, and upgrade-vs-choice walls restated; the flow worked example carries the 2026-08-25 maintainer directions each marked settled only by this ADR's acceptance.Discipline held: PR stays DRAFT (governed surface), review requested from
os-zhuang(HTTP 201, no fallback needed),skip-changesetper the ADR-0124/PR #9856 precedent, no product code, nopackages/specedits, no #11665 body edits. Out-of-scope finding filed as #12057 (finding, unassigned, Blocked-by #12049); the ADR states its disposition so the paper protocol cannot be mistaken for the model.State:
pm:dispatched→pm:awaiting-maintainer. ⛔ Next action is the maintainer's alone: review and hand-merge PR #12063 — the merge is the review record and the model's acceptance. After merge + verification onorigin/main, this card closes and #11665 (Blocked-by: #12049) unlocks for its implementation legs.
Generated by Claude Code
os-support-ai commented
on Aug 25, 2026 CollaboratorAuthorMore actionsMaintainer rulings — 2026-08-25, live PM chat, after reading the ADR draft on PR #12063. Recorded by the chartering PM session
session_01KWRU3s15AJz7PGW7a7wdCh; an amendment implementing both is dispatched to the same draft PR. ⛔ As with the rest of the ADR, nothing is settled until the maintainer's hand-merge.Ruling 1 — hook leaves the model (code-only posture). Verbatim, untranslated: 「hook 也算代码类吧,我觉得也不需要修改。」 Interpretation:
hookis removed from the Regime C pre-chart list and joins the "outside" tier. A hook body is imperative package code maintaining the package's own data invariants — the managed-package trigger analogy (Salesforce locks managed Apex triggers; customization = the vendor ships a new version). Packaged hooks get no ledger rows and no disable switch — thejobposture. Runtime authoring of brand-new sibling hooks stays open, unchanged. Cost stated to the maintainer on the record: a misbehaving packaged hook has no customer-side off-switch; the remedy is a vendor fix, as with jobs today.Ruling 2 — Regime C simplifies to disable + clone, no takeover ceremony. Verbatim, untranslated: 「行为类 能否搞一个启用停用的功能,我不想要可以停用,然后克隆一个。」 Interpretation: the behavioral regime becomes two independent primitives — an enable/disable switch per packaged artifact (the activation-ledger row flip, operator-gated per D3) and free sibling cloning (new name mandatory, whole-definition copy — both stand). No designated-replacement linkage:
replaced_byandcloned_fromleave the §4 ledger, which shrinks to a pure on/off registry(metadata_type, name, package_id, organization_id nullable-reserved, active). The clone is an ordinary artifact with no recorded linkage to its base — exactly the landed #11513 permission-set shape, generalized. Consequences: the §7.3 referenced-while-packaged guard attaches to disable (refused, callers named); the §7.4 "clone based on v3, base now v5" notice is dropped (no data source without provenance; recorded as deliberately not tracked, consistent with the deferred ServiceNow-style layer); the "half-done state" concept dissolves into ordinary displayed states; permission-set convergence (§8) gets simpler since semantics are now identical.Still open with the maintainer in chat: whether
actionfollows hook out of the model or stays in the Regime C pre-chart (PM proposal on the table: internal package plumbing → code-only; customer-facing business behavior → disable + clone, soactionstays).
Generated by Claude Code
os-support-ai commented
on Aug 25, 2026 CollaboratorAuthorMore actionsMaintainer ruling — 2026-08-25, live PM chat (follow-up to the amendment rulings). Recorded by the chartering PM session
session_01KWRU3s15AJz7PGW7a7wdCh.Ruling 3 —
actionstays in Regime C, and the disable half now has measured pull. Verbatim, untranslated: 「动作 可能是需要开关的,因为有的 action 我不想启用。」Interpretation: this settles the question left open after ruling 1 (whether
actionshould followhookout of the model) — it does not:actionremains in the disable+clone family, per the boundary the PM proposed and the maintainer has now confirmed by supplying the pull themselves (internal package plumbing → code-only; customer-facing business behavior → disable + clone). The quote is itself first-party pull for the disable half of actions: when the post-merge implementation legs are cut for #11665, an action-disable leg (samesys_metadata_activationledger, a consult point at action dispatch, a surface row) is chartered to follow the flow legs; the clone half of actions still waits for real pull, per §3's pre-chart discipline. No ADR text change required —actionalready sits in Regime C's pre-chart list; this ruling starts the clock on its switch, and the implementation card will cite this comment as provenance.
Generated by Claude Code
os-support-ai commented
on Aug 25, 2026 CollaboratorAuthorMore actionsClosing — both deliverables complete and the ADR is accepted on
origin/main.Verification (session
session_01KWRU3s15AJz7PGW7a7wdCh): PR #12063 merged as28b47a93on main;docs/adr/0126-packaged-metadata-customization-model.mdblob on main reads6ca6dd1d— byte-identical to the final pushed revision (heada09d035a, three maintainer rulings folded in).Merge provenance, for the record: the merge was executed by PM session
session_01H9StxQgG2DPA26XzZZqnJB(os-trump) via the merge queue, citing the maintainer's batch instruction on its governed-PR review, verbatim: 「同意,帮我合并,然后继续」 (audit comment on PR #12063, comment 5409315015). Per the ADR's own terms the merge is the model's acceptance — the §7 flow-instance directions (A1 install-level disable · C1 whole-definition clone, no ancestry · Q2(c) disable refused while packaged subflow callers exist · Fork D Setup surface, on/off only) are now settled.Downstream: #11665 unblocks now (label swap to
pm:queue, comment posted there); its implementation legs consume ADR-0126 §7. The action-disable leg follows the flow legs (ruling 3). Release-target (v17 minor vs v18) is pending a maintainer ruling in chat and will be recorded on the implementation cards when cut. #12057 (paper protocol) proceeds separately per §6.4/D5.
Generated by Claude Code
Chartered by maintainer, 2026-08-25, live PM chat (the #11665 fork discussion), verbatim: 「要整体评估除了流程还有哪些需要自定义的也有类似的问题,开始写adr」 — following 「很多所有的元数据都有类似的个性化需求,要统一考虑。」. Direct-dispatch channel (standing authorization 2026-08-10); dispatched immediately by the chartering PM session
session_01KWRU3s15AJz7PGW7a7wdCh.Why this card exists
The platform already runs two and a half customization regimes, each with its own ledger: org overlays for exactly five presentation types (pinned by identity in
protocol.org-scoped-write-refused.test.ts); clone-to-customize for permission sets (#11513, its own row-state + projection machinery); and the #11665 flow design about to invent a third. The maintainer ruled: stop per-type invention — assess every metadata type holistically and write the model down as an ADR, so this class of decision never returns to the inbox per type.Deliverable 1 — the survey (measured, identities not counts, positive controls)
Enumerate every authorable/packaged metadata type (the registry in
packages/spec/src/kernel/metadata-plugin.zod.tsis the starting census). Per type, measure:Deliverable 2 — the ADR, as a governed DRAFT PR (
docs/adr/**)The platform customization model:
sys_metadatais ⛔ NOT it): (metadata_type, name, org nullable) → active / replaced_by / cloned_from {package, name, version} / package_id. Definitions stay insys_metadata— sole definition ledger, untouched; the org 作用域的 flow overlay 只在「本进程内发布后」绑定触发器,重启后静默失绑——冷启动两条读路径都把 organization_id 非空的行滤掉了 #6190 phantom-overlay wall stands (any design needingallowOrgOverrideflipped on a behavioral type has drifted back into org 作用域的 flow overlay 只在「本进程内发布后」绑定触发器,重启后静默失绑——冷启动两条读路径都把 organization_id 非空的行滤掉了 #6190).Tentative flow-instance directions from the 2026-08-25 maintainer discussion, to incorporate as the worked example (provenance: live chat; final ruling = the maintainer's merge of this ADR, ⛔ none of these is settled until then): A1 + operator-gated multi-org writes + reserved org column + A2 pre-chart · C1 + C3 (new name + provenance; whole-definition copy, never param-list assembly) · Q2(c) takeover refused while packaged callers reference the flow as a subflow, callers named · Q3 a one-line "clone based on v3, base now v5" notice (no diff machinery) · Q4 two deliberate steps with the half-done state shown loudly · Fork D leaning D2 (a Setup surface; automation UI is Studio-only today — survey the Setup permission-set page as the precedent shape).
Discipline
⛔ Draft PR only — governed surface: never ready, never queued, never auto-merged; request review from
os-zhuang(author-identity 422 ⇒ assign instead); human merge is the review record and the model's acceptance. ⛔ No implementation code, nopackages/specedits, no edits to #11665's body. #11665 carriesBlocked-by:on this card and unblocks when the ADR lands.Refs: #11665 (design, comment 5404974967) · #11513 · #6190 · #10243 · #11753 (the sibling spec-declared-readonly ruling) · ADR-0087