Skip to content

[finding] The singular section: census is 4, not 3 — concept.mdx carries a 4th nameless one, plus two more in an unjudged JSON fence #13880

Description

@os-project-manager

Found while implementing #13759 (the three singular section: sites in layout-dsl.mdx).
Filed separately, not folded in: the triage ruling on #13759 fenced the population question
out of that PR, and this finding is exactly that question wearing a concrete example.

The measurement

Re-running the #13759 census with the same yaml parser and the same classifyYamlFence
the #11887 arm uses, on 8c6a7fc0b, over all of content/docs/**, with no marker filter:

yaml fences scanned : 148   (judged 145, skipped 3 on a syntax error)
singular `section:` mappings : 4
  NAMELESS content/docs/protocol/objectui/concept.mdx:426     label="Billing Info"          keys=label|fields
  NAMELESS content/docs/protocol/objectui/layout-dsl.mdx:235  label="Contact Information"   keys=label|columns|fields
  NAMELESS content/docs/protocol/objectui/layout-dsl.mdx:263  label="Product Details"       keys=label|columns|fields
  NAMELESS content/docs/protocol/objectui/layout-dsl.mdx:295  label=null                    keys=columns|fields

The population is 4, not the 3 the #13759 card recorded. #13759 fixed its three; the
concept.mdx one is untouched and still live.

Why the card counted 3 — the census was scoped by MARKER, not by shape

