Skip to content

feat(service-settings)!: the settings audit trail's global rung moves to a deployment-level sibling, sys_platform_setting_audit (18.x step 2, expand-first) - #24590

Merged
objectstack-fleet[bot] merged 14 commits into
mainfrom
claude/issue-24530-8b0e-deployment-level
Oct 19, 2026
Merged

objectstack-fleet[bot] merged 14 commits into
mainfrom
claude/issue-24530-8b0e-deployment-level

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Closes #24530
Clause-②: yes (narrowing)

18.x line, step 2 (8b-0e′), expand-first. This is PR 2a only.

The sys_secret / sys_flow_credential flip (ruling record 6259141885, #24435 Q1 A, for the latter) is not in this PR. It moves to step 6, with the opened ceremony; see "Measured" below.

⛔ Merge gate. This PR stays a draft until #24522's upgrade harness (#24552) has merged. Then it merges main, runs the harness, and lands only when R1–R4 hold with the harness green.

What changes

  1. New sys_platform_setting_audit, the settings audit trail's global rung, created fresh:

    • systemFields: { tenant: false }: no organization column;
    • requiredPermissions: ['manage_platform_settings'], as sys_platform_setting has;
    • managedBy: 'engine-owned', with reads only on the data API;
    • the same row shape as sys_setting_audit, with scope always global.

    It registers with service-settings (the manifest), joins SETTINGS_READ_DOOR_OBJECTS (so each namespace's readPermission applies there too), and joins PLATFORM_OBJECTS_BY_PACKAGE.

  2. The writer routes by rung (buildSettingAuditWriter, through one predicate, settingAuditObjectFor):

    • scope === 'global' goes to the sibling, with no organization;
    • tenant and user rows stay in sys_setting_audit, stamped as before;
    • each insert names its table literally, so the tenant-audit census keeps every write site statically decidable.
  3. Regenerated with the repo's tooling:

    • scripts/platform-object-tenancy-census.json: the sibling is added, out of reach because systemFields.tenant is false;
    • the tenant-audit census page and counts: one more write call site, with the hand-written figures the gate holds updated to match.
  4. Inventory: the sibling's row, placed next to sys_setting_audit's (column-drop, no column).

  5. Platform checklist: two items that read the global rung's audit rows from sys_setting_audit are re-pointed, each with a revision bump and a history entry.

Measured: why sys_secret and sys_flow_credential are untouched

Measured: the 18.0 DDL for the two tables, populated with 18.0-shaped rows, then the engine's schema sync and the v18 boot guard's own predicate.

declared shape boot guard (findV17ShapeTables) drift (detectManagedDrift)
systemFields: { tenant: false }, organization_id not declared refuses: ["sys_flow_credential","sys_secret"] drop_column, destructive, on both tables
tenancy: { enabled: false }, organization_id kept declared [] []

The first row refuses every 18.0 database at boot, which breaks R2. The second escapes the guard, and the epic seat rules that escape a gap, not a route. The kept ceremony class would also block its column-drops step on a column the runtime still declares: measured on organization-ownership-boot-refusal-order.dogfood.test.ts when the two objects' inventory fates were moved, and reverted. So both objects ship as 18.0 shipped them, and their flip lands with step 6.

18.0 rows

  • Nothing is moved, deleted or re-stamped, and no column is dropped.
  • An 18.0 install wrote its global-rung audit rows into sys_setting_audit, stamped with the Default Organization. They stay there, readable through the data API as before.
  • The global rung's history is the sibling plus sys_setting_audit rows selected by scope = 'global', never by a NULL organization.
  • There is no in-process history reader to union today: the only readers are the two data-API grids behind the settings read door. Both serve their rows, as the dogfood pin shows.

The step-5/6 ceremony owes

table owed
sys_setting_audit move the scope = 'global' rows to sys_platform_setting_audit: an inventory departures entry, plus a MOVES entry in organization-ownership-apply.ts like sys_setting's global-rung-move. Then scope's global option can retire, and 8e's NOT NULL applies to the rest.
sys_secret the column-less flip with step 6: the declaration goes to systemFields: { tenant: false }, the inventory fate goes 3 → column-drop, and the column-drops step drops organization_id. The settings writer stops stamping it.
sys_flow_credential the same flip with step 6, plus column-drops.
sys_platform_setting_audit nothing.

Step 7 removes the dual read: once the move has run, the global rung's history is the sibling alone.

Proof

  • R1: a fresh pnpm dev -- --fresh showcase boot.
    • GET /api/v1/discovery answered 200.
    • PUT /api/settings/ai (encrypted, global) and PUT /api/settings/branding (tenant) answered 200.
    • /data/sys_platform_setting_audit lists the global rows with no organization, and /data/sys_setting_audit the tenant rows, stamped.
  • R2:
  • R3: the same harness run's v17 case is refused with the guard's code.
  • R4: OS_TENANCY_POSTURE=isolated pnpm dev -- --fresh exits 1 with tenancy posture 'isolated' is not supported in 18.0 (NOT_IMPLEMENTED).

New pins:

  • service-settings/src/settings-deployment-level-expand.test.ts: a real engine under single with a live D9-stamp control. The new write shape, and the dual read on an 18.0-shaped row.
  • service-settings/src/settings-secret-organization.test.ts: per-rung routing through the one predicate.
  • qa/dogfood/test/settings-audit-global-rung-sibling.dogfood.test.ts: two showcase boots over one file, the second with an 18.0-shaped stamped global audit row.
  • The sibling also joins the D7 family pin, the read-door pin and the manifest pin.

Ablation X6: the routing predicate was pinned to sys_setting_audit, via scripts/ablation-replace.mjs, rebuilt, and checked by ablation-dist-preflight in both directions.

  • Red: the expand pin 2/4, the routing pin 2/6, the dogfood pin 2/4.
  • Restored to the HEAD blob.
  • The first attempt was a no-op: the build refused the marker spelling, and no pin ran.

Acceptance notes

  • A global-rung audit row now needs manage_platform_settings to be read through the data API. That is the narrowing the changeset states, with its remedy.
  • docs/qa checklist items 7 and 29 were re-pointed because their clauses stopped being true. Not in the claim's named surface; noted for the seat.

Generated by Claude Code

claude added 10 commits October 19, 2026 12:55
…bal-rung settings audit to a sibling (WIP)

Claude-Session: https://claude.ai/code/session_01HZT9daB4YX41N1SVVxYcek
Co-authored-by: Claude <noreply@anthropic.com>
…ped rows still read (WIP)

Claude-Session: https://claude.ai/code/session_01HZT9daB4YX41N1SVVxYcek
Co-authored-by: Claude <noreply@anthropic.com>
…rung to its sibling; checklist re-pointed (WIP)

Claude-Session: https://claude.ai/code/session_01HZT9daB4YX41N1SVVxYcek
Co-authored-by: Claude <noreply@anthropic.com>
…rally; tenant-audit census regenerated

Claude-Session: https://claude.ai/code/session_01HZT9daB4YX41N1SVVxYcek
Co-authored-by: Claude <noreply@anthropic.com>
…bel; query options typed in the expand pin

Claude-Session: https://claude.ai/code/session_01HZT9daB4YX41N1SVVxYcek
Co-authored-by: Claude <noreply@anthropic.com>
…0e-deployment-level

Claude-Session: https://claude.ai/code/session_01HZT9daB4YX41N1SVVxYcek
Co-authored-by: Claude <noreply@anthropic.com>
… ceremony drops their declared column

The kept ceremony class blocks its column-drops step on a column the
runtime still declares, so the fate moves with the declaration, in step 5.

Claude-Session: https://claude.ai/code/session_01HZT9daB4YX41N1SVVxYcek
Co-authored-by: Claude <noreply@anthropic.com>
…pped them; this step builds the settings-audit sibling only

Per the epic seat's binding scope correction (step 0's measured plan,
os-dev-report 6268559156): the column-less flip of sys_secret and
sys_flow_credential moves to step 6, with the opened ceremony.

Claude-Session: https://claude.ai/code/session_01HZT9daB4YX41N1SVVxYcek
Co-authored-by: Claude <noreply@anthropic.com>
…_flow_credential stayed tenant-scoped

Claude-Session: https://claude.ai/code/session_01HZT9daB4YX41N1SVVxYcek
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 4 package(s): @objectstack/cli, @objectstack/platform-objects, @objectstack/service-settings, @objectstack/spec, touching 22 documentable anchor(s). ⚠️ 1 changed file(s) yielded no anchor (packages/platform-objects/src/system/index.ts), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files.

60 hand-written doc(s) name something this change touched — list omitted above 15 rows. Re-derive on the tree named below: node scripts/docs-audit/affected-docs.mjs --json 8fbbd5082f3fcde0d972c76cfcd4d286c4eb4fa1.

⛔ 13 release-owned page(s) also affected — read-only, see AGENTS.md Documentation Guardrails.

What this run could not see
  • 1 changed file(s) yielded no anchor (packages/platform-objects/src/system/index.ts) — pages documenting those are invisible to this run
  • 1 cross-cutting symbol(s) contributed no route anchor: isSystem (5 routes)
  • 2 anchor(s) matched too much of the corpus to be a work list: created_at (literal, 38 pages), sys_user (literal, 41 pages)
  • 10 name(s) were too generic to anchor anything (single lowercase words)
  • the SDK route bridge reached 54 of 206 client-bound route-ledger rows — the other 152 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 152: 0 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 55 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 97 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.
  • a key NAME is not a key, so the hand re-read the line above prescribes can land on the wrong schema. The same spelling is authorable on one governed type and a [REMOVED] tombstone on another for each of active, aria, joins, objects, template, tools and version (censused on [finding] tools is a key on BOTH AgentSchema (tombstoned, dead) and SkillSchema (live, cloud-attested), so a name-based search attributes skill examples to the agent key — it produced a false stop-the-line alarm on PR #19059 #19093 over the liveness ledger's governed types, top-level keys); nothing in a search result distinguishes the two, so a grep hit on a LIVE example reads as evidence about the DEAD key. Measured on fix(spec): the agent.tools liveness row says dead — it claimed live on a key the schema tombstoned #19059: content/docs/ai/agents.mdx was reported as contradicting the agent.tools tombstone over its tools: example at :161, which is inside the defineSkill({ block opened at :155 — the page was already correct. Settle ownership by PARSING the value against both schemas, never by the name: that literal PASSES SkillSchema, and as an AgentSchema it FAILS at tools with the tombstone prescription. ⛔ These names are not the whole class — a key retired through a .strict() guidance map leaves no tombstone in the walked shape and none of them here (tool.category, live as AIToolDefinition.category).

Coarse fallback — 151 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 8fbbd5082f3fcde0d972c76cfcd4d286c4eb4fa1 → packageMentionDocs.

Which tree this was computed on

This run read content/docs from aa347d082214b0ff47d6ca657299c728f29d29b9 — the merge of head 2b295cabd4d838576682f001485858831f0be334 into base 8fbbd5082f3fcde0d972c76cfcd4d286c4eb4fa1, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin aa347d082214b0ff47d6ca657299c728f29d29b9 && git checkout aa347d082214b0ff47d6ca657299c728f29d29b9
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 8fbbd5082f3fcde0d972c76cfcd4d286c4eb4fa1 2b295cabd4d838576682f001485858831f0be334 && git checkout -B drift-repro 8fbbd5082f3fcde0d972c76cfcd4d286c4eb4fa1 && git merge --no-ff 2b295cabd4d838576682f001485858831f0be334

node scripts/docs-audit/affected-docs.mjs --json 8fbbd5082f3fcde0d972c76cfcd4d286c4eb4fa1

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs 8fbbd5082f3fcde0d972c76cfcd4d286c4eb4fa1 → pass the list as
args.docs, on the commit named under Which tree this was computed on.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 070d81252b3c534540607a78cd6e8782808efaa2
Local-runs: none
Scope: packages/spec/src/system/constants/platform-object-names.ts, packages/platform-objects/src/system/sys-platform-setting-audit.object.ts, packages/platform-objects/src/system/index.ts, packages/platform-objects/src/deployment-level-no-tenant-column.test.ts, packages/services/service-settings/src/settings-service-plugin.ts, packages/services/service-settings/src/settings-read-door.ts, packages/services/service-settings/src/manifest.ts, packages/services/service-settings/src/settings-service.types.ts, packages/services/service-settings/src/settings-deployment-level-expand.test.ts, packages/services/service-settings/src/settings-secret-organization.test.ts, packages/services/service-settings/src/settings-read-door.pin.test.ts, packages/services/service-settings/src/manifest.test.ts, packages/services/service-settings/src/config-change-audit.test.ts, packages/services/service-settings/src/settings-engine-bind-window.test.ts, packages/qa/dogfood/test/settings-audit-global-rung-sibling.dogfood.test.ts, packages/cli/src/utils/organization-ownership-inventory.ts, scripts/platform-object-tenancy-census.json, docs/audits/2026-08-tenant-audit-write-call-sites.counts.md, docs/qa/platform-checklist/areas/platform-core.json + packages/platform-objects/src/system/sys-setting-audit.object.ts, packages/platform-objects/src/system/sys-platform-setting.object.ts, packages/platform-objects/src/system/sys-secret.object.ts, packages/services/service-automation/src/sys-flow-credential.object.ts, packages/runtime/src/organization-ownership-boot-guard.ts, packages/services/service-settings/src/settings-service.ts, packages/services/service-settings/src/manifests/*.manifest.ts, packages/objectql/src/lifecycle/lifecycle-settings.ts, packages/cli/src/utils/organization-ownership-apply.ts, packages/qa/dogfood/test/upgrade-18x-harness.dogfood.test.ts, packages/qa/dogfood/test/upgrade-harness/fixture-18.0/manifest.json, packages/platform-objects/scripts/i18n-extract.config.ts, packages/platform-objects/src/apps/translations/bundle-ownership.test.ts, docs/adr/0131-total-organization-ownership-no-null-organization-id.md

Reviewer: an isolated at-tier reviewer subagent of the adopting seat (epic:#15194), read-only: the diff origin/main...refs/review/pr-24590 (merge-base 04669a467, origin/main at 5a871e4e4), the PR body, card #24530 with claim 6267470053 and os-dev-report 6270530684, rulings 6266750393 / 6267391172 / 6270035914 on #15194, ruling 6257510973 (#24377, Q4 A), step 0's measured plan 6268559156 (#24522), the merged harness and its fixture on origin/main, AGENTS.md, scripts/check-changeset-*.mjs, and the head's check-runs. The head did not move while this was written. The --paths reading of the file list is the schema face (one published-schema hit, platform-object-names.ts); the brief asks for the narrowing face, and both map to this tier. The prose faces (.changeset/, content/docs/) are read against the diff below and are no remainder.

① Derived judgments

(a) Fresh install — PASS. sys-platform-setting-audit.object.ts:44-47 declares managedBy: 'engine-owned', systemFields: { tenant: false } and requiredPermissions: ['manage_platform_settings'], with enable.apiMethods: ['get', 'list'] (:167-171): the same posture as sys_platform_setting.object.ts:53-57, :148. The D7 family pin (deployment-level-no-tenant-column.test.ts:39-40, the new row) asserts no injected or declared organization_id, the systemFields opt-out and the platform-scoped capability, so the created table has no organization column; the regenerated census (scripts/platform-object-tenancy-census.json, sys_platform_setting_audit, reach: out, reason systemFields.tenant: false) says the same from the registered schema. The read door is right: SETTINGS_READ_DOOR_OBJECTS (settings-read-door.ts:44-49) gains the sibling and registerSettingsReadDoor (:99-106) iterates that list, so the namespace predicate is ANDed into every find/findOne/count/aggregate on it; the read-door pin seeds a sibling row per namespace (settings-read-door.pin.test.ts:131-136) and its per-object for (const object of SETTINGS_READ_DOOR_OBJECTS) battery and the by-name registration check (hasObjectMiddleware) now cover it. Who may read a new global-rung row: a system context, or a principal holding manage_platform_settings (object permission) whose capabilities also satisfy the namespace's readPermission. Every stock global manifest (ai, auth, knowledge, mail, sms, storage in service-settings/src/manifests/, and objectql's lifecycle-settings.ts:23-24) already names manage_platform_settings as its readPermission, so the door, the setting and its trail agree.

(b) 18.0 database — PASS, the report's claim verified. The writer routes by rung only (settings-service-plugin.ts:553-573, settingAuditObjectFor), and sys-setting-audit.object.ts is untouched: its scope select keeps global, so the 18.0 global rows stay readable where they are. I looked for every reader of settings history: in this repo the non-test mentions of sys_setting_audit are the writer, the read door, settings-service.ts docblocks (:1333, :1859) and config-change-audit.ts prose; there is no route, service method or in-process reader that lists audit rows. In ../objectui (at 78b07f4) no source names sys_setting_audit, a settings history view or an audit grid, and the console bundle under packages/console/dist carries no such string. The only readers are the generic data-API grids GET /data/sys_setting_audit and GET /data/sys_platform_setting_audit, both behind the read door, and the dogfood pin reads the 18.0 row through the first and the new row through the second (settings-audit-global-rung-sibling.dogfood.test.ts:139-155). Nothing that showed a global-rung row before stops showing it. A reader that wants the global rung's whole history reads both tables, selected by scope = 'global': F3 holds (the fixture's 4 sys_setting_audit rows all carry org_mvf8cxynmka5sb9b), and the pins select by scope, never by a NULL organization (settings-deployment-level-expand.test.ts:205-224). Not building a union API is also what ADR-0131 D7's Presentation rule asks: no surface merges two sources server-side.

(c) Nothing moves, deletes or re-stamps 18.0 rows; no column drops — PASS. The diff touches no ceremony, apply, migration or schema-sync code; organization-ownership-apply.ts and its MOVES table are unchanged; the only inventory change is one added row for the new table (organization-ownership-inventory.ts:622-628). The dogfood pin's case B boots HEAD over a database holding an 18.0-shaped stamped global row and asserts, after the stack stops, that the row is still in sys_setting_audit with its organization (:157-164). The harness's own case 3 would red on any 18.0 row moved or re-stamped (upgrade-18x-harness.dogfood.test.ts:101-120).

(d) R1–R4 and the boot guard (F2) — PASS. F2: sys-secret.object.ts is blob 6c09998… on both origin/main and the head, and service-automation/src/sys-flow-credential.object.ts is blob daa0672… on both: byte-identical, neither flipped; no file in the diff changes either object's tenancy, and their inventory rows keep fate: 'attribution'. The guard: findV17ShapeTables (organization-ownership-boot-guard.ts:196-218) flags an object with systemFields.tenant === false, no declared organization_id, and a PHYSICAL organization_id column; the sibling is created fresh by createTable from a declaration with no such column, and on an 18.0 database the table does not exist before sync (pragma_table_info of a missing table answers no rows), so it can never be flagged. The guard's code is untouched, so R3 (v17 refused with the guard's code) and R4 (walled posture refused) are the same code paths as on main; the dogfood pin composes OrganizationOwnershipBootGuardPlugin and the audit plugin on both boots. R1 is the dogfood pin's case A plus the report's fresh showcase boot. R2: the fixture's reshaped sys_setting_audit rows (id, organization_id ×4) are never written by this PR; the dev ran the harness 5/5 at f6128e3, which IS the head #24552 merged as ec16dbe2e. What remains procedural, not a code defect, is in ③: the PR head has not merged main since ec16dbe2e, so the merged harness has not run on this tree in CI (and cannot: dogfood is main-only in CI and #24554's opt-in lane is unmerged).

(e) Complete feature (6270035914) — PASS. New installs write the new shape through a live predicate; the sibling is registered in the service manifest (manifest.ts:29), the read door and PLATFORM_OBJECTS_BY_PACKAGE; the 18.0 shape is still read. Nothing is dormant or waits for a later PR to switch it on; what is deferred (the move of the 18.0 global rows) is deferred by the line's own expand-first rule and is written down table by table. Each insert names its table literally (settings-service-plugin.ts:647-658), so the tenant-audit census stays statically decidable (one new elevated site, counts regenerated: 231 → 232).

(f) The open questions — all five "A" readings are sound. (1) Reverting the sys_secret / sys_flow_credential flip: correct under F2 and flags[0]; measured both spellings and the ceremony-class block. (2) No union reader: correct, there was none to union, and D7 forbids a merged list. (3) Name and shape: sys_platform_setting_audit mirrors sys_platform_setting; the field set, indexes and enable block match sys_setting_audit's one for one, with scope kept as a one-option select so one reader reads both tables with the same columns, which is what step 0's plan asked ("same fields"). (4) One PR, Closes #24530: consistent with 6270035914 item 2, which already places the deferred flips in the steps 5+6 landing. (5) Changeset disposition: judged in ②.

Minor, non-blocking: settings-service.ts:1333 still names three read-door objects in prose, and config-change-audit.test.ts:465's describe title still says "sys_setting_audit keeps its rows" while the helper now reads the sibling — cosmetic. The sibling, like sys_platform_setting, sys_metadata_commit and sys_migration_journal, is outside the platform-objects i18n extract roster (i18n-extract.config.ts:190, bundle-ownership.test.ts:19-42), so its labels ship untranslated; that mirrors the precedent and no gate asks otherwise.

② Semver level

Clause-②: yes (narrowing) on the PR body and in .changeset/24530-settings-audit-global-rung-sibling.md; four touched published packages (platform-objects, service-settings, spec, cli) at minor; @objectstack/dogfood is private. The yes arm is earned (a new object, a new exported predicate and two constants, a new registry name) and minor satisfies the LEVEL axis. The narrowing arm is BREAKING and is carried as the launch-window convention requires: ! in the title, the BREAKING banner, before/now/remedy in the body, and exactly one ADR-0087 marker, not-required (no-migration-prescription), a documented category (ADR-0087 :735); the body carries no FROM → TO block, so the category's refusal does not fire, and Check Changeset concluded success. The narrowing is real but small: a principal who could list a global-rung audit row in sys_setting_audit by object grant alone (a host whose engine offers no middleware seam, or a host-registered global manifest with a weaker readPermission) now needs manage_platform_settings; for every stock global namespace the read door already demanded it. Declaring it as a narrowing is the safe side. ADR-0087 has nothing to rewrite: no metadata key is removed or renamed, and sys_setting_audit.scope keeps its global option because 18.0 rows hold it. Level and arm agree with the diff.

③ Boundary flags

Implemented-by: claude/issue-24530-8b0e-deployment-level
Reviewed-by: session_01Y5583bs2RDd53MH6kM1ca3

VERDICT: PASS

…0e-deployment-level

Claude-Session: https://claude.ai/code/session_01HZT9daB4YX41N1SVVxYcek
Co-authored-by: Claude <noreply@anthropic.com>
…d tree; the read-door docblock and dual-write title name the sibling

Claude-Session: https://claude.ai/code/session_01HZT9daB4YX41N1SVVxYcek
Co-authored-by: Claude <noreply@anthropic.com>
…0e-deployment-level

Claude-Session: https://claude.ai/code/session_01HZT9daB4YX41N1SVVxYcek
Co-authored-by: Claude <noreply@anthropic.com>
…he merged tree (both siblings: sys_identity_email, sys_platform_setting_audit)

Claude-Session: https://claude.ai/code/session_01HZT9daB4YX41N1SVVxYcek
Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation protocol:system size/l tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(services): 18.x step 2 (8b-0e′): sys_secret, the settings audit's global rung and sys_flow_credential go deployment-level, expand-first

2 participants