diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 7dd3ed20..7aaac7a8 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -1,16 +1,18 @@ -name: Publish json-document prerelease +name: Publish v2 prerelease package on: push: tags: - "json-document-v*-rc.*" + - "json-document-collaboration-v*-rc.*" + - "json-document-contenteditable-collaboration-v*-rc.*" permissions: contents: read id-token: write concurrency: - group: npm-json-document-${{ github.ref }} + group: npm-v2-package-${{ github.ref }} cancel-in-progress: false jobs: @@ -30,15 +32,39 @@ jobs: node-version: "24" registry-url: "https://registry.npmjs.org" package-manager-cache: false - - name: Verify core prerelease identity - if: startsWith(github.ref_name, 'json-document-v') + - name: Resolve prerelease package + id: release env: RELEASE_TAG: ${{ github.ref_name }} run: | node --input-type=module --eval ' - import { readFileSync } from "node:fs"; - const pkg = JSON.parse(readFileSync("packages/json-document/package.json", "utf8")); - const expectedTag = `json-document-v${pkg.version}`; + import { appendFileSync, readFileSync } from "node:fs"; + + const releases = [ + { + prefix: "json-document-contenteditable-collaboration-v", + packageFile: "packages/contenteditable-collaboration/package.json", + workspace: "@interactive-os/json-document-contenteditable-collaboration", + }, + { + prefix: "json-document-collaboration-v", + packageFile: "packages/json-document-collaboration/package.json", + workspace: "@interactive-os/json-document-collaboration", + }, + { + prefix: "json-document-v", + packageFile: "packages/json-document/package.json", + workspace: "@interactive-os/json-document", + }, + ]; + + const release = releases.find(({ prefix }) => process.env.RELEASE_TAG.startsWith(prefix)); + if (release === undefined) { + throw new Error(`unsupported release tag ${process.env.RELEASE_TAG}`); + } + + const pkg = JSON.parse(readFileSync(release.packageFile, "utf8")); + const expectedTag = `${release.prefix}${pkg.version}`; if (process.env.RELEASE_TAG !== expectedTag) { throw new Error(`release tag ${process.env.RELEASE_TAG} does not match ${expectedTag}`); } @@ -48,10 +74,13 @@ jobs: if (pkg.publishConfig?.tag !== "next") { throw new Error("publishConfig.tag must remain next for prereleases"); } + appendFileSync(process.env.GITHUB_OUTPUT, `workspace=${release.workspace}\n`); ' - name: Install dependencies run: npm ci --no-audit --no-fund - - name: Verify core prerelease + - name: Verify v2 prerelease graph run: npm run release:check - - name: Publish core prerelease - run: npm publish -w @interactive-os/json-document --tag next --provenance + - name: Publish prerelease package + env: + RELEASE_WORKSPACE: ${{ steps.release.outputs.workspace }} + run: npm publish -w "$RELEASE_WORKSPACE" --tag next --access public --provenance diff --git a/docs/changelog.md b/docs/changelog.md index e3a0e116..6f3348cb 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -5,6 +5,12 @@ All notable changes to the active v2 packages are documented here. The complete ## Unreleased +- Added independent prerelease tag publishing for the Core and both optional + collaboration packages, and kept the live-site archive gate aware of the two + supported v2 companions. +- Enabled the two root-value cases that the active RFC 6902 implementation + already conforms to and documented the two vendored duplicate-member cases + that JSON module parsing cannot represent. - Added the independently versioned, transport-free `@interactive-os/json-document-collaboration` provider. Local and collaborative runtimes expose the same six-member `JSONDocument` Projection; diff --git a/docs/generated/repo-catalog.json b/docs/generated/repo-catalog.json index e56eebb8..5b420a8a 100644 --- a/docs/generated/repo-catalog.json +++ b/docs/generated/repo-catalog.json @@ -59,7 +59,7 @@ "status": "companion", "private": false, "publishable": true, - "version": "0.1.0", + "version": "0.1.0-rc.0", "description": "Transport-free causal collaboration provider for @interactive-os/json-document.", "license": "MIT", "summary": "Transport-free causal collaboration provider for the six-member\n`@interactive-os/json-document` Projection contract.", @@ -119,7 +119,7 @@ "status": "companion", "private": false, "publishable": true, - "version": "0.1.0", + "version": "0.1.0-rc.0", "description": "IME-safe contenteditable publication lease for json-document collaboration text.", "license": "MIT", "summary": "IME-safe DOM publication lease for\n`@interactive-os/json-document-collaboration/text`.", diff --git a/docs/standard/v2-projection-profile.md b/docs/standard/v2-projection-profile.md index aaa3262e..de0fdd55 100644 --- a/docs/standard/v2-projection-profile.md +++ b/docs/standard/v2-projection-profile.md @@ -161,7 +161,10 @@ conformance corpus의 public-root binding을 서로 분리한다. | `packages/json-document/tests/public/v2-jsonpath-standard-conformance.test.ts` | public root Projection의 전체 RFC 9535 CTS binding | suite가 export하는 structural type은 test harness 내부 계약이며 package public -export가 아니다. +export가 아니다. Vendored RFC 6902 corpus 112건 중 110건을 실행한다. 남은 2건은 +원본 JSON에 중복 `op` member가 있지만 JSON module parsing 단계에서 마지막 +member만 남아 public operation object로는 그 입력을 표현할 수 없어, 각 fixture에 +명시적인 `disabledReason`을 기록한다. 21개 요구사항의 현재 증거 상태는 runtime 13개, static 6개, deferred 2개다. schema-free `applyPatch`는 구현됐다. transform identity의 two-provider 검증, diff --git a/package-lock.json b/package-lock.json index 66c980c4..f328f0d0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5028,7 +5028,7 @@ }, "packages/contenteditable-collaboration": { "name": "@interactive-os/json-document-contenteditable-collaboration", - "version": "0.1.0", + "version": "0.1.0-rc.0", "license": "MIT", "devDependencies": { "@interactive-os/json-document": "*", @@ -5040,7 +5040,7 @@ }, "peerDependencies": { "@interactive-os/json-document": "^2.0.0-rc.0", - "@interactive-os/json-document-collaboration": "^0.1.0" + "@interactive-os/json-document-collaboration": "^0.1.0-rc.0" } }, "packages/json-document": { @@ -5055,7 +5055,7 @@ }, "packages/json-document-collaboration": { "name": "@interactive-os/json-document-collaboration", - "version": "0.1.0", + "version": "0.1.0-rc.0", "license": "MIT", "devDependencies": { "@interactive-os/json-document": "*", diff --git a/packages/contenteditable-collaboration/package.json b/packages/contenteditable-collaboration/package.json index d5147b45..88758189 100644 --- a/packages/contenteditable-collaboration/package.json +++ b/packages/contenteditable-collaboration/package.json @@ -1,6 +1,6 @@ { "name": "@interactive-os/json-document-contenteditable-collaboration", - "version": "0.1.0", + "version": "0.1.0-rc.0", "description": "IME-safe contenteditable publication lease for json-document collaboration text.", "type": "module", "license": "MIT", @@ -47,7 +47,7 @@ }, "peerDependencies": { "@interactive-os/json-document": "^2.0.0-rc.0", - "@interactive-os/json-document-collaboration": "^0.1.0" + "@interactive-os/json-document-collaboration": "^0.1.0-rc.0" }, "devDependencies": { "@interactive-os/json-document": "*", diff --git a/packages/json-document-collaboration/package.json b/packages/json-document-collaboration/package.json index 1a58f57b..79dfa737 100644 --- a/packages/json-document-collaboration/package.json +++ b/packages/json-document-collaboration/package.json @@ -1,6 +1,6 @@ { "name": "@interactive-os/json-document-collaboration", - "version": "0.1.0", + "version": "0.1.0-rc.0", "description": "Transport-free causal collaboration provider for @interactive-os/json-document.", "type": "module", "license": "MIT", diff --git a/packages/json-document/tests/conformance/v2/rfc6902-suite.ts b/packages/json-document/tests/conformance/v2/rfc6902-suite.ts index 24dc06af..9875456e 100644 --- a/packages/json-document/tests/conformance/v2/rfc6902-suite.ts +++ b/packages/json-document/tests/conformance/v2/rfc6902-suite.ts @@ -14,6 +14,7 @@ interface RFC6902Case { readonly expected?: unknown; readonly error?: string; readonly disabled?: boolean; + readonly disabledReason?: string; } export interface RFC6902Harness { @@ -35,7 +36,7 @@ export function runRFC6902Conformance(harness: RFC6902Harness): void { for (const [index, testCase] of allCases.entries()) { const label = `[${index}] ${testCase.comment ?? "(no comment)"}`; if (testCase.disabled) { - test.skip(label, () => undefined); + test.skip(`${label} — ${testCase.disabledReason ?? "no reason recorded"}`, () => undefined); continue; } @@ -58,8 +59,13 @@ export function runRFC6902Conformance(harness: RFC6902Harness): void { test("vendored suite size is intentional", () => { expect(allCases).toHaveLength(112); - expect(allCases.length - disabled).toBe(108); - expect(disabled).toBe(4); + expect(allCases.length - disabled).toBe(110); + expect(disabled).toBe(2); + expect( + allCases + .filter((testCase) => testCase.disabled) + .every((testCase) => testCase.disabledReason !== undefined), + ).toBe(true); }); }); } diff --git a/packages/json-document/tests/public/json-patch/conformance/spec_tests.json b/packages/json-document/tests/public/json-patch/conformance/spec_tests.json index c160535b..696c2ec4 100644 --- a/packages/json-document/tests/public/json-patch/conformance/spec_tests.json +++ b/packages/json-document/tests/public/json-patch/conformance/spec_tests.json @@ -193,7 +193,8 @@ { "op": "add", "path": "/baz", "value": "qux", "op": "remove" } ], "error": "operation has two 'op' members", - "disabled": true + "disabled": true, + "disabledReason": "JSON parsing collapses the duplicate op member before the operation reaches the public API" }, { diff --git a/packages/json-document/tests/public/json-patch/conformance/tests.json b/packages/json-document/tests/public/json-patch/conformance/tests.json index ae1f7f02..c24bf478 100644 --- a/packages/json-document/tests/public/json-patch/conformance/tests.json +++ b/packages/json-document/tests/public/json-patch/conformance/tests.json @@ -52,8 +52,7 @@ { "comment": "Toplevel scalar values OK?", "doc": "foo", "patch": [{"op": "replace", "path": "", "value": "bar"}], - "expected": "bar", - "disabled": true }, + "expected": "bar" }, { "comment": "replace object document with array document?", "doc": {}, @@ -264,7 +263,7 @@ { "comment": "Whole document", "doc": { "foo": 1 }, "patch": [{"op": "test", "path": "", "value": {"foo": 1}}], - "disabled": true }, + "expected": { "foo": 1 } }, { "comment": "Empty-string element", "doc": { "": 1 }, @@ -443,7 +442,8 @@ "patch": [ { "op": "add", "path": "/baz", "value": "qux", "op": "move", "from":"/foo" } ], "error": "patch has two 'op' members", - "disabled": true }, + "disabled": true, + "disabledReason": "JSON parsing collapses the duplicate op member before the operation reaches the public API" }, { "comment": "unrecognized op should fail", "doc": {"foo": 1}, diff --git a/scripts/evaluate-archive-isolation.mjs b/scripts/evaluate-archive-isolation.mjs index 2728ec12..6514df06 100644 --- a/scripts/evaluate-archive-isolation.mjs +++ b/scripts/evaluate-archive-isolation.mjs @@ -48,7 +48,7 @@ if ( ] !== "^2.0.0-rc.0" || contenteditableCollaborationPackage.peerDependencies?.[ "@interactive-os/json-document-collaboration" - ] !== "^0.1.0" + ] !== "^0.1.0-rc.0" ) { failures.push("the contenteditable collaboration companion surface is invalid"); } diff --git a/scripts/evaluate-live-site.mjs b/scripts/evaluate-live-site.mjs index 8c18eeac..92a064ce 100644 --- a/scripts/evaluate-live-site.mjs +++ b/scripts/evaluate-live-site.mjs @@ -5,6 +5,10 @@ const siteUrl = (process.env.SITE_URL ?? "https://developer-1px.github.io/json-d const attempts = Number(process.env.SITE_LIVE_ATTEMPTS ?? "18"); const delayMs = Number(process.env.SITE_LIVE_DELAY_MS ?? "10000"); const routes = JSON.parse(readFileSync(new URL("../apps/site/src/site-routes.json", import.meta.url), "utf8")); +const v2CompanionPackages = new Set([ + "@interactive-os/json-document-collaboration", + "@interactive-os/json-document-contenteditable-collaboration", +]); validateSiteRoutes(routes, fail); function fail(message) { @@ -74,8 +78,9 @@ async function checkOnce() { ) { fail("live llms.txt is missing the v2 Core contract."); } + const packageReferences = llms.match(/@interactive-os\/json-document-[a-z0-9-]+/g) ?? []; if ( - /@interactive-os\/json-document-(?:[a-z0-9-]+)/.test(llms) + packageReferences.some((packageName) => !v2CompanionPackages.has(packageName)) || /@interactive-os\/json-document\/(?:session|react)\b/.test(llms) || /\blabs\/extensions\b/.test(llms) ) {