Not drift, and not a fourth that appeared since: - section: is present at concept.mdx:425
in af01080e3 itself, the commit the card measured on. Two control runs separate the
hypotheses:

  • re-running the census with the gate's own YAML_SECTIONS_KEY pre-filter
    (/(^|[^A-Za-z0-9_$.])sections\s*:/m) yields 0, not 3 — so the card did not use it;
  • grep for the marker yields exactly the card's 3:
    os:check-yaml FormSectionSchema key=section appears 3 times in content/docs/**, all in
    layout-dsl.mdx.

So the card's population was "fences carrying the singular key=section marker", and it was
reported as "the singular population across all of content/docs/**". concept.mdx carries
no os:check-yaml markers at all (check:yaml-examples reports it as 0 tagged / 10 untagged), so it is invisible to that scoping.

Why it is not a copy of the #13759 edit

The concept.mdx site is a different enclosing shape and needs a decision #13759 did not take:

customizations:
  - field: phone
    required: true
  - section:              # <- the 4th nameless singular section
      label: Billing Info
      fields: [payment_terms, credit_limit]
  1. The enclosing shape has no schema. This is the page's "Layer 2: Admin Customization"
    example. A customizations: sequence of { field | section } overlay entries is
    declared nowhere in packages/spec — the only customizations in the authorable surface
    is tenant.zod.ts's z.record(z.string(), z.unknown()), a free-form record. Whether this
    fence teaches a real shape at all is the prior question; giving it a name polishes an
    example that may want removing or rewriting instead. Compare the steps: callout already
    on layout-dsl.mdx, which removed a phantom rather than repairing it.
  2. Its sibling fence is unjudged too, and is not YAML. The "Final Merged Layout" block
    directly below (concept.mdx:440) is a ```json fence carrying two more nameless
    sections ("label": "Contact Information", `"label": "Billing Info"`) inside a real
    `"sections": [ ... ]` array. `json` is in neither `TS_FENCE_LANGS` nor `YAML_FENCE_LANGS`,
    so both arms of `check-docs-section-name` pass over it. Fixing the YAML half alone would
    teach an anchor that vanishes from the merged output shown two paragraphs later.

Why the population question is the real subject

check-docs-section-name judges sections: sequences in both arms. This finding adds two
more shapes that carry form sections and that neither arm reaches — a singular section:
mapping, and a sections: array in a json fence — which is the same drift #10830 and #11887
each closed one selector at a time. Deciding the gate's population means deciding which keys
and which fence languages introduce a form section, together with how the os:check-yaml
marker vocabulary is read. That is a triage call, not a dev call, and it is the one #13759
deliberately deferred.

Sites, for whoever picks this up:

site fence shape
content/docs/protocol/objectui/concept.mdx:426 ```yaml, untagged - section: under customizations:, label: Billing Info
content/docs/protocol/objectui/concept.mdx:444 ```json, unjudged by both arms "label": "Contact Information"
content/docs/protocol/objectui/concept.mdx:452 ```json, unjudged by both arms "label": "Billing Info"

⛔ Not a schema change either way: FormSectionSchema.name stays .optional() (#10709,
reaffirmed #10830).

Back-links: #13759, #11887, #10830, #10709

Activity

  1. claude commented on Sep 2, 2026

    @claude
    Contributor

    Claim: session session_01WLJQhde67SeTccsmnBVarV (domain:devx execution seat, seat post #6023) — R1 wave 8.

    • Branch: claude/issue-13880-section-name-population
    • Worktree: ../objectstack-13880 (dedicated per-task worktree, off origin/main)
    • Domain: domain:devx per the triage (the gate's population in scripts/ + an AUTHORED content/docs/** page — content/docs/protocol/objectui/concept.mdx carries no generated-page banner on origin/main, so it is not a domain:spec generated page)
    • File surface: scripts/check-docs-section-name.mjs (third + fourth selectors: singular section: mappings in YAML fences; json-family fences bracket-matched like the TS arm; --self-test fixtures per selector; re-measured docblock census); content/docs/protocol/objectui/concept.mdx (the Layer-2 customizations: YAML fence :417-427 AND the merged-layout json fence :440-461 — ⛔ never the YAML half alone); any other content/docs/** page the widened population turns red, fixed in the same PR and listed per site; .github/workflows/lint.yml only if its step comment enumerates selectors. ⛔ packages/spec/** untouched — FormSectionSchema.name stays .optional(); ⛔ no new os:check-yaml marker as the fix (population by SHAPE, per the ruling).
    • Ruling order honoured: ① first decide whether the customizations: [{field}|{section}] overlay shape is real in packages/spec — on origin/main fed4fa409 git grep -n "customizations" origin/main -- packages/spec/src finds only package-API merge-strategy prose, metadata-plugin.zod.ts:527 (ADR-0126 §6 wall 3) and kernel/metadata-customization-retirement.test.ts ("never merge customizations") — no declared overlay list; expected answer "not real ⇒ rewrite the fence, no anchor", with citations in the PR body; ② only then the population change.
    • Premise re-verified on origin/main fed4fa409: git grep -n "^\s*-\? *section:" origin/main -- 'content/docs/**/*.mdx' → concept.mdx:425 (nameless, under customizations:), layout-dsl.mdx:234/:263/:296 (the [finding] 3 singular section: form-section examples in layout-dsl.mdx have no name — outside both arms of check-docs-section-name #13759 three), ui/doc-pages.mdx:257 (prose outside a fence — a control the new selector must NOT catch); json fences containing "sections" → exactly concept.mdx (:440, two nameless sections, // ← comments) and ui/forms.mdx:183 ("sections": [/* … */], an elided placeholder). Gate: YAML_SECTIONS_KEY :646 is plural-only, json is in neither TS_FENCE_LANGS :202 nor YAML_FENCE_LANGS :208. Premise holds.
    • Container & model: subagent lane (S/M), sonnet.
    • Clause ②: not reached — gate population + docs example; no contract change.
    • Serial constraints: scripts/check-docs-section-name.mjs was in PR Verdict handshake for 134 scripts/** self-tests that exit 0 on an early return #14479's surface — merged (9acddde94), no hazard; no in-flight PR of this seat touches concept.mdx. Changeset: scripts/** + content/docs/** only ⇒ no changeset, skip-changeset label.

    Generated by Claude Code

  2. claude commented on Sep 2, 2026

    @claude
    Contributor

    os-dev-report

    {
      "issue": 13880,
      "status": "done",
      "branch": "claude/issue-13880-section-name-population",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/14558",
      "premise_still_valid": true,
      "summary": "Answered the triage's prior question first: the customizations: overlay-diff list concept.mdx's Layer 2 example taught is not a declared shape (only customizations key in packages/spec is tenant.zod.ts's free-form z.record; FormViewSchema is .strict(); the three-layer merge engine it narrates is the paper metadata-customization protocol retired in @objectstack/spec 17, #13135/ADR-0049, tombstoned in MetadataPluginConfig.customizationPolicies/mergeStrategy, ADR-0126 section 6 wall 3: upgrades never merge customizations). Per the ruling, rewrote the fence into a Callout (same register as the steps: ghost layout-dsl.mdx already removed) naming the real mechanism (a per-org overlay write on the view metadata type, allowOrgOverride: true, ADR-0005) rather than adding an anchor to a fictional example. Added the two selectors the population question needed: (3) a singular YAML section: mapping at any nesting (document root or sequence-item value), widening YAML_SECTIONS_KEY from sections\\s*: to sections?\\s*:; (4) a sections: [...] array inside json/jsonc/json5 fences, bracket-matched with the same comment-masked matcher the TS arm uses (tolerates the // <- comments and JSON5 trailing commas concept.mdx's own merged-layout fence carries). Widened gate on the unmodified corpus measured 4 findings (matching the card's 4-not-3): concept.mdx :307 (Server Response json, a 5th site the issue itself hadn't named), :426 (the Layer 2 singular section:), :443/:451 (Final Merged Layout json, two sections). Fixed all four in this PR: :307 and the Final Merged Layout section got name: contact_information; the Billing-Info section (an artifact of the removed fictional Layer 2) was dropped from the merged output rather than named; the Layer 2 fence became the Callout. Widened gate is now green over the full 404-file corpus (22 TS literals, 22 YAML mappings including layout-dsl.mdx's 3 already-named singular sites from #13759, 2 JSON literals). ui/forms.mdx:183's elided sections placeholder is judged as zero entries, not skipped and not fabricated as a nameless section. ui/doc-pages.mdx:257 prose confirmed outside any fence, does not enter the population. No schema change: FormSectionSchema.name stays .optional(). No other content/docs/** page turned red under the widened corpus sweep.",
      "tests": "node scripts/check-docs-section-name.mjs --self-test -> 85 cases pass (real temp trees on disk; both new selectors driven RED and GREEN at both singular-section cardinalities, the JSON elided-placeholder and comment/trailing-comma tolerance, every new floor/anchor refusal exercised) -- re-run clean at final merge HEAD 38c73232d. node scripts/check-docs-section-name.mjs -> before-fix widened run on unmodified concept.mdx: 4 findings (:307,:426,:443,:451); after-fix: 0 nameless form-section examples, 404 docs files, 1180 TS-family fences / 22 literals, 13 YAML fences / 22 mappings, 148 json-family fences / 3 sections arrays / 2 literals -- clean at final HEAD too. pnpm --filter @objectstack/spec run check:yaml-examples -> concept.mdx: 0 tagged / 9 untagged (down from 0/10, one fewer untagged fence). Full derived gate list (node scripts/pm/dispatch-gates.mjs --commands, 39 commands) run at 45312b3fb -- all 39 green; three needed a one-time dependency build first (@objectstack/spec, @objectstack/formula, @objectstack/lint, @objectstack/client-react) since check:doc-formula-expressions / check:doc-security-posture / check:skill-examples each reported PREREQUISITE NOT MET (exit 3, not a finding) before the build. check:pm-dispatch-gates run detached (node scripts/pm/check-dispatch-gates.mjs) under heavy shared-verify-lock contention from sibling dispatch PRs (repeated queue-timeout exit 99 before it finally acquired) -- command-exit 0, dispatch-gates self-test: 1240 cases pass. Re-derived the same 39-command list at final merge HEAD 38c73232d (git log confirms no incoming commit touches scripts/check-docs-section-name.mjs or content/docs/protocol/objectui/**) and re-ran check-docs-section-name.mjs + its self-test there -- still green; the other 38 were not re-run post that second merge since nothing they read moved. A pnpm-lint-narrowed ESLint pass over just the two touched files was attempted 3 times and never completed -- each attempt queued behind other agents' heavy jobs and hit the 540s acquisition budget (queue-timeout, exit 99, NOT MEASURED, never ran); not one of the 39 derived commands, and CI's required Lint & Repo Gates job runs full pnpm lint regardless.",
      "mcp_calls": 0,
      "open_questions": [],
      "out_of_scope_findings": []
    }

    Generated by Claude Code


    Generated by Claude Code

  3. claude commented on Sep 2, 2026

    @claude
    Contributor

    ACCEPT — PR #14558 merged to main as 2a2653619 (out of the merge queue 14:18:54Z; added_to_merge_queue 13:54:14Z). Session session_01WLJQhde67SeTccsmnBVarV (domain:devx execution seat, seat post #6023), R1 wave 8.

    Close-out probes on origin/main 2a2653619 (verify worktree; the merge commit is the probed head):

    • scripts/check-docs-section-name.mjs: JSON_FENCE_LANGS (:253, json/jsonc/json5) routed through the shared sweepBracketMatchedFence(file, block, kind, …) (:770, called for json at :855 and for ts at :860 — one bracket-matcher, two arms); the singular-section: YAML selector YAML_SECTIONS_KEY = /(^|[^A-Za-z0-9_$.])sections?\s*:/m (:753, gate at :833); census floors FLOOR_YAML_FENCES (:316) … FLOOR_JSON_SECTION_LITERALS (:342) and JSON_CENSUS_ANCHORS (:326, anchored on concept.mdx) present, enforced at :939+.
    • content/docs/protocol/objectui/concept.mdx: contact_information named at :117 (YAML), :308 (Server Response JSON) and :461 (merged layout JSON); the Layer-2 box row reads "Org overlay: a full FormView write" (:393) and the former customizations: YAML fence is the <Callout type="warn"> at :419.
    • Merge stat: 2 files, +469 −94 (concept.mdx 53 lines, the script 510) — the YAML and JSON halves of concept.mdx fixed together, never the YAML half alone. skip-changeset, size-l.

    Against triage 5486760083: population widened by SHAPE (two more selectors, each with self-test fixtures and a re-measured census); ⛔ packages/spec/** untouched (FormSectionSchema.name stays .optional()); ⛔ no new os:check-yaml marker as the fix. All held. Zero rework.

    pm:dispatched removed with this comment; the card closes via the PR's Fixes #13880.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions