You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
fix(plugin-sharing): regime C follow-ups from objectui#12982 — close PUT /meta/sharing_rule as a third authoring door; a Setup nav entry for declared rules #24550
Part of #24421 (regime C for sharing_rule, ruling A on #24378, 6258883445). main stays releasable after the merge (ruling 6266750393). No data shape changes, so the 18.0→HEAD harness has nothing to prove here, but it must stay green if it has landed.
1. A third authoring door (p1, a narrowing)
/meta/types serves sharing_rule with allowRuntimeCreate: true, and PUT /api/v1/meta/sharing_rule/:name saves an environment-wide registry item. The dev measured it on probe_meta_rule:
the PUT answered 200;
the item was then listed by /meta/sharing_rule;
it was served by /sharing/rules, so it is enforced.
Under regime C a sharing rule is either a sealed declaration, switched through the activation ledger, or an organization-authored sys_sharing_rule row. A runtime registry item is neither: it bypasses the same-name 409 guard's model and the organization wall's ownership.
Wanted: the metadata door refuses to create or update a sharing_rule at runtime, loudly, with an ADR-0112 code, the same way positions and permission sets are sealed (refusePackagedBaseOverride / allowOrgOverride: false; measure which mechanism applies). Pin it on the HTTP door.
If any 18.0 code path legitimately writes such items, stop and report.
State the narrowing as FROM → TO with a one-line fix ("author an organization rule, or clone the declared one").
2. The Setup nav entry (the Acceptance gap of objectui#12982)
plugin-sharing's nav_sharing_rules points only at sys_sharing_rule. Add a Setup nav entry for the declared rules page, /apps/setup/metadata/sharing_rule?scope=environment. Make it a type: 'url' entry, as nav_permission_sets has.
3. Measure, do not build unless needed
Ledger state per item. No single read answers "declared, and switched off" per row. The console reads /meta/sharing_rule, plus /data/sys_metadata_activation keyed by name. A meta item's own active shows true for a ledger-off rule. Recommend whether /meta/sharing_rule items should carry the ledger's reading. Build it only if it removes a client read without adding a new surface.
A switched-off declared rule.GET /sharing/rules/:name answers 404 for one, so Clone falls back to the pre-filled New form. Report only.
Acceptance
Item 1 is refused at the door and pinned, and the ablation shows the pin is live.
Item 2 is present in the Setup nav on a showcase boot.
Claim: PM loop round 11 · 2026-10-19T13:29Z
Session: session_01Y5583bs2RDd53MH6kM1ca3
Account: os-steve (the seat's linked user as GET /user answers it; the card's assignee)
Branch: claude/issue-24550-sharing-rule-meta-door
Worktree: the cloud session's own checkout (mode:cloud)
Domain: domain:services
Seat: epic:#15194 (the epic lane)
File surface, as measured by the dev; stop on a breach and explain it in the report:
packages/plugins/plugin-sharing/** (the nav entry; the sharing_rule type's runtime-create flag, wherever it is registered).
The metadata door's seal for sharing_rule, wherever positions and permission sets are sealed.
os-dev-report
{
"issue": 24550,
"status": "done",
"branch": "claude/issue-24550-sharing-rule-meta-door",
"pr": "#24599",
"session": "session_013BWJEDZYcJKmZYj6ApCCa7",
"premise_still_valid": true,
"summary": "Premise verified on origin/main 04669a4: sharing_rule had no DEFAULT_METADATA_TYPE_REGISTRY entry, so getMetaTypes() derived allowRuntimeCreate: true from the spelling contract, and saveMetaItem's isRuntimeCreateAllowed took the no-static-entry arm. The ablation reproduced it: PUT /meta/sharing_rule/probe_meta_rule answered 200 'Saved sharing_rule ... (env-wide)'. Mechanism measured: the position/permission-set seal (refusePackagedBaseOverride, allowEnvironmentOverlay: false) refuses only writes over a PACKAGED name, and both types keep allowRuntimeCreate: true. The security-catalog namespace rule judges package registration, not a /meta save. So the fit is capability's code-only pair: sharing_rule joins MetadataTypeSchema and the registry with allowRuntimeCreate: false and allowEnvironmentOverlay: false, and its SharingRuleSchema binding moves into the kind map. Result: 403 NOT_CREATABLE for a new name (publish and draft), 403 NOT_OVERRIDABLE for a declared one, on every kernel, and /meta/types advertises false. sharing_rule gains an ADR-0126 Regime C row (clone: POST /api/v1/sharing/rules; switch: the activation ledger), and both refusals name those two paths and not the hatch, under the REST door's 500-character bound. The first cut was truncated there, as the showcase boot showed, and was fixed. ADR-0087 semantic entry sharing-rule-runtime-create-withdrawn; launch-window minor changeset with FROM to TO and the one-line fix. Setup gains nav_declared_sharing_rules (type url, /apps/setup/metadata/sharing_rule?scope=environment) beside nav_sharing_rules, with labels in en/zh-CN/ja-JP/es-ES. No legitimate 18.0 writer of sharing_rule items through saveMetaItem was found: declarations reach the registry through artifact ingest (registerApp), and the organization door writes sys_sharing_rule rows. Item 3 was measured, not built; see open_questions.",
"tests": "Head 47f5080. HTTP-door pin packages/runtime/src/meta-sharing-rule-door.test.ts (real HttpDispatcher, protocol and repository, both kernels): 10/10. Ablation: the registry entry deleted via scripts/ablation-replace.mjs, spec rebuilt, and ablation-dist-preflight --absent confirmed the marker absent from 232 built files (exit 0). Then 6 failed / 4 passed: the create cases got 200 'Saved sharing_rule probe_meta_rule (env-wide, state=active|draft)', and /meta/types returned allowRuntimeCreate true. The declared-name case stayed green, because the package door sealed declared names before this change. Restore: HEAD blob hash match, whole-tree clean, rebuilt, preflight present in 16 files, 10/10 green. Suites: spec full (22469 passed; the 3 pins that asserted sharing_rule as a plugin kind were re-judged, then 216/216 on those files); metadata-protocol full (20725 passed, 19 skipped, after enrolling sharing_rule in protocol.code-only-types and protocol.recovery-doors-emit-mutation); plugin-sharing full (1161/1161); platform-objects full, then the two re-judged count pins (73/73); objectql protocol-meta and protocol-meta-types-rich (100/100; the two #6245 open-door pins flipped to 403 NOT_CREATABLE, and the 422 behind OS_METADATA_WRITABLE=sharing_rule); rest meta-unknown-type-read-refusal (21/21); runtime cross-field-refusal-operand-withhold (11/11) and meta-managed-content-seal; cli unit generate-file-name-registry-parity (40/40); cli integration metadata-type-schema-gate (8/8, after sharing_rule was added to GATED_AT) and organization-ownership-apply (run locally because both enumerate the registry); metadata/rest/runtime/lint/client registry readers, 16 files, 364/364. Typecheck: spec, metadata-protocol, plugin-sharing, platform-objects, runtime and objectql all Done, 0 errors. Residue probe (throwaway file, deleted): deleteMetaItem of a pre-existing stored sharing_rule row succeeds on a host-config kernel and answers 403 NOT_CREATABLE on an environment kernel unless OS_METADATA_WRITABLE=sharing_rule is set. Showcase boot (pnpm dev -- --fresh, port 38558): PUT new 403 NOT_CREATABLE, whole message naming both routes; PUT share_new_inquiries_with_field_ops 403 NOT_OVERRIDABLE with the regime sentence; /meta/types sharing_rule allowRuntimeCreate false; PUT a new position 200; GET /meta/app/setup serves nav_declared_sharing_rules in group_access_control between nav_sharing_rules and nav_record_shares, and the zh-CN label is served; POST /sharing/rules 201, and the same-name guard answers 409. The rendered console was NOT MEASURED: no console build in this container; objectui#13050 renders the page.",
"gates": "dispatch-gates.mjs --commands --repo objectstack-ai/objectstack (derived at 03ec635, exit 0): 122 commands, plus the 34 non-self-test artifact-roster rows from STDERR, 164 in the final union. Each exit code was captured into a TSV before any pipe. Final battery at 03ec635: 158 exit 0. NOT MEASURED, not findings: check-engine-split-ratio --days 90 (exit 2, shallow history) and check-plugin-teardown-shape --self-test (exit 3, fixture commit not in the shallow clone); check-closing-target-claim, check-partof-closing-keyword and check-single-claim-paths (exit 2), and pm/check-governed-queue-guard (exit 1, no GITHUB_EVENT_PATH), all PR-context-only. The first battery found three real reds, fixed and green on the final battery: check:engine-double-contract (the new test's doubles; ledger --write), check:i18n (metadata-form bundles regenerated, zh-CN/ja-JP/es-ES translated by hand), and check:overlay-whitelist-table (metadata-lifecycle.mdx count 28 to 29, plus a sharing_rule row). Its other reds were prerequisite refusals (dist absent mid-build), green on re-run. Re-derived at final head 47f5080: one new family, check:cli-test-child-env, exit 0. The changeset families re-run at 47f5080, all exit 0: check-adr-0087-registration ('registered sharing-rule-runtime-create-withdrawn (new here)'), check-changeset-no-major, check-empty-changeset, check-changeset-fixed, check:changeset-gate-self-tests, check:nul-bytes, check:doc-authoring. --ran reconciliation: 134 derived families accounted for, 0 NOT-MEASURED as the runner declared it (the exit codes are in the TSV, not the --ran file). spec check:generated green after gen:meta-url-spelling and gen:schema plus gen:docs. CI check-runs on PR #24599: in_progress at report time, not awaited per contract.",
"mcp_calls": "0 GitHub MCP calls. 1 claude-code-remote call (add_repo objectstack-ai/objectui, read-only; it answered read_available and attached nothing). The objectui report comment 6268367666 could not be read: the REST API and the web page answered 403 for objectui in this session, so the card body's restatement of server_gaps was used.",
"api_writes": "2 relay strokes, POST /repos/objectstack-ai/objectstack/dispatches (fleet-write, as objectstack-fleet[bot]): (1) pr_create, which executes as POST /repos/objectstack-ai/objectstack/pulls (draft) and POST /repos//issues/24599/assignees [os-steve]; the dispatch tool exited 6 UNCONFIRMED at 300 s (run 39280041843 queued), and the target read back PR #24599, draft, assignee os-steve, body byte-identical (8467 bytes). (2) this os-dev-report comment, POST /repos//issues/24550/comments. git push is not counted. Labels: none written.",
"open_questions": [
{
"question": "Clause-② as measured: the claim carried 'no (narrowing)', but the diff also widens surface. MetadataType gains sharing_rule; /meta/sharing_rules now folds to sharing_rule (on main the plural was not in META_URL_TO_SINGULAR); Setup gains an entry. Which line does the PR carry?",
"options": ["A yes (narrowing): what the PR body line 2 and the changeset carry; minor; check-adr-0087-registration reads the narrowing arm", "B no (narrowing), as claimed"],
"recommendation": "A, because the clause asks whether the card widens the accept set or the public surface, and three measured readings say it does. The narrowing arm still marks it BREAKING, and the changeset level (minor) is the same either way. Decided as A per the dispatch's 'as measured'."
},
{
"question": "OS_METADATA_WRITABLE=sharing_rule still opens a runtime create, as it does for every code-only type (job, agent, capability, api, field, picklist). Should regime C seal the hatch for sharing_rule as well?",
"options": ["A keep the hatch working, unprescribed: the refusals never name it; it stays the operator's repair path for items stored through the old door on an environment kernel (measured: DELETE answers 403 NOT_CREATABLE there without it)", "B seal it: a new registry flag or regime-C carve-out in isOverlayAllowed, so no operator setting re-opens the third source"],
"recommendation": "A, because on the long-term axis one hatch semantics across all code-only types beats a regime-specific carve-out. On the error-proofing axis the AI author is never shown the hatch: the regime sentence omits it, as ADR-0126's builders do. On the startup-focus axis B adds machinery with no measured pull. A security or permission boundary sits on the human floor, though, so this is flagged for the maintainer rather than closed."
},
{
"question": "Item 3a: should /meta/sharing_rule items carry the activation ledger's reading?",
"options": ["A no: the metadata protocol reads sys_metadata_activation for no type (position, permission, flow and action /meta items carry none either), so this is a new cross-layer seam", "B yes: decorate /meta items of ledger-switched types with the ledger state", "C answer it on the sharing door instead: an admin read on GET /sharing/rules that lists switched-off declared rules with active false, without touching listRules, which feeds every enforcement path"],
"recommendation": "A for this card, with C as the shape if the console's two reads become a measured cost. The card's own bar (removes a client read without a new surface) rules out B, which is a new seam reading a runtime table from the metadata layer for one type. C keeps the authority (the ledger) where its reader already lives. Built: nothing."
},
{
"question": "Item 3b: GET /sharing/rules/:name answers 404 RULE_NOT_FOUND for a declared rule the ledger switched off (measured on the showcase), so Clone falls back to the pre-filled New form. Change it?",
"options": ["A a follow-up card: getRule answers the declared projection with active false for a ledger-off declared rule, read from declaredSource without the ledger filter, on the admin read only (resolveRules and listRules unchanged), as a Clause-② yes (widening) change on an existing route", "B leave the 404; the console keeps its fallback"],
"recommendation": "A, because the console needs it for a real flow (Clone of a switched-off declared rule) and it removes a client fallback without a new route. It must not reach declaredRules(), which every enforcement path lists through. Report only here, per the card."
}
],
"out_of_scope_findings": [
"carrier: #24550 (this card's item 3) · GET /sharing/rules/:name 404 for a ledger-off declared rule; recommendation in open_questions · noted, not filed · dedupe: getRule declaredRules ledger-off 404, sharing rule clone switched off",
"carrier: objectstack-ai/objectui#13050 · the rendered Setup page for nav_declared_sharing_rules was not measured here (no console build); the served nav and the /meta/sharing_rule list it reads were measured · noted, not filed",
"File surface beyond the claim, declared: the seal lives in packages/spec (registry, enum, schema binding, ADR-0087 entry, generated url map and reference docs) and packages/metadata-protocol (refusal text, Regime C row). The nav labels live in packages/platform-objects (Setup translations, source hashes, metadata-form bundles). Also: scripts/engine-double-contract.pinned.json, content/docs/concepts/metadata-lifecycle.mdx, and re-judged pins in objectql and cli tests. Nothing in plugin-webhooks; #24529's diff touches none of these files."
]
}
Ruling record: the OS_METADATA_WRITABLE hatch keeps one semantics for sharing_rule · epic PM session_01Y5583bs2RDd53MH6kM1ca3 (os-steve) · 2026-10-19T16:49Z
Provenance. This is open question 2 of #24550's report (6271296954), confirmed by the contract review of PR #24599 (6272404682, ③ item 1). The seat put two options to the maintainer in its chat:
A: keep one hatch semantics for every code-only type;
B: a regime-C carve-out that seals the hatch for sharing_rule.
The maintainer replied 「A」.
What it binds:
sharing_rule takes no carve-out in isOverlayAllowed. Like every other code-only type, OS_METADATA_WRITABLE=sharing_rule remains an explicit operator opt-in, and it is the delete path for any residue on an environment kernel.
os-dev-report addendum
{
"issue": 24550,
"addendum_to": 6271296954,
"status": "done",
"branch": "claude/issue-24550-sharing-rule-meta-door",
"pr": "#24599",
"session": "session_013BWJEDZYcJKmZYj6ApCCa7",
"head": "3cd2fbfa",
"summary": "Patch round on the contract review's FAIL (red gates only). Each blocker was verified in the code before it was fixed. B1: examples/app-showcase/src/coverage.ts KIND_COVERAGE gains a sharing_rule row (status demonstrated, files src/security/sharing-rules.ts, notes naming regime C). B2: packages/objectql/src/engine-security-catalog-package-door.test.ts BODIES gains a spec-valid sharing_rule body, so it registers through registerApp and its three it.each rows run with a body. package-disable-enforcement.test.ts was measured, not assumed: it iterates MetadataTypeSchema.options inside its cases and passes with sharing_rule enrolled, so no change was needed. B1's row made one more gate red, check:stack-collection-maps: the sharingRules waiver on STACK_COLLECTION_COVERAGE went stale once KIND_COVERAGE covered the kind, so 'sharingRules' was dropped from that waiver (gate and --self-test green). origin/main was merged (fa61a22), bringing in harness ec16dbe. The hatch question is left as it is for the maintainer, as instructed.",
"tests": "Full objectql suite: 448 files, 8422/8422 passed. engine-security-catalog-package-door and package-disable-enforcement by name, verbose: 33/33, including 'registers a stack-declared sharing_rule under its package' and the save-over-declared refusal on both topologies. Full showcase suite: 36 files, 431/431. pnpm --filter './examples/*' run typecheck: app-todo, app-multi-package, app-crm, embed-objectql and app-showcase all Done. Harness packages/qa/dogfood/test/upgrade-18x-harness.dogfood.test.ts run locally: 5/5 passed. metadata artifact-door-capabilities (git grep hit on the edited script): 4/4.",
"gates": "After the merge: spec check:generated exit 0. Exit 0 each: check:examples-live-imports and check:i18n-coverage (the two families new on the re-derivation), check:i18n, check:overlay-whitelist-table, check:engine-double-contract, check-adr-0087-registration, check-changeset-no-major, check:merge-driver, check:nul-bytes, check:type-check-coverage, check:cross-package-test-inputs, objectql typecheck. check:stack-collection-maps (red in CI at 90e3990) was reproduced locally (exit 1, stale waiver) and fixed (exit 0, self-test 18 assertions). CI at 3cd2fbf, all completed: 36 success, 5 skipped, 0 failed: Build Core=success; Governed Surface Queue Guard=success; Lint & Repo Gates=success; Lint · CI, release & engine gates=success; Lint · ESLint=success; Lint · PM dispatch-gates=success; Lint · docs & code guards=success; Lint · repo & tooling gates=success; Lint · scoped · query-options erasure=success; Lint · scoped · slot lookup & corpus=success; Lint · scoped · tooling self-tests=success; Test Core=success; Test Core (1/6)=success; Test Core (2/6)=success; Test Core (3/6)=success; Test Core (4/6)=success; Test Core (5/6)=success; Test Core (6/6)=success; Type Check · consumer gates=success; Type Check · debt ledger=success; Type Check · source gates=success; Type Check · workspace=success; TypeScript Type Check=success",
"mcp_calls": "1 GitHub MCP read (get_job_logs for job 118183907415). 0 MCP writes.",
"api_writes": "1 relay stroke this round: POST /repos/objectstack-ai/objectstack/dispatches, comment on #24550 (this addendum). Comments on #24550 from this run: 2 of 3.",
"open_questions": []
}
the seat's re-review on PR #24599 at b8e0baa7, CONTRACT_REVIEW_TIER, PASS (it supersedes the FAIL at 47f50805; B1–B3 resolved)
R2 harness
5/5 on the merged tree (addendum 6273585481)
hatch
ruling A (6272437439): one semantics for every code-only type, stated in the changeset
Delivered.
sharing_rule is a code-only metadata kind. A new name at the /meta door answers 403 NOT_CREATABLE, and a declared name answers 403 NOT_OVERRIDABLE. Both refusals name the two sanctioned routes: an organization rule (POST /api/v1/sharing/rules), or clone plus the activation switch.
The Setup nav lists the declared rules.
Carried.
The changeset's hatch sentence says the hatch "reopens every write on the type". A declared name stays NOT_OVERRIDABLE with the hatch open, so the precise phrase is "every write of an item no package declares". This is prose only and errs on the side of caution, so no follow-up card.
The console half is objectui#13050, still in flight. After it lands, the .objectui-sha pin move and an F1 re-run follow (method 6263864885).
The card closes completed. The dev session is archived.
Activity
objectstack-fleet commentedon Oct 19, 2026
Claim: PM loop round 11 · 2026-10-19T13:29Z
Session:
session_01Y5583bs2RDd53MH6kM1ca3Account:
os-steve(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-24550-sharing-rule-meta-doorWorktree: the cloud session's own checkout (
mode:cloud)Domain:
domain:servicesSeat:
epic:#15194(the epic lane)File surface, as measured by the dev; stop on a breach and explain it in the report:
packages/plugins/plugin-sharing/**(the nav entry; thesharing_ruletype's runtime-create flag, wherever it is registered).sharing_rule, wherever positions and permission sets are sealed.plugin-webhooks(feat(plugin-webhooks): 18.x step 1 (8b-0g′): declared webhooks are read from the registry, the seeder retires, expand-first #24529 is in flight). If the type registration you must touch is a shared list that feat(plugin-webhooks): 18.x step 1 (8b-0g′): declared webhooks are read from the registry, the seeder retires, expand-first #24529 also edits, keep your hunk minimal and say so.Container & model:
S,mode:cloud,model: TIER_DEFAULTClause-②: no (narrowing) — the dev re-measures; refusing a runtime create through
/metanarrows an accepted writeResponsibility: n/a — measured server gaps (Setup → Sharing Rules lists only stored rules once declared rules leave sys_sharing_rule (objectstack C3 stage 9) objectui#12982 report 6268367666) under ruling A (6258883445)
Thread-read: 6268367666
Serial constraints cleared:
objectstack-fleet commentedon Oct 19, 2026
os-dev-report
{
"issue": 24550,
"status": "done",
"branch": "claude/issue-24550-sharing-rule-meta-door",
"pr": "#24599",
"session": "session_013BWJEDZYcJKmZYj6ApCCa7",
"premise_still_valid": true,
"summary": "Premise verified on origin/main 04669a4: sharing_rule had no DEFAULT_METADATA_TYPE_REGISTRY entry, so getMetaTypes() derived allowRuntimeCreate: true from the spelling contract, and saveMetaItem's isRuntimeCreateAllowed took the no-static-entry arm. The ablation reproduced it: PUT /meta/sharing_rule/probe_meta_rule answered 200 'Saved sharing_rule ... (env-wide)'. Mechanism measured: the position/permission-set seal (refusePackagedBaseOverride, allowEnvironmentOverlay: false) refuses only writes over a PACKAGED name, and both types keep allowRuntimeCreate: true. The security-catalog namespace rule judges package registration, not a /meta save. So the fit is capability's code-only pair: sharing_rule joins MetadataTypeSchema and the registry with allowRuntimeCreate: false and allowEnvironmentOverlay: false, and its SharingRuleSchema binding moves into the kind map. Result: 403 NOT_CREATABLE for a new name (publish and draft), 403 NOT_OVERRIDABLE for a declared one, on every kernel, and /meta/types advertises false. sharing_rule gains an ADR-0126 Regime C row (clone: POST /api/v1/sharing/rules; switch: the activation ledger), and both refusals name those two paths and not the hatch, under the REST door's 500-character bound. The first cut was truncated there, as the showcase boot showed, and was fixed. ADR-0087 semantic entry sharing-rule-runtime-create-withdrawn; launch-window minor changeset with FROM to TO and the one-line fix. Setup gains nav_declared_sharing_rules (type url, /apps/setup/metadata/sharing_rule?scope=environment) beside nav_sharing_rules, with labels in en/zh-CN/ja-JP/es-ES. No legitimate 18.0 writer of sharing_rule items through saveMetaItem was found: declarations reach the registry through artifact ingest (registerApp), and the organization door writes sys_sharing_rule rows. Item 3 was measured, not built; see open_questions.",
"tests": "Head 47f5080. HTTP-door pin packages/runtime/src/meta-sharing-rule-door.test.ts (real HttpDispatcher, protocol and repository, both kernels): 10/10. Ablation: the registry entry deleted via scripts/ablation-replace.mjs, spec rebuilt, and ablation-dist-preflight --absent confirmed the marker absent from 232 built files (exit 0). Then 6 failed / 4 passed: the create cases got 200 'Saved sharing_rule probe_meta_rule (env-wide, state=active|draft)', and /meta/types returned allowRuntimeCreate true. The declared-name case stayed green, because the package door sealed declared names before this change. Restore: HEAD blob hash match, whole-tree clean, rebuilt, preflight present in 16 files, 10/10 green. Suites: spec full (22469 passed; the 3 pins that asserted sharing_rule as a plugin kind were re-judged, then 216/216 on those files); metadata-protocol full (20725 passed, 19 skipped, after enrolling sharing_rule in protocol.code-only-types and protocol.recovery-doors-emit-mutation); plugin-sharing full (1161/1161); platform-objects full, then the two re-judged count pins (73/73); objectql protocol-meta and protocol-meta-types-rich (100/100; the two #6245 open-door pins flipped to 403 NOT_CREATABLE, and the 422 behind OS_METADATA_WRITABLE=sharing_rule); rest meta-unknown-type-read-refusal (21/21); runtime cross-field-refusal-operand-withhold (11/11) and meta-managed-content-seal; cli unit generate-file-name-registry-parity (40/40); cli integration metadata-type-schema-gate (8/8, after sharing_rule was added to GATED_AT) and organization-ownership-apply (run locally because both enumerate the registry); metadata/rest/runtime/lint/client registry readers, 16 files, 364/364. Typecheck: spec, metadata-protocol, plugin-sharing, platform-objects, runtime and objectql all Done, 0 errors. Residue probe (throwaway file, deleted): deleteMetaItem of a pre-existing stored sharing_rule row succeeds on a host-config kernel and answers 403 NOT_CREATABLE on an environment kernel unless OS_METADATA_WRITABLE=sharing_rule is set. Showcase boot (pnpm dev -- --fresh, port 38558): PUT new 403 NOT_CREATABLE, whole message naming both routes; PUT share_new_inquiries_with_field_ops 403 NOT_OVERRIDABLE with the regime sentence; /meta/types sharing_rule allowRuntimeCreate false; PUT a new position 200; GET /meta/app/setup serves nav_declared_sharing_rules in group_access_control between nav_sharing_rules and nav_record_shares, and the zh-CN label is served; POST /sharing/rules 201, and the same-name guard answers 409. The rendered console was NOT MEASURED: no console build in this container; objectui#13050 renders the page.",
"gates": "dispatch-gates.mjs --commands --repo objectstack-ai/objectstack (derived at 03ec635, exit 0): 122 commands, plus the 34 non-self-test artifact-roster rows from STDERR, 164 in the final union. Each exit code was captured into a TSV before any pipe. Final battery at 03ec635: 158 exit 0. NOT MEASURED, not findings: check-engine-split-ratio --days 90 (exit 2, shallow history) and check-plugin-teardown-shape --self-test (exit 3, fixture commit not in the shallow clone); check-closing-target-claim, check-partof-closing-keyword and check-single-claim-paths (exit 2), and pm/check-governed-queue-guard (exit 1, no GITHUB_EVENT_PATH), all PR-context-only. The first battery found three real reds, fixed and green on the final battery: check:engine-double-contract (the new test's doubles; ledger --write), check:i18n (metadata-form bundles regenerated, zh-CN/ja-JP/es-ES translated by hand), and check:overlay-whitelist-table (metadata-lifecycle.mdx count 28 to 29, plus a sharing_rule row). Its other reds were prerequisite refusals (dist absent mid-build), green on re-run. Re-derived at final head 47f5080: one new family, check:cli-test-child-env, exit 0. The changeset families re-run at 47f5080, all exit 0: check-adr-0087-registration ('registered sharing-rule-runtime-create-withdrawn (new here)'), check-changeset-no-major, check-empty-changeset, check-changeset-fixed, check:changeset-gate-self-tests, check:nul-bytes, check:doc-authoring. --ran reconciliation: 134 derived families accounted for, 0 NOT-MEASURED as the runner declared it (the exit codes are in the TSV, not the --ran file). spec check:generated green after gen:meta-url-spelling and gen:schema plus gen:docs. CI check-runs on PR #24599: in_progress at report time, not awaited per contract.",
"mcp_calls": "0 GitHub MCP calls. 1 claude-code-remote call (add_repo objectstack-ai/objectui, read-only; it answered read_available and attached nothing). The objectui report comment 6268367666 could not be read: the REST API and the web page answered 403 for objectui in this session, so the card body's restatement of server_gaps was used.",
"api_writes": "2 relay strokes, POST /repos/objectstack-ai/objectstack/dispatches (fleet-write, as objectstack-fleet[bot]): (1) pr_create, which executes as POST /repos/objectstack-ai/objectstack/pulls (draft) and POST /repos//issues/24599/assignees [os-steve]; the dispatch tool exited 6 UNCONFIRMED at 300 s (run 39280041843 queued), and the target read back PR #24599, draft, assignee os-steve, body byte-identical (8467 bytes). (2) this os-dev-report comment, POST /repos//issues/24550/comments. git push is not counted. Labels: none written.",
"open_questions": [
{
"question": "Clause-② as measured: the claim carried 'no (narrowing)', but the diff also widens surface. MetadataType gains sharing_rule; /meta/sharing_rules now folds to sharing_rule (on main the plural was not in META_URL_TO_SINGULAR); Setup gains an entry. Which line does the PR carry?",
"options": ["A yes (narrowing): what the PR body line 2 and the changeset carry; minor; check-adr-0087-registration reads the narrowing arm", "B no (narrowing), as claimed"],
"recommendation": "A, because the clause asks whether the card widens the accept set or the public surface, and three measured readings say it does. The narrowing arm still marks it BREAKING, and the changeset level (minor) is the same either way. Decided as A per the dispatch's 'as measured'."
},
{
"question": "OS_METADATA_WRITABLE=sharing_rule still opens a runtime create, as it does for every code-only type (job, agent, capability, api, field, picklist). Should regime C seal the hatch for sharing_rule as well?",
"options": ["A keep the hatch working, unprescribed: the refusals never name it; it stays the operator's repair path for items stored through the old door on an environment kernel (measured: DELETE answers 403 NOT_CREATABLE there without it)", "B seal it: a new registry flag or regime-C carve-out in isOverlayAllowed, so no operator setting re-opens the third source"],
"recommendation": "A, because on the long-term axis one hatch semantics across all code-only types beats a regime-specific carve-out. On the error-proofing axis the AI author is never shown the hatch: the regime sentence omits it, as ADR-0126's builders do. On the startup-focus axis B adds machinery with no measured pull. A security or permission boundary sits on the human floor, though, so this is flagged for the maintainer rather than closed."
},
{
"question": "Item 3a: should /meta/sharing_rule items carry the activation ledger's reading?",
"options": ["A no: the metadata protocol reads sys_metadata_activation for no type (position, permission, flow and action /meta items carry none either), so this is a new cross-layer seam", "B yes: decorate /meta items of ledger-switched types with the ledger state", "C answer it on the sharing door instead: an admin read on GET /sharing/rules that lists switched-off declared rules with active false, without touching listRules, which feeds every enforcement path"],
"recommendation": "A for this card, with C as the shape if the console's two reads become a measured cost. The card's own bar (removes a client read without a new surface) rules out B, which is a new seam reading a runtime table from the metadata layer for one type. C keeps the authority (the ledger) where its reader already lives. Built: nothing."
},
{
"question": "Item 3b: GET /sharing/rules/:name answers 404 RULE_NOT_FOUND for a declared rule the ledger switched off (measured on the showcase), so Clone falls back to the pre-filled New form. Change it?",
"options": ["A a follow-up card: getRule answers the declared projection with active false for a ledger-off declared rule, read from declaredSource without the ledger filter, on the admin read only (resolveRules and listRules unchanged), as a Clause-② yes (widening) change on an existing route", "B leave the 404; the console keeps its fallback"],
"recommendation": "A, because the console needs it for a real flow (Clone of a switched-off declared rule) and it removes a client fallback without a new route. It must not reach declaredRules(), which every enforcement path lists through. Report only here, per the card."
}
],
"out_of_scope_findings": [
"carrier: #24550 (this card's item 3) · GET /sharing/rules/:name 404 for a ledger-off declared rule; recommendation in open_questions · noted, not filed · dedupe: getRule declaredRules ledger-off 404, sharing rule clone switched off",
"carrier: objectstack-ai/objectui#13050 · the rendered Setup page for nav_declared_sharing_rules was not measured here (no console build); the served nav and the /meta/sharing_rule list it reads were measured · noted, not filed",
"File surface beyond the claim, declared: the seal lives in packages/spec (registry, enum, schema binding, ADR-0087 entry, generated url map and reference docs) and packages/metadata-protocol (refusal text, Regime C row). The nav labels live in packages/platform-objects (Setup translations, source hashes, metadata-form bundles). Also: scripts/engine-double-contract.pinned.json, content/docs/concepts/metadata-lifecycle.mdx, and re-judged pins in objectql and cli tests. Nothing in plugin-webhooks; #24529's diff touches none of these files."
]
}
Generated by Claude Code
objectstack-fleet commentedon Oct 19, 2026
Ruling record: the
OS_METADATA_WRITABLEhatch keeps one semantics forsharing_rule· epic PMsession_01Y5583bs2RDd53MH6kM1ca3(os-steve) · 2026-10-19T16:49ZProvenance. This is open question 2 of #24550's report (6271296954), confirmed by the contract review of PR #24599 (6272404682, ③ item 1). The seat put two options to the maintainer in its chat:
sharing_rule.The maintainer replied 「A」.
What it binds:
sharing_ruletakes no carve-out inisOverlayAllowed. Like every other code-only type,OS_METADATA_WRITABLE=sharing_ruleremains an explicit operator opt-in, and it is the delete path for any residue on an environment kernel.objectstack-fleet commentedon Oct 19, 2026
os-dev-report addendum
{
"issue": 24550,
"addendum_to": 6271296954,
"status": "done",
"branch": "claude/issue-24550-sharing-rule-meta-door",
"pr": "#24599",
"session": "session_013BWJEDZYcJKmZYj6ApCCa7",
"head": "3cd2fbfa",
"summary": "Patch round on the contract review's FAIL (red gates only). Each blocker was verified in the code before it was fixed. B1: examples/app-showcase/src/coverage.ts KIND_COVERAGE gains a sharing_rule row (status demonstrated, files src/security/sharing-rules.ts, notes naming regime C). B2: packages/objectql/src/engine-security-catalog-package-door.test.ts BODIES gains a spec-valid sharing_rule body, so it registers through registerApp and its three it.each rows run with a body. package-disable-enforcement.test.ts was measured, not assumed: it iterates MetadataTypeSchema.options inside its cases and passes with sharing_rule enrolled, so no change was needed. B1's row made one more gate red, check:stack-collection-maps: the sharingRules waiver on STACK_COLLECTION_COVERAGE went stale once KIND_COVERAGE covered the kind, so 'sharingRules' was dropped from that waiver (gate and --self-test green). origin/main was merged (fa61a22), bringing in harness ec16dbe. The hatch question is left as it is for the maintainer, as instructed.",
"tests": "Full objectql suite: 448 files, 8422/8422 passed. engine-security-catalog-package-door and package-disable-enforcement by name, verbose: 33/33, including 'registers a stack-declared sharing_rule under its package' and the save-over-declared refusal on both topologies. Full showcase suite: 36 files, 431/431. pnpm --filter './examples/*' run typecheck: app-todo, app-multi-package, app-crm, embed-objectql and app-showcase all Done. Harness packages/qa/dogfood/test/upgrade-18x-harness.dogfood.test.ts run locally: 5/5 passed. metadata artifact-door-capabilities (git grep hit on the edited script): 4/4.",
"gates": "After the merge: spec check:generated exit 0. Exit 0 each: check:examples-live-imports and check:i18n-coverage (the two families new on the re-derivation), check:i18n, check:overlay-whitelist-table, check:engine-double-contract, check-adr-0087-registration, check-changeset-no-major, check:merge-driver, check:nul-bytes, check:type-check-coverage, check:cross-package-test-inputs, objectql typecheck. check:stack-collection-maps (red in CI at 90e3990) was reproduced locally (exit 1, stale waiver) and fixed (exit 0, self-test 18 assertions). CI at 3cd2fbf, all completed: 36 success, 5 skipped, 0 failed: Build Core=success; Governed Surface Queue Guard=success; Lint & Repo Gates=success; Lint · CI, release & engine gates=success; Lint · ESLint=success; Lint · PM dispatch-gates=success; Lint · docs & code guards=success; Lint · repo & tooling gates=success; Lint · scoped · query-options erasure=success; Lint · scoped · slot lookup & corpus=success; Lint · scoped · tooling self-tests=success; Test Core=success; Test Core (1/6)=success; Test Core (2/6)=success; Test Core (3/6)=success; Test Core (4/6)=success; Test Core (5/6)=success; Test Core (6/6)=success; Type Check · consumer gates=success; Type Check · debt ledger=success; Type Check · source gates=success; Type Check · workspace=success; TypeScript Type Check=success",
"mcp_calls": "1 GitHub MCP read (get_job_logs for job 118183907415). 0 MCP writes.",
"api_writes": "1 relay stroke this round: POST /repos/objectstack-ai/objectstack/dispatches, comment on #24550 (this addendum). Comments on #24550 from this run: 2 of 3.",
"open_questions": []
}
Generated by Claude Code
objectstack-fleet commentedon Oct 19, 2026
Landed and closed · epic PM
session_01Y5583bs2RDd53MH6kM1ca3(os-steve) · 2026-10-19T19:51Z. PR #24599 (closePUT /meta/sharing_rule; Setup lists declared sharing rules) has merged.merged: true; merge commit1e8b6284cb8e0baa7,CONTRACT_REVIEW_TIER, PASS (it supersedes the FAIL at47f50805; B1–B3 resolved)Delivered.
sharing_ruleis a code-only metadata kind. A new name at the/metadoor answers403 NOT_CREATABLE, and a declared name answers403 NOT_OVERRIDABLE. Both refusals name the two sanctioned routes: an organization rule (POST /api/v1/sharing/rules), or clone plus the activation switch.Carried.
NOT_OVERRIDABLEwith the hatch open, so the precise phrase is "every write of an item no package declares". This is prose only and errs on the side of caution, so no follow-up card..objectui-shapin move and an F1 re-run follow (method 6263864885).The card closes
completed. The dev session is archived.