From 3c8ae08e78d75b09f6432132bf6d158d00d6581c Mon Sep 17 00:00:00 2001 From: Raghu Betina Date: Sun, 18 Oct 2026 07:25:59 -0500 Subject: [PATCH] Adopt the rails-sketch/2026-10 target profile First Draft moves its Rails target from 8.1.3.1 to 8.1.4 (see firstdraft/firstdraft#1191). Rails 8.1.4 dumps schema columns in declaration order and changes titleize, so on 2026-10-16 the owner gave the target a new profile ID, rails-sketch/2026-10. The Plan format stays sketch/0.23; the Service changes its target.profile constant in place. plan init now writes the new profile, and artifact validation accepts only it. An artifact for rails-sketch/2026-09-bookmark-assets reports invalid_artifact, which the older-profile test now exercises. The Service marks the break with API contract 0.8.0, and the CLI takes 0.9.0, the pre-1.0 minor bump for a breaking change. The accepted range becomes >= 0.8.0, < 0.9.0, so the release compatibility check refuses this CLI beside a 0.7.x Service. The CLI still does not read the FirstDraft-API-Contract header at runtime. The plan status zero-gap digest covers the target, so it is recomputed with the Service's GapSet serialization, JSON.pretty_generate plus a newline; the same method reproduces the previous digest. --- CHANGELOG.md | 15 +++++++++++++++ docs/commands.md | 10 +++++----- package-lock.json | 4 ++-- package.json | 2 +- release/compatibility.json | 4 ++-- src/compilation-artifact.js | 2 +- test/compilation-artifact.test.js | 5 ++++- test/plan-status.test.js | 4 ++-- 8 files changed, 32 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a5dcf80..703f56b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,21 @@ carry no release status. The `v` tag and npm show whether a version is Entries start with the first version prepared after this file was added, and earlier versions have none. The repository's [tags](https://github.com/firstdraft/cli/tags) identify the source of each published version. +## 0.9.0 + +Moves the Rails target to profile `rails-sketch/2026-10`. First Draft adopts Rails 8.1.4 under that new profile ID and +API contract `0.8.0`, because Rails 8.1.4 changes the generated schema's column order and an inflection rule. + +- `plan init` writes Plans that target `rails-sketch/2026-10`. The Plan format stays + `firstdraft.foundation-plan.sketch/0.23`. +- `plan compile` and `compilation download` accept only artifacts for `rails-sketch/2026-10`. An artifact for + `rails-sketch/2026-09-bookmark-assets` reports `invalid_artifact`. +- The accepted API-contract range is `>= 0.8.0` and `< 0.9.0`. + +Use CLI 0.9.0 with a Service that serves API `0.8.x`; CLI 0.8.2 writes and accepts only the retired profile. Projects +and Plans on the retired profile are not migrated. First Draft refuses them, and its refusal names the fix: start a +new Project from the Plan. + ## 0.8.2 Adds `firstdraft compilation cancel `, so an agent can recover a Compilation that will not finish diff --git a/docs/commands.md b/docs/commands.md index 4a171b9..46b8683 100644 --- a/docs/commands.md +++ b/docs/commands.md @@ -3,10 +3,10 @@ This page owns the detailed public semantics of the current command surface. Run `firstdraft --help` or a command group's `--help` for concise executable syntax. See [Errors and recovery](errors.md) before retrying a failed mutation. -The current `0.8.x` source line contains the auditable command shell, browser and device login, local Foundation Plan initialization, local +The current `0.9.x` source line contains the auditable command shell, browser and device login, local Foundation Plan initialization, local application-key and UUID generation, conditional whole-document push, whole-graph analysis status polling, direct Compile-and-materialize and private publish orchestration, and retained-Compilation inspection and cancellation. -CLI `0.8.x` requires the service's `0.7.x` API contract. The +CLI `0.9.x` requires the service's `0.8.x` API contract. The [changelog](https://github.com/firstdraft/cli/blob/main/CHANGELOG.md) describes each version. ## Command map @@ -139,7 +139,7 @@ From the project that the Plan describes: firstdraft plan init --name "Oscar Party" ``` -This creates an empty `firstdraft.foundation-plan.sketch/0.23` Plan targeting `rails-sketch/2026-09-bookmark-assets` and a +This creates an empty `firstdraft.foundation-plan.sketch/0.23` Plan targeting `rails-sketch/2026-10` and a client-generated Project ID under `.firstdraft/`. A nested ignore file keeps that local scratch area out of Git without changing the project's own `.gitignore`. Initialization makes no network request and refuses to replace an existing `.firstdraft` path. @@ -390,7 +390,7 @@ local paths, or environment values. Success writes exactly the validated private newline to stdout. If the command fails after progress has begun, its structured JSON error envelope is the final stderr document after the progress lines. -The closed API `0.7.x` progress-reason allowlist is `github.configuration_missing`, `github.oauth_unavailable`, +The closed API `0.8.x` progress-reason allowlist is `github.configuration_missing`, `github.oauth_unavailable`, `github.api_unavailable`, `github.reauthorization_required`, `github.account_mismatch`, `github.installation_unavailable`, `github.installation_not_ready`, `github.preflight_unavailable`, the legacy-only `github.preflight_unclassified`, and these stage-specific fallbacks: `github.preflight_unavailable.configuration`, @@ -440,7 +440,7 @@ never starts replacement work. An incomplete rollback leaves `.firstdraft-root-o reconciliation before this command can run again. Artifact validation accepts only Plan format `firstdraft.foundation-plan.sketch/0.23` and target profile -`rails-sketch/2026-09-bookmark-assets`, in addition to matching the retained Compilation's provenance and verifying file integrity. +`rails-sketch/2026-10`, in addition to matching the retained Compilation's provenance and verifying file integrity. An earlier format or profile is rejected before materialization, even when the retained status names that profile. Successful root adoption is intentionally one-way. The original `.firstdraft` authoring state moves under diff --git a/package-lock.json b/package-lock.json index 43fb8c9..d5b3cf3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@firstdraft.com/cli", - "version": "0.8.2", + "version": "0.9.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@firstdraft.com/cli", - "version": "0.8.2", + "version": "0.9.0", "license": "MIT", "bin": { "firstdraft": "bin/firstdraft.js" diff --git a/package.json b/package.json index fa5bbd9..bff5cfb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@firstdraft.com/cli", - "version": "0.8.2", + "version": "0.9.0", "description": "Command-line interface for First Draft", "license": "MIT", "type": "module", diff --git a/release/compatibility.json b/release/compatibility.json index 97a50fd..e01eb2a 100644 --- a/release/compatibility.json +++ b/release/compatibility.json @@ -1,9 +1,9 @@ { "format": "firstdraft.release-compatibility/1", "component": "cli", - "version": "0.8.2", + "version": "0.9.0", "requires": { - "api_contract": [">= 0.7.0", "< 0.8.0"], + "api_contract": [">= 0.8.0", "< 0.9.0"], "foundation_plan_formats": ["firstdraft.foundation-plan.sketch/0.23"] } } diff --git a/src/compilation-artifact.js b/src/compilation-artifact.js index 43c95bb..50e8eb9 100644 --- a/src/compilation-artifact.js +++ b/src/compilation-artifact.js @@ -27,7 +27,7 @@ export const ARTIFACT_MEDIA_TYPE = "application/vnd.firstdraft.compilation-artifact+json"; export const ARTIFACT_FORMAT = "firstdraft.compilation-artifact/1"; export const FOUNDATION_PLAN_FORMAT = "firstdraft.foundation-plan.sketch/0.23"; -export const RAILS_TARGET_PROFILE = "rails-sketch/2026-09-bookmark-assets"; +export const RAILS_TARGET_PROFILE = "rails-sketch/2026-10"; export const MAX_ARTIFACT_BYTES = 128 * 1024 * 1024; const ARTIFACT_KEYS = ["format", "provenance", "manifest_sha256", "files"]; diff --git a/test/compilation-artifact.test.js b/test/compilation-artifact.test.js index 00ee957..914bc7c 100644 --- a/test/compilation-artifact.test.js +++ b/test/compilation-artifact.test.js @@ -306,7 +306,10 @@ test("pins external provenance identities and validates nested metadata", () => }); test("rejects an older target profile even when retained status agrees", () => { - const target = { id: "rails", profile: "rails-sketch/2026-09" }; + const target = { + id: "rails", + profile: "rails-sketch/2026-09-bookmark-assets", + }; const fixture = artifactFixture({ provenance: { target } }); assert.throws( diff --git a/test/plan-status.test.js b/test/plan-status.test.js index 393b48d..1bb03e0 100644 --- a/test/plan-status.test.js +++ b/test/plan-status.test.js @@ -37,7 +37,7 @@ const ANALYZER_RELEASE = "foundation-plan-rails/application-2026-09-27-bookmark-assets"; const COMPILER_RELEASE = "foundation-plan-rails/compiler-application-2026-09-27-bookmark-assets"; -const TARGET = { id: "rails", profile: "rails-sketch/2026-09-bookmark-assets" }; +const TARGET = { id: "rails", profile: "rails-sketch/2026-10" }; const PLAN_STATUS_HELP = `First Draft CLI Usage: @@ -250,7 +250,7 @@ test("plan status accepts the pinned Service zero-gap canonical digest", async ( const body = analysisBody("valid"); body.analysis.gap_set.gaps = []; body.analysis.gap_set_sha256 = - "acf87b117814f28e52a85e6c13fb77e58166a38038bb36a6e0b6177995262618"; + "c38373ec9f208fb4abb6eeec29c447142dc4f6dd706c8a48286abee4d55d66a8"; const result = await invoke(["plan", "status"], { cwd, fetchFunction: recordingFetch([jsonResponse(body)], []),