docs: document runtime OWD gate in permissions guide + round-2 ADR status verification#3061
Merged
Merged
Conversation
…he governance section
…partial/cloud-owned ADRs Per-decision code+test verification (same method as #3052's round 1) of the 14 remaining medium/low-density Proposed ADRs: - Flip to Accepted: 0037 (Live Canvas — all four phases landed incl. preview-evaluator + objectui surfaces), 0065 (SDUI styling — envelope, scoped-styles compiler + 4-property test, token lint; cloud half noted). - Honest partial notes, keep Proposed: 0080 (save-time compile->store not wired), 0078 (core shared completeness predicate + lint absent), 0052 (context decomposition undone), 0067 (Decision-2 turn-atomicity missing), 0022 (Slack channel->connector delegation unbuilt), 0051 (render side absent), 0076 (D3 unbuilt, D12 runtime enforcement missing), 0061 (Tier 1 claim verified TRUE; own conformance bar unmet), 0028 (NOT STARTED). - Cloud-owned banners verified accurate, framework slices noted: 0038, 0063, 0064 (service-ai genuinely absent from framework).
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
os-zhuang
marked this pull request as ready for review
July 16, 2026 13:31
os-zhuang
pushed a commit
that referenced
this pull request
Jul 16, 2026
…echeck job + correct stale ADR-0076 D12 status Two follow-ups after merging latest main: - lint.yml: the example-app typecheck step built only ./packages/* (direct children). The connector packages the showcase imports were built purely by accident — through dogfood's dependency chain — which broke when dogfood moved to packages/qa/. Request the examples' dependency closure explicitly (--filter='./examples/*^...') so the step no longer depends on which package happens to live at the top level. - ADR-0076: the round-2 status verification merged from main (#3061) was read against a pre-#3028 snapshot — svcAvailable no longer hardcodes 'available'; the D12 framework side shipped in #3028. Correct the status line and note OQ#9/OQ#10 resolution (#3037). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A1BtxNeUaGmvUYr8FwtUNu
os-zhuang
added a commit
that referenced
this pull request
Jul 16, 2026
…结论 (#2462) (#3037) * feat(transport): prove the IHttpServer port is Hono-free — second adapter on raw node:http (ADR-0076 D11/OQ#10, #2462) Multi-adapter was designed but unproven: only the Hono adapter existed, and ADR-0076 D11 flagged 'the normalized context shows Hono-isms' as a caveat blocking the transport decomposition. This adds the validation: - New @objectstack/plugin-node-server: a thin IHttpServer implementation on raw node:http with ZERO dependencies beyond @objectstack/core — :param + trailing-* routing (registration-order first-match, same as the primary adapter), eager JSON/urlencoded body parse with lazy rawBody() for binary, SSE via native res.write/end, 404/405-with-Allow semantics, EADDRINUSE retry, graceful drain on close. Deliberately no getRawApp()/mount(). - Cross-adapter conformance suite: boots the dispatcher bridge AND the REST route generator (with ObjectQL + memory driver) on BOTH adapters over real sockets — /data CRUD roundtrip, /meta reads, /ready, /health, discovery, :param routing, 404/405 parity, plus a probe-for-probe response-shape parity matrix between the two adapters. 40 assertions, all green. Findings recorded in ADR-0076 (OQ#9/OQ#10/OQ#11 resolution notes): - The port has NO hard Hono-isms. The Host-header backfill in the Hono adapter is a Fetch-API artifact local to that adapter, not a port leak. - All remaining Hono coupling is confined to the feature-detected getRawApp() escape hatch (metadata HMR, cloud-connection routes, static/SPA + CORS + Server-Timing) which degrades gracefully. - Follow-up for the D11 window: codify res.write/res.end (SSE) and getPort() — extensions consumers already rely on — plus 404/405 semantics into the IHttpServer contract. - OQ#9 audit verdict (delineate, don't merge; only discovery + packages are genuinely double-mounted) recorded in the ADR open-questions list. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A1BtxNeUaGmvUYr8FwtUNu * fix(plugin-node-server): harden query/params against prototype pollution (CodeQL) CodeQL flagged remote property injection: query-param keys come straight from the request URL, so building the map on a plain object literal let '?__proto__=…' write through the prototype chain. Use null-prototype objects for query and params and drop the dangerous keys (__proto__/constructor/prototype) outright; regression test pins that '?__proto__=polluted' is dropped and Object.prototype stays clean. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A1BtxNeUaGmvUYr8FwtUNu * fix(plugin-node-server): eliminate the dynamic property-write sink CodeQL flags The blacklist guard added in the previous commit was not recognized as a sanitizer by CodeQL's js/remote-property-injection rule — the sink is the computed write itself (obj[userKey] = …). Build query and params via Object.fromEntries (own data properties only, no prototype-chain walk) so the sink no longer exists; the __proto__/constructor/prototype drop stays as defense in depth. Regression test unchanged and green (41/41). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A1BtxNeUaGmvUYr8FwtUNu * refactor(qa): reposition the port-conformance adapter as a private QA gate — packages/qa/http-conformance Maintainer review: the node:http adapter is a validation instrument, not a product server, so it must not ship as a publishable plugin- package. Reposition it accordingly: - Move packages/plugins/plugin-node-server → packages/qa/http-conformance; rename @objectstack/plugin-node-server → @objectstack/http-conformance, private: true, test-only (no build/publish), matching the existing verification-gate packages (dogfood, downstream-contract). - packages/qa/ becomes the unified home for non-published verification gates (new pnpm-workspace glob); migrating dogfood/downstream-contract there is proposed as a follow-up. - Drop the changeset + fixed-group entry (private packages are not versioned); update the ADR-0076 OQ#10 note to the new name. Behavior unchanged: same adapter, same 41-assertion cross-adapter conformance suite, all green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A1BtxNeUaGmvUYr8FwtUNu * refactor(qa): migrate dogfood + downstream-contract into packages/qa/ (unified verification-gate home) Completes the packages/qa/ consolidation started with http-conformance: all three non-published verification gates (dogfood regression gate, downstream-contract compatibility gate, http-conformance port gate) now live under one directory. Mechanical path migration — no behavior change: - git mv packages/{dogfood,downstream-contract} → packages/qa/ - rewrite every 'packages/dogfood' / 'packages/downstream-contract' breadcrumb: spec liveness proof registry + JSON ledgers, spec-liveness-check.yml path trigger, eslint ignore, docs/ADRs, source comments - bump the repo-root traversal one level in the four dogfood conformance tests that resolve REPO_ROOT from __dirname Verified from the new locations: dogfood 273 passed / 3 skipped, downstream-contract typecheck + 14 tests, spec check:liveness resolves all bound proofs, http-conformance 41/41. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A1BtxNeUaGmvUYr8FwtUNu * chore: retrigger CI — Actions did not fire on dc6507c Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A1BtxNeUaGmvUYr8FwtUNu * docs(changeset): fix dogfood path breadcrumb after packages/qa migration Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A1BtxNeUaGmvUYr8FwtUNu * fix(ci): build the examples' dependency closure explicitly in the typecheck job + correct stale ADR-0076 D12 status Two follow-ups after merging latest main: - lint.yml: the example-app typecheck step built only ./packages/* (direct children). The connector packages the showcase imports were built purely by accident — through dogfood's dependency chain — which broke when dogfood moved to packages/qa/. Request the examples' dependency closure explicitly (--filter='./examples/*^...') so the step no longer depends on which package happens to live at the top level. - ADR-0076: the round-2 status verification merged from main (#3061) was read against a pre-#3028 snapshot — svcAvailable no longer hardcodes 'available'; the D12 framework side shipped in #3028. Correct the status line and note OQ#9/OQ#10 resolution (#3037). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A1BtxNeUaGmvUYr8FwtUNu * fix(ci): cap turbo test concurrency at the runner's core count (OOM mitigation) Test Core started failing deterministically on the hosted runner — plugin-audit#test dies with ZERO vitest output (kernel OOM-kill signature) while passing locally on Node 20 and 22 — first on main @4f8c2d1, then twice on this PR (initial run + job re-run). Onset correlates with the task graph growing past ~100 tasks (connector packages + qa gates): turbo's default concurrency (10) schedules that many vitest workers + tsup DTS builds onto a 4-vCPU runner and peak memory tips over. Cap test-step concurrency at 4 (PR affected-tests + push full-run). CPU-bound workload, so wall-clock cost is minimal; peak memory becomes bounded. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A1BtxNeUaGmvUYr8FwtUNu * fix(qa): bump repo-relative path in the newly-merged declarative-mcp dogfood test + regen lockfile after merge showcase-declarative-mcp.dogfood.test.ts landed on main (#3062) against the old packages/dogfood location; after the packages/qa migration its '../../../examples/app-showcase' URL resolved inside packages/. One more level, same as the other conformance tests. Lockfile regenerated after taking main's side in the merge. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A1BtxNeUaGmvUYr8FwtUNu --------- Co-authored-by: Claude <noreply@anthropic.com>
os-zhuang
added a commit
that referenced
this pull request
Jul 16, 2026
* feat(transport): prove the IHttpServer port is Hono-free — second adapter on raw node:http (ADR-0076 D11/OQ#10, #2462) Multi-adapter was designed but unproven: only the Hono adapter existed, and ADR-0076 D11 flagged 'the normalized context shows Hono-isms' as a caveat blocking the transport decomposition. This adds the validation: - New @objectstack/plugin-node-server: a thin IHttpServer implementation on raw node:http with ZERO dependencies beyond @objectstack/core — :param + trailing-* routing (registration-order first-match, same as the primary adapter), eager JSON/urlencoded body parse with lazy rawBody() for binary, SSE via native res.write/end, 404/405-with-Allow semantics, EADDRINUSE retry, graceful drain on close. Deliberately no getRawApp()/mount(). - Cross-adapter conformance suite: boots the dispatcher bridge AND the REST route generator (with ObjectQL + memory driver) on BOTH adapters over real sockets — /data CRUD roundtrip, /meta reads, /ready, /health, discovery, :param routing, 404/405 parity, plus a probe-for-probe response-shape parity matrix between the two adapters. 40 assertions, all green. Findings recorded in ADR-0076 (OQ#9/OQ#10/OQ#11 resolution notes): - The port has NO hard Hono-isms. The Host-header backfill in the Hono adapter is a Fetch-API artifact local to that adapter, not a port leak. - All remaining Hono coupling is confined to the feature-detected getRawApp() escape hatch (metadata HMR, cloud-connection routes, static/SPA + CORS + Server-Timing) which degrades gracefully. - Follow-up for the D11 window: codify res.write/res.end (SSE) and getPort() — extensions consumers already rely on — plus 404/405 semantics into the IHttpServer contract. - OQ#9 audit verdict (delineate, don't merge; only discovery + packages are genuinely double-mounted) recorded in the ADR open-questions list. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A1BtxNeUaGmvUYr8FwtUNu * fix(plugin-node-server): harden query/params against prototype pollution (CodeQL) CodeQL flagged remote property injection: query-param keys come straight from the request URL, so building the map on a plain object literal let '?__proto__=…' write through the prototype chain. Use null-prototype objects for query and params and drop the dangerous keys (__proto__/constructor/prototype) outright; regression test pins that '?__proto__=polluted' is dropped and Object.prototype stays clean. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A1BtxNeUaGmvUYr8FwtUNu * fix(plugin-node-server): eliminate the dynamic property-write sink CodeQL flags The blacklist guard added in the previous commit was not recognized as a sanitizer by CodeQL's js/remote-property-injection rule — the sink is the computed write itself (obj[userKey] = …). Build query and params via Object.fromEntries (own data properties only, no prototype-chain walk) so the sink no longer exists; the __proto__/constructor/prototype drop stays as defense in depth. Regression test unchanged and green (41/41). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A1BtxNeUaGmvUYr8FwtUNu * refactor(qa): reposition the port-conformance adapter as a private QA gate — packages/qa/http-conformance Maintainer review: the node:http adapter is a validation instrument, not a product server, so it must not ship as a publishable plugin- package. Reposition it accordingly: - Move packages/plugins/plugin-node-server → packages/qa/http-conformance; rename @objectstack/plugin-node-server → @objectstack/http-conformance, private: true, test-only (no build/publish), matching the existing verification-gate packages (dogfood, downstream-contract). - packages/qa/ becomes the unified home for non-published verification gates (new pnpm-workspace glob); migrating dogfood/downstream-contract there is proposed as a follow-up. - Drop the changeset + fixed-group entry (private packages are not versioned); update the ADR-0076 OQ#10 note to the new name. Behavior unchanged: same adapter, same 41-assertion cross-adapter conformance suite, all green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A1BtxNeUaGmvUYr8FwtUNu * refactor(qa): migrate dogfood + downstream-contract into packages/qa/ (unified verification-gate home) Completes the packages/qa/ consolidation started with http-conformance: all three non-published verification gates (dogfood regression gate, downstream-contract compatibility gate, http-conformance port gate) now live under one directory. Mechanical path migration — no behavior change: - git mv packages/{dogfood,downstream-contract} → packages/qa/ - rewrite every 'packages/dogfood' / 'packages/downstream-contract' breadcrumb: spec liveness proof registry + JSON ledgers, spec-liveness-check.yml path trigger, eslint ignore, docs/ADRs, source comments - bump the repo-root traversal one level in the four dogfood conformance tests that resolve REPO_ROOT from __dirname Verified from the new locations: dogfood 273 passed / 3 skipped, downstream-contract typecheck + 14 tests, spec check:liveness resolves all bound proofs, http-conformance 41/41. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A1BtxNeUaGmvUYr8FwtUNu * chore: retrigger CI — Actions did not fire on dc6507c Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A1BtxNeUaGmvUYr8FwtUNu * docs(changeset): fix dogfood path breadcrumb after packages/qa migration Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A1BtxNeUaGmvUYr8FwtUNu * fix(ci): build the examples' dependency closure explicitly in the typecheck job + correct stale ADR-0076 D12 status Two follow-ups after merging latest main: - lint.yml: the example-app typecheck step built only ./packages/* (direct children). The connector packages the showcase imports were built purely by accident — through dogfood's dependency chain — which broke when dogfood moved to packages/qa/. Request the examples' dependency closure explicitly (--filter='./examples/*^...') so the step no longer depends on which package happens to live at the top level. - ADR-0076: the round-2 status verification merged from main (#3061) was read against a pre-#3028 snapshot — svcAvailable no longer hardcodes 'available'; the D12 framework side shipped in #3028. Correct the status line and note OQ#9/OQ#10 resolution (#3037). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A1BtxNeUaGmvUYr8FwtUNu * fix(ci): cap turbo test concurrency at the runner's core count (OOM mitigation) Test Core started failing deterministically on the hosted runner — plugin-audit#test dies with ZERO vitest output (kernel OOM-kill signature) while passing locally on Node 20 and 22 — first on main @4f8c2d1, then twice on this PR (initial run + job re-run). Onset correlates with the task graph growing past ~100 tasks (connector packages + qa gates): turbo's default concurrency (10) schedules that many vitest workers + tsup DTS builds onto a 4-vCPU runner and peak memory tips over. Cap test-step concurrency at 4 (PR affected-tests + push full-run). CPU-bound workload, so wall-clock cost is minimal; peak memory becomes bounded. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A1BtxNeUaGmvUYr8FwtUNu * fix(qa): bump repo-relative path in the newly-merged declarative-mcp dogfood test + regen lockfile after merge showcase-declarative-mcp.dogfood.test.ts landed on main (#3062) against the old packages/dogfood location; after the packages/qa migration its '../../../examples/app-showcase' URL resolved inside packages/. One more level, same as the other conformance tests. Lockfile regenerated after taking main's side in the merge. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A1BtxNeUaGmvUYr8FwtUNu * ci: TEMPORARY #3071 diagnostics — isolated verbose plugin-audit runs + dmesg OOM probe plugin-audit#test dies on the hosted runner with zero captured output (3x deterministic since main@4f8c2d1) while passing locally under Node 20/22 with the exact CI command. Bracket the turbo test step with an isolated, verbose, ungrouped vitest run (before: fresh machine; after: post-graph machine + kernel OOM traces) so the real failure output cannot be lost to the GH log pipeline. SIGQUIT-on-timeout dumps Node thread stacks if it hangs. To be REMOVED once #3071's root cause is fixed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A1BtxNeUaGmvUYr8FwtUNu --------- Co-authored-by: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Docs-only follow-up to #3052, two commits:
1.
authorization.mdx— document the runtime OWD posture gateThe "Governance: how declared = enforced is kept true" section listed four CI-time mechanisms; #3052 added a fifth that is runtime. Added a Runtime OWD posture gate bullet (env-tighten-only over packaged declarations →
403 owd_widening_forbidden;externalSharingModel ≤ sharingModel→403 owd_external_wider; write-path only) and updated the intro to "Five mechanisms — four CI-time, one runtime". This was the docs-drift-check advisory on #3052.2. Round-2 ADR status verification (14 ADRs)
Same per-decision code+test method as round 1 (#3052), applied to the remaining medium/low-density Proposed ADRs:
Flipped to Accepted (2):
previewDraftsreads, objectui LiveCanvas/PreviewModeContext/DraftPreviewBar,preview-evaluator.ts+ test, assistantBus)Honest partial notes, kept Proposed (9): each now states exactly what landed and what is missing —
svcAvailablestill hardcodesavailable), 0061 (Tier-1 claim verified TRUE; its own conformance bar unmet), 0028 (NOT STARTED — target model entirely unbuilt)Cloud-owned banners verified accurate (3): 0038 / 0063 / 0064 —
service-aiis genuinely absent from framework; framework-side slices (L3 build probes,skill.surface/agent.surfaceenums) noted.Notes
docs/+content/docs/edits.Proposedbut says precisely which half.🤖 Generated with Claude Code
Generated by Claude Code