Repository navigation
metadata: every boot of a multi-package artifact built by os build warns that its flat src/docs pages are "claimed by no package body" — the CLI puts them at the top level by its own rule, and the warning`s remedy cannot be followed #22190
Description
Activity
objectstack-fleet commented
on Oct 8, 2026 ContributorAuthorMore actionsTriage: first grade,
bug·priority:p3·domain:cli·area:devpath·pm:queue. Direction: the producer conforms, so the build attaches flatsrc/docsto the package that owns the manifestTriage seat (objectstack-wide, seat post #6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-08T07:07Z. ⛔ Not a claim, ⛔ not a dispatch.Triage: lands in
packages/cli/src/utils/collect-docs*⇒domain:cli; rationale: under the 2026-09-22 ADR-0130 addendum, a multi-package artifact carries its metadata once, inpackages[]. The collector is the side that still writes a top-leveldocs[].- Why p3: behaviour is correct (5 docs served, owner right). What is wrong is one boot WARN whose remedy cannot be followed in the ADR-0130 layout.
- Why not silence the sweep:
packages/metadata/src/plugin.ts's residual warning is right about everything else it catches. A carve-out there for one producer's shape is a consumer-side exception. - Pins: the two-package build puts the flat docs on the app package's body, and the boot logs no residual for them. Controls: the single-package shape is unchanged;
src/service/docsstill lands on the service body.
- addedarea:devpathThe road — create, dev, verify, publish/install, connect an agent, iterateThe road — create, dev, verify, publish/install, connect an agent, iteratebugSomething isn't workingSomething isn't workingand removed
on Oct 8, 2026 objectstack-fleet commented
on Oct 9, 2026 ContributorAuthorMore actionsClaim: PM loop round 1
Session:session_01BmsuLyUeuG5CNpZFMH1jzS
Account:os-elon-musk(the seat's linked user asGET /useranswers it; always the card's assignee)
Branch:claude/issue-22190-flat-docs-owner-package
Worktree:objectstack-issue-22190
Domain:domain:cli
Seat:domain:cli#1
File surface:packages/cli/src/utils/collect-docs.ts(collectDocsFromSrcand the package-docs attachment),packages/cli/src/commands/compile.ts(where the flatdocsare written, about:931-:1000), new or extended tests beside them underpackages/cli/src/utils/orpackages/cli/test/, and.changeset/22190-*.md(@objectstack/clipatch). ⛔ Notpackages/metadata/src/plugin.ts(the residual sweep stays as it is, per triage). Stop on breach; explain in the report.
Container & model:M,mode:subagent,model: default (opus).dispatch-gates --tierprints "no path-derived mandate"; the owner of the flat directory is a design judgment, so this is not a mechanical card.
Clause-②: no
Responsibility:packages/cli/src/utils/collect-docs.tswithcompile.ts, this lane's producer, writes flat docs to the top level of a multi-package artifact | none: the metadata plugin's residual sweep is right to warn, and triage ruled out a carve-out there | every boot of a multi-package artifact that ships flatsrc/docsreaches it; it is used today (a downstream app measures it on every boot)
Thread-read: 6054545749
Serial constraints cleared: no open PR touchescollect-docs.tsorcompile.ts(REST file lists of all 14 open PRs, read in this round). PR #22381 editspackages/cli/src/utils/stack-collections.tsandserve.ts, which this card does not write. Lane sibling in flight: #22310 (packages/runtime/src/domains/automation.ts), disjoint.objectstack-fleet commented
on Oct 9, 2026 ContributorAuthorMore actionsos-dev-report
{ "issue": 22190, "status": "done", "branch": "claude/issue-22190-flat-docs-owner-package", "pr": "https://github.com/objectstack-ai/objectstack/pull/22403", "session": "session_01BmsuLyUeuG5CNpZFMH1jzS", "premise_still_valid": true, "summary": "os build now puts a multi-package artifact's flat src/docs on the body of the one packages[] entry whose id equals the artifact's manifest.id. The new placeCollectedDocs in collect-docs.ts makes every docs placement, and compile.ts calls it in place of attachPackageDocs. If no entry carries that id, or two do, or the manifest has no id, the flat docs stay on the top level, which is pinned. The doc lint is unchanged (#18431 clause 2) and packages/metadata is untouched. On the card-shaped fixture, the boot-level residual WARN goes from 1 to 0, and GET /api/v1/meta/doc serves the same 4 docs under the same owners. Two answers move to match what a single-package artifact and a src/PKG/docs doc already answer: lock none to full (editable true to false, resettable false to true), and the app package's /api/v1/packages docs [] to [acme_faq, acme_guide]. The single-package artifact is byte-identical: sha256 710ab6c6 on both base 117d34de and this branch.", "tests": "Union after the last commit, HEAD 027bc7fa4: 65 of 65 derived gate families exit 0, plus `pnpm --filter @objectstack/cli typecheck` exit 0 and the full `pnpm lint` exit 0 with no findings. `dispatch-gates --ran`: '65 derived, 65 run, 0 NOT-MEASURED, 0 UNRUN' (a derived zero; every row carries its exit code). An earlier pass read check:dual-build-cjs-loads and check:i18n-coverage as PREREQUISITE NOT MET (exit 3, dist missing outside the cli closure), so they were not measured there. After `turbo run build --filter=!@objectstack/docs` both read OK in the union. cli unit layer (`pnpm --filter @objectstack/cli exec vitest run --project unit --maxWorkers=2`, under the lock): 'Test Files 271 passed (271) / Tests 3983 passed (3983)' at 925e0742, followed by typecheck 'check:test-typecheck: OK ... 3 file(s) / 28 error(s) / 6 pinned signature(s)', VERDICT command-exit 0. 925e0742..027bc7fa4 is one docblock comment. Re-run at 027bc7fa4: unit (collect-docs.flat-docs-owner, collect-docs.package-docs, collect-docs, validate-build-gate-parity, non-array-packages-readers) 'Test Files 5 passed (5) / Tests 137 passed (137)'. Integration, run locally because the diff touches one e2e file (OS_TEST_TIERS=nightly; build-package-docs-attachment, build-docs-step-count, build-multi-package-artifact): 'Test Files 3 passed (3) / Tests 16 passed (16)'. The rest of the integration layer is left to CI. ABLATION, from the committed state via scripts/ablation-replace.mjs: flatDocsOwner's 'owners.length === 1' became '=== -22190'; anchor x1 to x0, blob 5db191c3f456 to 02e9d463bdfd. Unit file: '5 failed | 10 passed (15)'. Every placement and door case fails, and the service control, the door's lit control and every no-owner and single-package control stay green. e2e: '1 failed | 3 passed (4)', only the owned-placement case. Restore: blob equals HEAD 5db191c3f456 and `git diff HEAD` is empty. The subject resolves from source through a relative import, so no rebuild was needed. BOOT READING (integration layer, `objectstack dev --fresh --seed-admin --no-watch` on the card-shaped fixture): the residual WARN line count is 1 at base and 0 on this branch. Single-package control: build stdout identical with timings stripped.", "mcp_calls": "0 — no MCP GitHub tool called. Reads used `gh api` GETs: the issue and its comments, #18431, #19246 and PR 22403 read-back.", "api_writes": "3 REST writes, each one fleet-write relay stroke (POST /repos/objectstack-ai/objectstack/dispatches, HTTP 204, executed as objectstack-fleet[bot]): (1) pr_create, POST /repos/objectstack-ai/objectstack/pulls, giving draft #22403 (relay read-back: 10657 bytes sent and stored, identical); (2) label-write assign, POST /repos/objectstack-ai/objectstack/issues/22403/assignees os-elon-musk (read back MATCHES; no label in the target because the diff publishes a cli patch changeset, so skip-changeset does not apply); (3) post-stamped comment, POST /repos/objectstack-ai/objectstack/issues/22190/comments (this report). Not REST: 6 git pushes to the branch, one of them the empty-branch probe.", "open_questions": [ { "question": "H2's unmatched case: on a multi-package artifact whose manifest.id names no packages[] entry, or names two, the flat src/docs stay on the top level, so its boot still logs the residual WARN. The WARN's remedy cannot be followed in an ADR-0130 layout. This is pinned as today's behaviour (unit and e2e). What should the long-term answer be?", "options": [ "A: Keep it as pinned. No guess, and the WARN stays, which is true: the artifact's two halves disagree.", "B: Make os build refuse or warn when a packages[] stack ships flat src/docs and no single entry carries manifest.id. The message names the fix: give the app package the artifact's manifest id, or move the docs into a package directory or inline defineStack docs.", "C: Attach the docs to a chosen entry (first or last)." ], "recommendation": "A for now. composeStacks(..., { manifest: 'preserve' }) always yields the match, because its manifest is one input's and that input contributes its own entry. No in-repo or reported producer writes the unmatched shape. B adds a build-time diagnostic, which is new gate surface and defaults to no without a measured producer. C is rejected: it is a guess, the kind of silent misattribution that the 'never re-derive ownership' rule at the metadata door exists to prevent." } ], "out_of_scope_findings": [ "class: a · reach: public door `os serve objectstack.config.ts --dev` (a config boot with no compiled artifact) on a two-package composeStacks(..., { manifest: 'preserve' }) config with flat src/docs. The authenticated GET /api/v1/meta/doc answered acme_service_runbook and setup_overview only: the two flat docs were absent and nothing warned. Measured on this branch's build. serve.ts is unchanged against base 117d34de (`git diff 117d34de 027bc7fa4 -- packages/cli/src/commands/serve.ts` is empty), so the behaviour predates this change. `os dev` is not affected because it compiles first. · evidence: the serve.ts dev mirror (around :2716-:2734) merges collectDocsFromSrc's flat docs into config.docs on the TOP LEVEL, and a packages[] config boot registers per body, so nothing on that path registers those docs. The fix is to route the mirror through placeCollectedDocs (landed in #22403). serve.ts is outside this claim's surface, and PR #22381 also edits it. Blocked-by: #22190 · dedupe words: os serve config flat src/docs not served · serve.ts docs mirror packages[] top-level · config boot multi-package docs missing · placeCollectedDocs serve mirror", "carrier: the next PR to touch packages/metadata/src/plugin-artifact-packages-attribution.test.ts (domain:engine, fenced here) · the docsArtifact docblock says the top-level flat-docs shape 'is on every such artifact the compiler produces'. That now holds only when no package owns the manifest. The test stays green because its fixture is built by hand · noted, not filed", "carrier: the serve.ts mirror fix above · in packages/cli/test/normalized-call-sites.test.ts, the 'commands/serve.ts :: config.docs' row's `why` says the flat set joins the top level 'as collectAndLintDocs returns it for the artifact's top level'. For a multi-package stack, os build no longer places it there · noted, not filed" ], "gates": [ { "cmd": "node scripts/check-adr-0087-registration.mjs --base origin/main", "exit": 0, "verdict": "✓ check-adr-0087-registration: this PR adds no declared-breaking changeset (1 non-breaking changeset(s) seen)." }, { "cmd": "node scripts/check-adr-0087-registration.mjs --self-test", "exit": 0, "verdict": "✓ check-adr-0087-registration --self-test: 441 assertions over real temp git repos (real scan()/assertInputs() path)" }, { "cmd": "node scripts/check-changeset-no-major.mjs --base origin/main", "exit": 0, "verdict": "✓ This diff introduces no `major` bump." }, { "cmd": "node scripts/check-changeset-no-major.mjs --self-test", "exit": 0, "verdict": "✓ check-changeset-no-major --self-test: 339 assertions (frontmatter dialects measured against @changesets/parse + the pre/exit exemption switch in both directions + the #7005 diff scoping over real..." }, { "cmd": "node scripts/check-ci-filter-parity.mjs", "exit": 0, "verdict": "OK: all 20 build input(s) turbo.json declares outside the packages (itself, 2 globalDependencies, and every `$TURBO_ROOT$` input of a build Build Core runs) and all 11 script(s) the `build-core` jo..." }, { "cmd": "node scripts/check-closing-keyword-parity.mjs", "exit": 0, "verdict": "check-closing-keyword-parity: OK (3 parsers agree on all 9 keywords and both measured separators; sweep found 5 file(s) carrying the grammar across 10380 tracked file(s), all registered)." }, { "cmd": "node scripts/check-closing-keyword-parity.mjs --self-test", "exit": 0, "verdict": "✓ check-closing-keyword-parity --self-test: 40 assertions, 5 mutations of the shipped parsers each driven to red." }, { "cmd": "node scripts/check-comment-mask-adoption.mjs", "exit": 0, "verdict": "OK check:comment-mask-adoption — 14 private comment-stripper(s) under packages/** + examples/**, all 14 recorded and every recorded row still reached (13 unconverted, 1 specimen). A new one reds h..." }, { "cmd": "node scripts/check-comment-mask-adoption.mjs --self-test", "exit": 0, "verdict": "PASS check-comment-mask-adoption --self-test (0 failure(s))" }, { "cmd": "node scripts/check-comment-mask-corpus.mjs", "exit": 0, "verdict": "✓ comment-mask corpus sweep [scripts/js-comment-mask.mjs]: 8496 files, 0 disagree, 0 unparseable, 171.2s (comparator self-test: 26 cases pass)." }, { "cmd": "node scripts/check-dts-emitted.mjs --self-test", "exit": 0, "verdict": "check-dts-emitted self-test: all assertions passed." }, { "cmd": "node scripts/check-empty-changeset.mjs --base origin/main", "exit": 0, "verdict": "✓ No changeset from the merge base modified or deleted by this diff (#17712)." }, { "cmd": "node scripts/check-empty-changeset.mjs --self-test", "exit": 0, "verdict": "✓ check-empty-changeset --self-test: 170 assertions over real temp git repos (real scan() path)" }, { "cmd": "node scripts/check-issue-citations.mjs", "exit": 0, "verdict": "✅ check-issue-citations: every citation this change adds resolves (or is a declared cross-repo reference)." }, { "cmd": "node scripts/check-keyed-text-bounds.mjs", "exit": 0, "verdict": "✓ check:keyed-text-bounds: 111 *.object.ts files under packages/** + apps/** + examples/** (walk is repo-wide; 0 outside), 116 object declarations, 241 declared index entries, 588 text-family field..." }, { "cmd": "node scripts/check-keyed-text-bounds.mjs --self-test", "exit": 0, "verdict": "PASS check-keyed-text-bounds --self-test (0 failure(s))" }, { "cmd": "node scripts/check-platform-object-tenancy-census.mjs", "exit": 0, "verdict": "✓ platform-object tenancy census matches the tree: 83 platform-namespace objects, 48 in the machinery's reach, 35 outside it, every exclusion explained by a declaration on its own schema." }, { "cmd": "node scripts/check-platform-object-tenancy-census.mjs --self-test", "exit": 0, "verdict": "✓ check-platform-object-tenancy-census self-test: all checks pass (83 objects, 35 outside the machinery)" }, { "cmd": "node scripts/check-plugin-teardown-shape.mjs", "exit": 0, "verdict": "✓ check:plugin-teardown-shape: 69 Plugin implementation(s) across 7920 source(s) under packages/**; every teardown-shaped method (stop / shutdown / close / dispose) sits beside a real destroy() (0 ..." }, { "cmd": "node scripts/check-plugin-teardown-shape.mjs --self-test", "exit": 0, "verdict": "✓ check-plugin-teardown-shape self-test: 48 cases pass (real pre-#10375 fixture reds, the repaired file and both delegating-alias directions stay green, every roster name reds, every excluded name ..." }, { "cmd": "node scripts/check-registry-log-declared.mjs", "exit": 0, "verdict": "OK: 73 vitest-running package(s) walked, 11 selected as engine-booting, every one declares a recognised registry log level (debug/info/warn/error/silent)." }, { "cmd": "node scripts/check-registry-log-declared.mjs --self-test", "exit": 0, "verdict": "self-test OK: 16 cases + level-vocabulary read + population declaration + real-tree selection floor." }, { "cmd": "node scripts/check-rest-log-spy-declared.mjs", "exit": 0, "verdict": "OK: 30 of 270 test file(s) beside packages/rest/src/log.ts observe the fault log, and every one of them declares its own OS_REST_LOG level." }, { "cmd": "node scripts/check-rest-log-spy-declared.mjs --self-test", "exit": 0, "verdict": "check-rest-log-spy-declared self-test reached its verdict: 23 case(s), 0 failure(s)." }, { "cmd": "node scripts/check-system-context-census.mjs", "exit": 0, "verdict": "check-system-context-census: OK — 118 elevation read sites in 20 packages across 55 files, living in 101 symbol(s); the page cites 114 symbol(s) against 114 required, over 137 anchors and 7 file-le..." }, { "cmd": "node scripts/check-system-context-census.mjs --self-test", "exit": 0, "verdict": "check-system-context-census --self-test: all cases passed" }, { "cmd": "node scripts/check-undeclared-dep-imports.mjs", "exit": 0, "verdict": "✓ check:undeclared-dep-imports: 80 workspace packages under packages/** + apps/** + examples/**, 2951 non-test src files, 2397 @objectstack/* specifiers (0 assembled, not judged); 1 ledger row(s), ..." }, { "cmd": "node scripts/check-undeclared-dep-imports.mjs --self-test", "exit": 0, "verdict": "PASS check-undeclared-dep-imports --self-test (0 failure(s))" }, { "cmd": "node scripts/docs-audit/check-affected-docs.mjs", "exit": 0, "verdict": "✓ affected-docs self-test: 605 cases pass." }, { "cmd": "node scripts/docs-audit/check-drift-comment.mjs", "exit": 0, "verdict": "✓ check-drift-comment: 66 cases pass across 5 fixture diff(s)." }, { "cmd": "node scripts/pm/release-rehearsal-clone.mjs --self-test", "exit": 0, "verdict": "✓ self-test passed" }, { "cmd": "node scripts/release-pending-publish.mjs --self-test", "exit": 0, "verdict": "✓ release-pending-publish self-test: 92 cases across 22 batteries pass." }, { "cmd": "pnpm --filter @objectstack/spec run check:duration-unit-keys", "exit": 0, "verdict": "✓ check:duration-unit-keys — 197 unit-declaring numeric key(s) across 2955 source file(s) all carry their unit in the key name (or in a sibling `unit`, or under a declared exemption: 6 declared dur..." }, { "cmd": "pnpm check:changeset-gate-self-tests", "exit": 0, "verdict": "✓ check-changeset-no-major --self-test: 339 assertions (frontmatter dialects measured against @changesets/parse + the pre/exit exemption switch in both directions + the #7005 diff scoping over real..." }, { "cmd": "pnpm check:cli-test-child-env", "exit": 0, "verdict": "✓ check:cli-test-child-env: 132 spawner source(s) among 268 under packages/cli/test/**; no new bulk process.env copy reaches a spawned child, all 158 spawn call(s) declare their child's env, and al..." }, { "cmd": "pnpm check:cross-package-test-inputs", "exit": 0, "verdict": "OK: 30 package(s) read outside themselves, all declared, and turbo.json hashes every declared glob (6 of them on a split \"test:repo\" task); 13 walked root(s) judged, 3 on ACCEPTED_WALK_RADII; 2884 ..." }, { "cmd": "pnpm check:doc-authoring", "exit": 0, "verdict": "✓ doc authoring guard: sibling-package prose ids hold the baseline — 0 pinned site(s) across 0 file(s), 89421 string(s) read in 1283 parsed source(s) (seen floor 40000 strings / 600 sources), no gr..." }, { "cmd": "pnpm check:driver-memory-census", "exit": 0, "verdict": "check-driver-memory-census: OK — every declaration is ledgered, every ledger entry is live, and every ruled file states \"#6664 census: 2 ruled consumers\". This gate polices the census, never invest..." }, { "cmd": "pnpm check:dts-closure", "exit": 0, "verdict": "check-dts-closure: 72 built package(s) swept - 172/172 declared declaration file(s) present across 72 package(s); 0 built package(s) declare no declaration entry point and owe none." }, { "cmd": "pnpm check:dual-build-cjs-loads", "exit": 0, "verdict": "✓ check:dual-build-cjs-loads — 107 published require entry point(s) across 66 package(s) load; 717 emitted CommonJS file(s) parse; 1 cross-format behaviour probe(s) agree; 105 require condition(s) ..." }, { "cmd": "pnpm check:engine-double-contract", "exit": 0, "verdict": "check-engine-double-contract: OK — 990 pinned, 129 in the DEBT ledger, 3 exempt." }, { "cmd": "pnpm check:gitlink-declared", "exit": 0, "verdict": "check-gitlink-declared: OK (10380 index entries -- 0 gitlink(s) at mode 160000; no .gitmodules in the index, so nothing is declared; nothing to declare)." }, { "cmd": "pnpm check:i18n", "exit": 0, "verdict": "check-i18n-bundles: OK (9 package(s) — all bundles in sync, no undeclared authoring keys)." }, { "cmd": "pnpm check:i18n-coverage", "exit": 0, "verdict": "check-i18n-coverage: OK (13 config(s), 621 baselined untranslated string(s), none new)." }, { "cmd": "pnpm check:i18n-walk-parity", "exit": 0, "verdict": "✓ check-i18n-walk-parity: 11 declared group(s), 9 walked, 2 exempted — every declared group has an extractor face." }, { "cmd": "pnpm check:issue-citations", "exit": 0, "verdict": "✅ check-issue-citations --self-test: grammar narrowed, every spelling enumerated, qualifier a closed set of repositories, four 404 causes kept apart, both board strategies agree, diff scope red AND..." }, { "cmd": "pnpm check:lean-entry-closure", "exit": 0, "verdict": "✓ check-lean-entry-closure: 2 published condition(s) measured from a real load." }, { "cmd": "pnpm check:logger-receiver-detach", "exit": 0, "verdict": "OK every log channel keeps its receiver: 3234 non-test TS file(s) walked, 0 detach(es) on the 5 declared receiver-sensitive sink spelling(s)." }, { "cmd": "pnpm check:nul-bytes", "exit": 0, "verdict": "check-nul-bytes: OK (scanned 10371 text file(s) -- 10371 tracked, 0 untracked-not-ignored; skipped 9 binary; no raw ASCII control bytes)." }, { "cmd": "pnpm check:objectql-double-limit", "exit": 0, "verdict": "OK ObjectQL double `limit` conformance holds: 470 double(s) graded, 273 apply the caller's bound or refuse it loudly." }, { "cmd": "pnpm check:objectui-changeset", "exit": 0, "verdict": "✓ objectui-range --self-test: all checks passed" }, { "cmd": "pnpm check:org-identifier", "exit": 0, "verdict": "check-org-identifier: OK (3256 author-facing source file(s), 18 session binding(s) resolved, no removed session.tenantId alias)." }, { "cmd": "pnpm check:page-declaration-shape", "exit": 0, "verdict": "check-page-declaration-shape: OK — 34 page entries across 3246 sources under packages/**, examples/**, apps/** all reach the kernel through a discoverable declaration (`: Page` or `definePage()`)." }, { "cmd": "pnpm check:pm-changeset-deadline-census", "exit": 0, "verdict": "✓ changeset-deadline-census --self-test: all cases passed across 5 batteries (what counts as a named target, the controls that make a zero a reading, the verdict truth table including the inconclus..." }, { "cmd": "pnpm check:published-files", "exit": 0, "verdict": "✓ check:published-files — 69 publishable package(s) of 80 workspace member(s) declare a `files` whitelist that covers every entry point plus CHANGELOG.md and admits no test, test-harness config or ..." }, { "cmd": "pnpm check:query-options-erasure", "exit": 0, "verdict": "✓ query-options-erasure ratchet holds: 65 unswept non-test site(s) in 17 file(s), none new, and every file measured parsed. Every other non-test file under packages/ is covered by `pnpm lint`." }, { "cmd": "pnpm check:refd-timer-probe", "exit": 0, "verdict": "OK check-refd-timer-probe: 8491 source file(s) swept; the process-global timer probe is read in packages/qa/refd-timer-testkit/src/index.ts and nowhere else." }, { "cmd": "pnpm check:slot-lookup", "exit": 0, "verdict": "✓ slot-lookup ratchet holds: 104 unswept site(s) in 25 file(s), none new, and every file in the population parsed. Every other file under packages/ is covered by `pnpm lint`." }, { "cmd": "pnpm check:sourcemap-no-sources-content", "exit": 0, "verdict": "check-sourcemap-no-sources-content: 68 built package(s) swept - 544 map(s), none embed source text." }, { "cmd": "pnpm check:test-source-alias", "exit": 0, "verdict": "check-test-source-alias OK — 73 packages with tests scanned; 60 registered as still resolving a workspace dep through `dist/`; 53 published subpath(s) resolved through every alias table." }, { "cmd": "pnpm check:tier-file-adoption", "exit": 0, "verdict": "OK: 80 workspace package(s) walked, 82 nightly-tier test file(s) on disk (82 e2e, 0 live), owned by 1 package(s); every one reads OS_TEST_TIERS." }, { "cmd": "pnpm check:type-check-coverage", "exit": 0, "verdict": "check-type-check-coverage: OK — 79/80 workspace packages type-checked (plus the root), 1 in the DEBT ledger (26 frozen raw errors, https://github.com/objectstack-ai/objectstack/issues/4311), 1 exempt." }, { "cmd": "pnpm check:type-check-debt", "exit": 0, "verdict": "check-type-check-coverage --re-measure: OK — 1 ledger entr(ies) re-measured in 30.3s, 26 raw tsc error(s) total, none above its recorded number." }, { "cmd": "pnpm check:watch-hint-literal", "exit": 0, "verdict": "✓ check-watch-hint-literal: 72 declaration(s) across 4 rostered name(s) -- ROOT_DIR_WATCH_HINTS 48, ROOT_FILE_WATCH_HINTS 13, ROOT_WATCH_HINTS 3, DECLARED_WATCH_HINTS 8 -- every one an array of quo..." }, { "cmd": "pnpm check:where-matcher", "exit": 0, "verdict": "✓ where-matcher conformance holds: 491 matcher(s) discovered, 491 answer the combinator battery correctly or refuse it loudly (321 refuse)." }, { "cmd": "pnpm --filter @objectstack/cli typecheck", "exit": 0, "verdict": "check:test-typecheck: OK — @objectstack/cli's test layer compiles under packages/cli/tsconfig.test.json; 3 file(s) / 28 error(s) / 6 pinned signature(s) held in test-typecheck-debt.json (shrink-onl..." }, { "cmd": "pnpm lint", "exit": 0, "verdict": "eslint . --no-inline-config printed no findings (full repo run, not narrowed)" } ], "line_budget": "none set · additions 556, deletions 27 (6 files, base 117d34de..027bc7fa4)", "files_changed": [ ".changeset/22190-flat-docs-owner-package.md (+15/-0)", "packages/cli/src/commands/compile.ts (+17/-9)", "packages/cli/src/utils/collect-docs.ts (+103/-12)", "packages/cli/src/utils/collect-docs.flat-docs-owner.test.ts (+364/-0, new)", "packages/cli/test/build-package-docs-attachment.e2e.test.ts (+48/-5)", "packages/cli/test/validate-build-gate-parity.test.ts (+9/-1)" ], "deviations": [ "The final union ran `pnpm --filter @objectstack/cli typecheck` inside the gate runner without the verify lock. The earlier typecheck, run with the unit layer at 925e0742, held the lock.", "The full cli unit layer was measured at 925e0742, not at the final HEAD 027bc7fa4. The only difference is one docblock comment. The touched-surface unit and e2e files were re-run at 027bc7fa4.", "The PR was opened after the gate union, not at the first demonstrable commit, so that its write-once body could cite the union's HEAD. The branch was pushed at every step.", "Claim surface: the e2e pin edited is packages/cli/test/build-package-docs-attachment.e2e.test.ts, and the closed gate-parity roster row was renamed in packages/cli/test/validate-build-gate-parity.test.ts. Both are under packages/cli/test, inside the claim's 'new or extended tests'. serve.ts and packages/metadata were not touched.", "The harness attribution reminder asked for a model-named Co-Authored-By trailer and a different PR footer. Per AGENTS.md, I used the model-free pair `Claude-Session` plus `Co-authored-by: Claude` and the session-URL PR footer.", "Labels documentation, size/l, tests and tooling appeared on PR 22403 from another actor (path and size labelers). Left as they are." ] }
Generated by Claude Code
objectstack-fleet commented
on Oct 9, 2026 ContributorAuthorMore actionsACCEPT: PR #22403 (head
027bc7fa4)domain:cliseat (#6024) ·session_01BmsuLyUeuG5CNpZFMH1jzS· 2026-10-09T03:05Z. Reviewed against GitHub, not against the report.- PR shape: draft, base
main; the first line isFixes #22190, the only closing keyword in the body, and the body carries a line-initialClause-②: no. Six files,+556 / -27, all inside the claim's surface:compile.ts,collect-docs.ts, a newcollect-docs.flat-docs-owner.test.ts, and two existingpackages/cli/testpins. The changeset is.changeset/22190-flat-docs-owner-package.md(@objectstack/clipatch). No governed path;packages/metadataandserve.tsare untouched. - Diff read:
placeCollectedDocsis now the one decision of where both doc sets land.flatDocsOwneranswers the singlepackages[]entry whose id equalsmanifest.id, read throughdocsPackageRefs, and nobody otherwise. ⛔ No guess.- The flat set is appended after the owner's own directory docs through
attachPackageDocs(itsclaimedDocsidentity dedupe is unchanged). Inline top-level docs never move. - With no
packages[], the verydocsarray andpackagesvalue come back, so a single-package artifact is byte-identical (sha256710ab6c6on both base and head, per the report).
- Triage direction met: the producer conforms and the residual sweep is untouched. The two-package build puts the flat docs on the app body. The boot WARN count is 1 at base and 0 on head, through the real
MetadataPlugindoor, with a lit control that draws exactly one warning.src/service/docsstays on the service body. - A behaviour change the changeset states, accepted: these docs now ride the owning package's installed record and its lock (
full, resettable), as a single-package artifact's flat docs and anysrc/PKG/docsdoc already do. Before, they were a residual registered outside any package record. - Spot-checked:
@objectstack/metadatais a declared dependency of@objectstack/cli, so the door test's import is legitimate. The ablation (owners.length === 1broken) fails 5 of 15 unit cases (every placement and door case) and the owned-placement e2e case; every control stays green. - Gates: the dev's union at
027bc7fa4(the PR's current head) was 65 of 65 exit 0,--ranreconciled with 0 unrun, and the fullpnpm lintexited 0. CI: in progress at this read, with no failure. Landing waits for every check to be green. - The dev's open question, answered here (an in-seat call under SKILL.md's non-escalation class; the maintainer's veto window applies): A, keep the unmatched case as pinned. When no entry carries
manifest.id, or two do, the flat docs stay on the top level and the residual warning stays true.composeStacks(…, { manifest: 'preserve' })always yields the match, and no in-repo or reported producer writes the unmatched shape (zero pull).- B would add a new build diagnostic, and a new gate defaults to no unless the maintainer names it.
- C guesses an owner, the silent misattribution the metadata door refuses to make.
- Out of scope:
filed #22405: the config-boot twin.os serve objectstack.config.ts --devon a two-package project serves none of its flat docs and warns nothing (measured). Its fix reusesplaceCollectedDocsinserve.tsafter PR feat(core,cli,verify): bootStack composes what serve composes — item 1 stage 2 of #22301 (HELD at stop conditions) #22381 releases that file.Acceptance notes: thedocsArtifactdocblock inpackages/metadata/src/plugin-artifact-packages-attribution.test.ts(domain:engine's; carrier: the next PR to touch it).Acceptance notes: thenormalized-call-sites.test.tsrow'swhy(carrier: [finding] cli(serve): a config boot of a multi-package composeStacks project serves none of its flat src/docs pages, and nothing warns #22405's fix).
Generated by Claude Code
- PR shape: draft, base
objectstack-fleet commented
on Oct 9, 2026 ContributorAuthorMore actionsLanded: PR #22403 →
83e7ae93ad, a single-parent queue squashdomain:cliseat (#6024) ·session_01BmsuLyUeuG5CNpZFMH1jzS· 2026-10-09T03:50Z- Landing shape:
83e7ae93adhas one parent (git rev-list --parents -n 1gives 2 fields) and is an ancestor oforigin/main. It entered the merge queue at 2026-10-09T03:26Z and merged at 2026-10-09T03:49Z, on that first entry. - Content on
origin/main:packages/cli/src/utils/collect-docs.tsexportsflatDocsOwnerandplaceCollectedDocs(2 hits at the landed commit), andcompile.tsplaces through it.collect-docs.flat-docs-owner.test.tsand.changeset/22190-flat-docs-owner-package.md(@objectstack/clipatch) are present. - Review of record: ACCEPT
6073416652at027bc7fa4, one round,Clause-②: no; no contract review owed. All 34 checks were green on the head before the ready flip. The dev's open question was answered in-seat as A (the unmatched case stays as pinned); the maintainer's veto window applies. - State: the card closed
completedthroughFixes #22190;pm:dispatchedis stripped in this act. - Follow-up: [finding] cli(serve): a config boot of a multi-package composeStacks project serves none of its flat src/docs pages, and nothing warns #22405 (
finding), the config-boot twin, reusesplaceCollectedDocsinserve.ts. - Released: this card's hold on
collect-docs.tsandcompile.ts.
Generated by Claude Code
- Landing shape:
- added 3 commits that reference this issue
on Oct 9, 2026
Filing gate: ① product defect with reach measured. Class (b), violates a declared contract. The producer and the reader of one artifact disagree, and the operator is told to fix something they cannot fix. reach: the boot log of every
objectstack dev/startof a multi-package artifact whose app ships flatsrc/docspages, measured on every boot.Who acts on it: the objectstack triage seat routes it. The fix lands in the CLI's docs collector and/or the metadata plugin's residual sweep. Found by the
repo:hotcrmseat's dev on objectstack-ai/hotcrm#1907 (PR objectstack-ai/hotcrm#2011), sessionsession_012zh91QzFgePbkmuHnugLN3. ⛔ Not a claim. It holds back nothing in hotcrm's code. hotcrm's acceptance for #2011 asks for no ownership diagnostic at boot, so whether to merge with the line present is the hotcrm maintainer's call.Measured (hotcrm PR #2011,
@objectstack/*17.7.0,objectstack dev --fresh --seed-admin --compile)Every boot logs one
[MetadataPlugin] … carries N top-level metadata item(s) that none of its 2 package bodies declare …WARN. The items are hotcrm's four ADR-0046 package docs in flatsrc/docs/*.md.Behaviour equals the single-package main. The reported owner is the app package
app.objectstack.hotcrm, and the docs API serves 5 docs on both.Boot WARN count: 22 on
main, 23 on the PR head. The extra line is this one.The remedy cannot be followed in the ADR-0130 layout. A per-package docs directory must be named after the package id or its last segment (
hotcrm):src/sales/docsgivesdocs/uncollected-directory;src/service/docsis collected onto the service body.So the app package, whose directory is
src/sales/, has no docs location the build attaches to its body. An operator or agent following the WARN ("Rebuild the artifact so each collection it ships is carried by the package that owns it") would invent asrc/hotcrm/directory that ADR-0130's layout does not have.Read from source (objectstack
origin/main959c209d)packages/metadata/src/plugin.ts~1097–1112: the residual sweep registers top-level items no package body claimed under the manifest id, and warns wheneverresidual > 0.src/docs/directory to the artifact's TOP-LEVELdocs[](packages/cli/src/utils/collect-docs*; its own test reads "keeps reading the flat src/docs/ alongside the per-package ones"). The 2026-09-22 ADR-0130 addendum then leaves exactly those items as residuals.Expected (shape for triage, not a spec): either the build attaches flat
src/docsto the package that owns the manifest (the app package), or the residual sweep recognises the documented flat-docs rule and stays quiet. In both cases the warning stops telling an author to rebuild something the layout cannot express.Duplicate check
MCP
search_issueson objectstack-ai/objectstack, open and closed: "multi-package artifact top-level docs residual warning MetadataPlugin flat src/docs not claimed by any package body" → 31 hits. The nearest are:packages[i]body carry the same definitions #14512, the double serialization this sweep follows from;manifest.idwhile the registry owns it per package —crm_orderis served twice onGET /api/v1/meta/object, listed undercom.example.multi.core, and Studio's Data pillar for the App package shows the module's object #14599, top-level attribution.None reports this warning on a flat
src/docsartifact.Dedupe words: flat src/docs residual · top-level metadata item no package body · MetadataPlugin residual warn docs · ADR-0046 package docs multi-package · uncollected-directory app package
Generated by Claude Code