Skip to content

docs(qa): re-ground the activation-ledger checklist items on the tenantless sys_metadata_activation - #15251

Merged
hotlong merged 1 commit into
mainfrom
claude/issue-15154-platform-checklist-activation-ledger
Sep 4, 2026
Merged

docs(qa): re-ground the activation-ledger checklist items on the tenantless sys_metadata_activation#15251
hotlong merged 1 commit into
mainfrom
claude/issue-15154-platform-checklist-activation-ledger

Conversation

@hotlong

@hotlong hotlong commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Fixes #15154

sys_metadata_activation dropped its reserved organization_id column before it ever
shipped (#15024, PR #15155). Verified against origin/main rather than inferred from the
card: sys-metadata-activation.object.ts declares systemFields: { tenant: false }, the
declared index is { fields: ['metadata_type', 'name'], unique: 'global' }, and
ObjectStoreMetadataActivationStore.list() is scoped by metadata_type and nothing else —
no NULL-organization filter, no org-row skip. The premise holds.

platform-core.activation-ledger-row-contract (revision 1 → 2)

leg was now
step 2 five declared columns incl. organization_id, "NULL on every row" four ledger columns beside id and the audit family; organization_id absent from the row key set
step 6 refusal attributed to the COALESCE'd index (ADR-0120 D3 NULL-collapse) the plain unique: 'global' over two required key parts; D3's collapse kept as history that is no longer reachable
step 7 INSERT a row with organization_id — impossible, no such column replaced by a no-tenant-column probe

Step 2 is a real strengthening, not a wording fix. The old spelling cannot be carried
forward at all: once the column is gone, a value check of the shape row.organization_id ?? null answers null either way, so it passes while measuring nothing — green for exactly
the reason it should be red. The key-set assertion is the same inversion #15024 already
applied to the dogfood pin (expect(Object.keys(row)).not.toContain('organization_id'),
with an arrayContaining anti-vacuity control beside it).

Step 7 is replaced, not retired — the judgement call the card flagged, ruled by the PM
on dispatch. ADR-0131 D7 names sys_metadata_activation as reverted before 17.3 and not
returning, which makes "this ledger has no organization column" a load-bearing platform
property; dropping the leg would lose coverage rather than retire an obsolete assertion.
The replacement stays inside the item's established idiom — the same direct-sqlite fixture
class steps 6 and 7 already required, no new checklist mechanism:

  • PRAGMA table_info(sys_metadata_activation) — the column list carries metadata_type /
    name / package_id / active beside the driver's id and the injected audit family,
    and nothing tenant-shaped;
  • an INSERT naming organization_id is refused by sqlite (has no column named organization_id);
  • an anti-vacuity CONTROL: the same statement with that column dropped succeeds, so the
    refusal names the missing column rather than a malformed statement. The
    (metadata_type, name) pair is fresh on purpose, so step 6's unique index cannot be what
    answered.

The negative entries follow the same correction. A resurrected tenant column is now worse
than the shape it replaced: the store no longer filters or skips on read (there is no column
to filter on), so an org-carrying row would be merged straight into the deployment-wide
answer. And a duplicate accepted by the index is no longer diagnosable as the #5030
NULL-distinct hole — that hole needed a nullable tenant column inside the key.

source gains anchors for #systemFields (the opt-out that removes the column rather
than leaving it unwritten — resolveInjectedSystemColumns would provision it by injection
with no field declared) and #list, plus the ADR-0131 D7 citation. ADR-0126 §5's "the org
column is reserved" bullet is marked withdrawn, and §5's operator-gate half is explicitly
recorded as standing.

access-security.activation-write-operator-gate (revision 1 → 2)

Read-back detail only, as the card scoped it. Two sites (step 7 and the inert-gate clause's
verify) asked the runner to see organization_id NULL; they now read the key set, with the
same vacuity warning. The gate itself is untouched and its unit pins are unmodified — the
source citation now says so explicitly, so the next reader does not infer the gate moved with
the withdrawn column bullet.

