# Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.
#
# Merge semantics for generator-owned artifacts (#4675).
#
# These files are sorted arrays and append-only ledgers derived from source. When
# two PRs each add or drop a few lines the result is a set union — fully
# composable — but a three-way TEXT merge reports it as a conflict a human must
# resolve by hand. The correct resolution is always the same: discard both sides
# and re-run the generator.
#
# ⚠️ The driver is a LOCAL git facility, and that bounds what it can fix (#5837).
# The GitHub merge queue rebuilds each PR server-side, where no custom merge
# driver runs — so for the three hottest artifacts a driver could not stop the
# queue from evicting the second PR that touched them. Those three are now
# SHARDED, one file per category / entry point, so PRs touching different
# categories touch disjoint files and the queue has nothing to conflict on. They
# stay routed here as directories: the driver still owns a same-category
# collision, which is the residue sharding cannot remove.
#
# Two entries below are still SINGLE files — spec-changes.json and
# docs/protocol-upgrade-guide.md — and #8344 asked what the driver-less queue does
# to them. MEASURED (2026-08-13, the real in-flight case plus four synthetic pairs,
# each merged in a clone with no merge.os-regen.driver): it never leaves them
# stale-but-clean. Both are sorted unions and an ADR-0087 registration is
# insertion-only, so the queue's text merge either takes both sides — byte-identical
# to the regeneration, gates green — or conflicts outright. It conflicts only when
# the two in-flight entries are ADJACENT in registry sort order; one existing entry
# between them is already enough to merge clean AND current.
#
# Sharding them would not buy back an ejection, which is why they are still single
# files: every conflicting case also conflicts in
# packages/spec/src/migrations/registry.ts — generated, committed, unsharded,
# NOT_DRIVER_MANAGED — and every registration touches it by construction. The table
# and the reproduction are in packages/spec/src/migrations/entries/README.md.
#
# `merge=os-regen` hands those paths to `scripts/git-merge-regen.mjs`, which does
# NOT text-merge them. See that file for why it also does not regenerate them
# in place (git runs merge drivers BEFORE the sources are merged, so anything
# computed there describes a half-merged tree).
#
# The driver is registered per clone by `scripts/setup-git-hooks.mjs`, which
# `pnpm install` runs. A clone WITHOUT it registered falls back to git's default
# text merge — i.e. exactly today's behaviour — so committing this file cannot
# regress anyone.
#
# The single source of truth for this list is `scripts/regen-artifacts.mjs`;
# `node scripts/git-merge-regen.mjs --self-test` reconciles the two in both
# directions. Add a path there, not only here.
#
# Deliberately absent: docs-import-surface.baseline.json and
# dual-source-exports.baseline.json (shrink-only ratchets — recomputing can
# WIDEN them), variant-docs.json and the migrations/conversions registries
# (hand-written). Those conflicts are for a human. See NOT_DRIVER_MANAGED.
#
# The migrations registry is the interesting one since #7297: its three append
# tables now come from `packages/spec/src/migrations/entries/` (one file per
# entry, the `.changeset/*.md` shape), so the conflict two retirement cards used
# to have is gone at the SOURCE — different entries are different files. The
# file stays out of this list anyway, because it is now MIXED: a driver that
# deferred it whole would resolve its still-hand-written prose by regenerating,
# which loses an edit rather than a merge. `check:migration-registry` is what
# guards the generated half instead.
#
# The strictness ledger's COUNTS file joined at #5107 — the ledger's numbers were
# the repo's hottest conflict surface and merged in the one way that hides: two
# batches each decrement a header by their own correct delta, the rows merge
# cleanly because they do not overlap, and the subtotal merges clean and WRONG
# (seven cases in one day). Note it is the counts file, not the ledger — the
# ledger's prose is hand-written and must never be resolved by regenerating.
#
# The liveness state table's counts joined at #7377 for the same reason, one file
# over — 9 of its 30 rows had drifted from the gate before anyone re-ran the
# documented snippet. Same split and the same caveat: `liveness/state-counts.md`
# is the numbers and is driver-managed; `liveness/README.md` is the Notes prose —
# hand-written measurement of how each type got where it is — and is NOT.
# Regenerating a Note would fabricate a verdict, which that README calls worse
# than a missing row.
#
# The elevation census page joined at #13646 — a generated `file:line` anchor
# table whose correct merged values are on NEITHER side of a conflict (measured on
# #13625: five conflicted anchors resolved to 4408/5771/6019/6382/6575 against
# branch 4407/5770/… and main 4284/5647/…), so no text merge and no hand merge can
# reach them. ⚠️ It is routed as the FILE and NOT as `content/docs/permissions/**`:
# unlike `content/docs/references/**` above, which is generated whole, that
# directory is 22 hand-written prose pages around one generated one, and the glob
# would defer the prose to OURS. See NOT_DRIVER_MANAGED for that entry.
#
# This is also the row where the header's own warning is answered rather than
# accepted: `scripts/check-system-context-census.mjs` still reddens on every PR from
# the required `Lint & Repo Gates` job — it RE-DERIVES the census from the tree, so
# it catches the stale anchors a merge leaves behind even when nothing conflicted,
# which is the majority case (#13625: 18 anchors stale, 5 marked). The driver removes
# hand-merge rounds; it is never the only signal.
#
# ⚠️ #14064 CORRECTED the sentence that used to open that paragraph — "deferring is
# safe here BECAUSE the census gate re-derives". The gate re-derives the census and
# the anchors. It re-derives no PROSE, because prose is derived from nothing, and
# this page is the one routed path that carries both. So the argument was true and
# its domain was half the risk surface: the driver drops a side WHOLE, and on this
# page that side can carry hand-written paragraphs the gate is constitutionally
# unable to miss. Measured, not reasoned — deleting a 3-line anchor-free paragraph
# and running ten doc-family gates returned ten exit 0 over deleted documentation.
#
# Routing this file is still RIGHT (the correct anchors are on neither side; nothing
# above changes). What #14064 added is the missing half: the row now declares
# `mixed: 'line-anchors'` in scripts/regen-artifacts.mjs, and the driver refuses to
# defer SILENTLY when the incoming side carries anything but anchor numbers — it
# text-merges instead, and conflicts loudly if that cannot be done. The cheap case
# stays cheap: of the last 25 main commits to this page, 24 changed nothing but
# anchor numbers.