Both items bump revision and append a history entry, per the README's change lifecycle.

Gates

pnpm check:platform-checklist (deliberately not in lint.yml — maintainer decision;
run by hand). Baseline captured at 1bc3c092a before any edit, re-run at 96fc81042
after: the output is byte-identical, diff empty. The 4 pre-existing UNCLASSIFIED
coverage problems (batch_endpoints, crud_endpoints, metadata_endpoints,
route_generation) are unchanged — this change adds none and removes none.

Anti-vacuity for that green. Because a checklist edit's gate can go green by not being
read at all, one of the two anchors this change adds was re-pointed at a symbol that does
not exist, proven on disk by grep counts before and after, then measured: the gate went
4 problems → 5, naming sys-metadata-activation.object.ts#thisSymbolDoesNotExist as an
ABSENT SYMBOL. Restored with git checkout HEAD -- (absolute path) and proven byte-identical
(git hash-object equals the HEAD blob 3cb88d94; git diff HEAD and git status --porcelain
both empty; zero residual mutation markers).

Symbol-anchor floor (scripts/checklist-symbol-anchor-baseline.json, shrink-never):
areas/platform-core.json 58 → 60 (two anchors added, the safe direction),
areas/access-security.json 44 → 44. No floor lowered; the baseline file is untouched.

Derived family. node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack
let the script derive its own change set (2 committed paths vs merge base 1bc3c092a,
three-dot). It reconciles to 10 runnable families, harvested with --commands. All 10
green at 96fc81042, exit codes captured before any pipe (cmd > file 2>&1; EXIT=$?):

check-ci-filter-parity · check-closing-keyword-parity (+ --self-test) ·
check-comment-mask-corpus · check:doc-formula-expressions · check:cross-package-test-inputs ·
check:doc-authoring · check:nul-bytes · check:refd-timer-probe · check:watch-hint-literal

One NOT MEASURED, then measured. check:doc-formula-expressions first exited 3
PREREQUISITE NOT MET, its own words: "Nothing was measured … It is NOT a finding." It needed
@objectstack/formula and then @objectstack/lint built. Both built, gate re-run, exit 0.
Recorded here rather than reported as a red, since exit 3 says nothing about the tree.

Verify-lock declaration. The two builds went through
bash scripts/pm/os-verify-lock.sh -c ..., which reported UNLOCKED (declared) · no usable flock on this host, so the shared verify lock was NEVER taken and NOTHING was serialized.
Declaring it as the entry point instructs: the wall-clock numbers above are shared-box
readings, not quiet-machine promises.

Not run, deliberately: the repo-wide pnpm lint sweep and the full test suite. This diff
is two JSON data files under docs/qa/; no package source, no test, no gate script changed —
dispatch-gates derived no test family for it, and CI runs the farm exactly once regardless.

Changeset

None, and none is owed: the diff publishes nothing from any released package. The
skip-changeset label is applied on this PR (⛔ not an empty-frontmatter changeset — the gate
rejects those).


Generated by Claude Code

…ntless table