#
# #13731 enumerated this file's blind spot and closed it: `check:merge-driver` now
# also reconciles the GENERATORS. Every `gen:*` script in every workspace manifest
# (and the root) must be accounted for — named as a row's `gen` below, or carrying a
# recorded disposition in NOT_DRIVER_MANAGED. Until then the gate was green over an
# artifact that was in NEITHER list, which is how #13646 and #13335 were each found
# by hand, during a merge. Eleven generators were unaccounted; each now has one.
#
# The two rows added here are the ones whose answer was "route": the per-skill
# reference indexes (#13335) and the react-blocks contract (#14296 item 3 retired
# its second, JSON rendering — one artifact now, so one row). Their
# neighbours got the other answer for reasons recorded per path — the skill docs and
# the AI skills guide are MIXED (a spliced block in hand-written prose, so a deferral
# would launder the prose; #14064 added a THIRD answer for the mixed file whose
# generated half no hand merge can reach — see `mixed` in scripts/regen-artifacts.mjs
# — but "not routed" remains the first answer to reach for), the two per-package
# test-typecheck ledgers are shrink-only
# ratchets, the sdui lockstep record cannot be regenerated without an objectui
# checkout, and the openapi/sbom outputs are gitignored so git never merges them.
#
# ⚠️ The same LOCAL-facility bound applies to all three: routing removes hand-merge
# rounds, it does NOT protect them in the merge queue. What protects them is
# server-side — `check:skill-refs` and `check:react-blocks` run in `lint.yml` on
# `pull_request` and `merge_group` with no `paths:` filter, and both RE-DERIVE their
# artifact from source rather than reading it back, so they also catch the silent
# case where two branches' rows do not overlap and the text merge exits 0 describing
# neither side.

packages/spec/spec-changes.json                              merge=os-regen
packages/spec/liveness/state-counts.md                       merge=os-regen
packages/spec/authorable-surface/**                          merge=os-regen
packages/spec/authorable-surface.base.json                   merge=os-regen
packages/spec/authorable-defaults/**                         merge=os-regen
packages/spec/json-schema.manifest/**                        merge=os-regen
packages/spec/api-surface/**                                 merge=os-regen
packages/spec/src/meta-spelling/meta-url-data.generated.ts   merge=os-regen
packages/spec/export-origins/**                              merge=os-regen
packages/spec/declaration-map/**                             merge=os-regen
packages/spec/api-surface-signatures.json                    merge=os-regen
docs/protocol-upgrade-guide.md                               merge=os-regen
docs/audits/2026-07-unknown-key-strictness-ledger.counts.md  merge=os-regen
content/docs/references/**                                   merge=os-regen
content/docs/permissions/system-context.mdx                  merge=os-regen
skills/*/references/_index.md                                merge=os-regen
skills/objectstack-ui/references/react-blocks.md             merge=os-regen
scripts/platform-object-tenancy-census.json                  merge=os-regen