`sys_metadata_activation` dropped its reserved `organization_id` column before it
ever shipped (#15024): the object declares `systemFields: { tenant: false }`, the
declared index is `unique: 'global'` over `(metadata_type, name)`, and
`ObjectStoreMetadataActivationStore` no longer filters reads to NULL-organization
rows or skips org-carrying ones. Three legs of
`platform-core.activation-ledger-row-contract` were written around that column.

- Step 2 asserted five declared columns with `organization_id` NULL on every row.
  It now asserts the column is ABSENT from the row's key set. The value spelling
  passes vacuously once the column is gone (`row.organization_id ?? null` is
  `null` either way), which is why the dogfood pin was inverted into a key-set
  assertion rather than carried forward.
- Step 6 (uniqueness) still works and still refuses; only its stated mechanism was
  wrong. It now names the plain `unique: 'global'` over two required key parts,
  with ADR-0120 D3's COALESCE collapse recorded as history that is no longer
  reachable here.
- Step 7 INSERTed a row carrying `organization_id`, so the leg could not be run at
  all. It is REPLACED by a no-tenant-column probe — `PRAGMA table_info` plus an
  INSERT naming the column, refused, bracketed by a control INSERT that lands
  without it — not retired, because ADR-0131 D7 makes "this ledger has no
  organization column" a load-bearing platform property.

`access-security.activation-write-operator-gate` changes only its two ledger
read-backs; the operator gate and its unit pins are untouched. ADR-0126 §5's
operator-gate half stands, and the source citation now says so, so the next reader
does not infer the gate moved with the withdrawn column bullet.

Both items bump `revision` and append a `history` entry, per the checklist's
change lifecycle.

Fixes #15154

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@hotlong hotlong added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 4, 2026
@github-actions github-actions Bot added the size/s label Sep 4, 2026
@hotlong
hotlong added this pull request to the merge queue Sep 4, 2026
Merged via the queue into main with commit 5ab3507 Sep 4, 2026
35 checks passed
@hotlong
hotlong deleted the claude/issue-15154-platform-checklist-activation-ledger branch September 4, 2026 08:33
os-zhuang pushed a commit that referenced this pull request Sep 4, 2026
…sertions

`sys_metadata_activation` dropped its reserved `organization_id` column before it
ever shipped (#15024): the object declares `systemFields: { tenant: false }`, the
opt-out that REMOVES the column rather than leaving it unwritten. PR #15251
re-grounded the two items #15154 named. Four siblings still read that column back
and asserted it NULL — a VACUOUS leg, not merely a wrong value: once the column
is gone, `row.organization_id ?? null` answers `null` either way, so the read
passes rather than failing and a runner sees green for exactly the reason it
should be red. Each is inverted into a KEY-SET assertion, the shape #15024 used
on the dogfood pin and PR #15251 carried into step 2.

- platform-core.activation-ledger-registration-home — step 2's row capture and
  the no-automation clause's "ONE install-level row (organization_id NULL)". The
  row is re-said as DEPLOYMENT-level: with no tenant column there is no second
  scope for install-level to be distinguished from. The schema-side probe stays
  with the sibling item that owns it.
- api-backend.packaged-action-disabled-dispatch — the disable step's row
  confirmation, plus `automated.ref`, which described the dogfood pin as
  asserting "ONE install-level row with organization_id NULL". That pin has been
  a key-set reading named "writes ONE deployment-level row, and the TABLE has no
  tenant column at all" since #15024; the ref now quotes its live name.
- api-backend.action-activation-door-contract — the happy-path step, its
  acceptance clause and `automated.ref`. The clause also glossed the column as
  "the per-org dimension is reserved and unwritten": ADR-0131 D7 WITHDREW that
  ADR-0126 §5 D3 bullet ("a reserved nullable tenant column is the shape D1
  forbids") and names this table as reverted before 17.3 and not returning, so
  the gloss told a runner the tenant dimension was coming back. The source list
  now cites ADR-0131 D7 and marks which half of §5 survives.
- automation.packaged-flow-disable-durable — the ledger read step, the row
  clause and its "§5 reserves the column" gloss, the verify line's
  NULL-collapsed 'organization' index (it is a plain `unique: 'global'` over two
  required key parts; with no tenant column `normalizeDeclaredIndex` has no part
  to prepend), and the `source` line still citing "org-carrying rows skipped on
  read" and "organization_id never written". The store citation splits so
  `#list` carries the read-path correction where the read path lives.

Each item bumps `revision` and appends a `history` entry, per the checklist's
change lifecycle. No item outside this defect class is touched, and no clause of
the four contracts themselves moved — only what a runner records about the row.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/s skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

docs(qa): platform-checklist activation-ledger-row-contract is written around the removed sys_metadata_activation tenant column

1 participant