From 6de4888a05955c577b07e9b996da3d0c16e06879 Mon Sep 17 00:00:00 2001 From: Raghu Betina Date: Mon, 12 Oct 2026 11:41:23 -0500 Subject: [PATCH] Preview first and follow the app's AGENTS.md On 2026-10-12 the owner changed what the user's agent does after Compile. It writes any Behavior to write item that makes Home raise, previews without asking, and debugs any other failure as its own without weakening a spec. The service's next Compiler puts that rule in the generated AGENTS.md, so the test run and continuation now point there instead of restating it. The old rule, which held the preview until every item was written and handed other failures to the user, is gone. The same review found steps that changed no outcome. The Skill no longer asks how involved the user wants to be: no workshop Plan had a choice it governed. It makes implementation choices, names them in the read-back, and asks only on request. After "make the rest of the decisions for me", the read-back is a progress update and Compile follows. The read-back drops its technical block and gaps-readback.md, which copied the GapSet on every byte change; the SHA rechecks, which the CLI's local_plan_changed covers; the local JSON Schema validator procedure, since plan push validates; the exact CLI version probe; and the readable-file check, which local_input_unreadable covers. A destroy without show now defaults to adding show instead of a read-back question. The hand-off report shrinks to where the app is, what works, what comes next, and how to preview it. The interview no longer asks about email confirmation, by the owner's decision of the same day: verification stays out unless the user asks, so sign-up signs people in at once and they can share the app with friends right away. The After-Compile email item says reset and unlock emails are not delivered until a mail provider is added. Two stale lines go: the gap example of a comment on a post or an album, whose storage and models now compile, and the "Compiler without stubs" hedge. The evals follow. The level cases expect no level question, delegation compiles after a progress update, the failing-spec case expects debugging instead of a hand-back, and the two local validator cases are removed. A generated AGENTS.md fixture is staged where the cases now read it, and the evaluator's interview protocol drops the digest and gaps file as well. The plugin version moves to 0.8.16 because 0.8.15 is published and its compatibility bytes must match its tag. The package digest is left for the release to record. --- CHANGELOG.md | 32 ++++ RELEASING.md | 3 +- evals/README.md | 3 +- evals/create-full-stack-app/cases.json | 167 +++++------------- .../fixtures/generated-application-AGENTS.md | 64 +++++++ .../fixtures/generated-application-README.md | 12 +- .../fixtures/schema-library-only.package.json | 8 - .../candidate-interview-protocol.md | 34 ++-- package-lock.json | 4 +- package.json | 2 +- .../claude-plugin/.claude-plugin/plugin.json | 2 +- packages/claude-plugin/package.template.json | 2 +- release/compatibility.json | 2 +- skills/create-full-stack-app/SKILL.md | 111 +++++------- .../references/diagnostics-and-recovery.md | 56 +++--- .../references/foundation-plan-023.md | 37 ++-- .../references/interview.md | 61 +++---- .../references/modeling-guide.md | 31 ++-- test/release-compatibility.test.mjs | 9 - test/repository.test.mjs | 57 +----- 20 files changed, 300 insertions(+), 397 deletions(-) create mode 100644 evals/create-full-stack-app/fixtures/generated-application-AGENTS.md delete mode 100644 evals/create-full-stack-app/fixtures/schema-library-only.package.json diff --git a/CHANGELOG.md b/CHANGELOG.md index dc736e7..37474fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,38 @@ Entries are newest first. Keep their headings stable. Publish material correctio new entries so readers who advanced their checkpoint see them. Entries explain what changed, why, when it applies, and any useful small example or verification; they need not reproduce commit logs. +## 2026-10-12: Agents preview first and debug failures + +**Skills — released in plugin 0.8.16.** Once the First Draft service deploys the matching Compiler, a generated app's +`AGENTS.md` changes how the agent treats the first spec run. Before, the agent wrote every item in the README's +Behavior to write before the first preview, asked you before previewing otherwise, and reported any other failing spec +to you as a First Draft defect. Now it first writes any item whose entry says Home raises, starts the preview, and +tells you in one line which pages deny or raise until the rest are written. It debugs any other failure as its own and +never skips, deletes, or loosens an example to get a green run. When generated code caused the failure, it adds one +line under "First Draft defects" in `.firstdraft/design/implementation-notes.md`. + +The app's `AGENTS.md` also says that `.firstdraft/submitted-foundation-plan.json` and `.firstdraft/gaps.json` record +what was compiled and never govern later code, and that a Behavior to write entry is deleted once its specs pass. It +says how to add a resource the way the generated ones are built. Generated controllers declare `verify_authorized` and +`ApplicationController` does not, so a controller from `bin/rails generate scaffold` is public until it gets that +declaration, a Policy with a rule, a relation scope, and a spec, and request specs for each denial. + +The Skill now follows the app's `AGENTS.md` for the test run instead of restating it. It no longer asks how involved +you want to be in technical decisions: it makes them, names them in the read-back, and asks only if you say you want +to be asked. After "make the rest of the decisions for me", the read-back is a progress update and Compile follows in +the same turn. The read-back drops its closing technical block and the `gaps-readback.md` file, and the Skill drops +its local JSON Schema validation step and its exact CLI version check; `plan push` validates the Plan. When `destroy` +comes without `show`, the Skill adds `show` so each record's page carries Delete, and names that choice in the +read-back instead of asking. The hand-off report now says where the app is, what works, what the agent writes next, +and how to preview it. + +The interview no longer asks about email confirmation. The Skill leaves `verification` out unless you ask for it, so +sign-up signs people in at once and you can share the app with friends right away. Password reset and lockout stay; +their emails are not delivered until you add a mail provider, as the Account email section of `DEPLOY.md` describes. + +Apps compiled earlier keep their `AGENTS.md`. To adopt the new rules, ask your agent to compare its spec bullet with +this entry and update it. + ## 2026-10-12: State Machine events First Draft cannot generate are stubs **Skills — released in plugin 0.8.15.** Plugin 0.8.14 carried the same text but was never published: its tag was pushed while a GitHub Actions incident had dropped its main CI run, so the publish workflow refused it. Once the First Draft service deploys the matching Compiler, a required, diff --git a/RELEASING.md b/RELEASING.md index a92e652..e128fa2 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -53,8 +53,7 @@ packaged lines it lists. `script/cli-contract/config.mjs` names the bundled CLI by `cliPackageVersion`, `cliRevision`, and `cliRuntimeSha256`. To bundle a new CLI, edit them by hand, along with `requires.cli` in [`release/compatibility.json`](release/compatibility.json). CI checks out `cliRevision` from CLI `main`, so land the -CLI first. `sh script/check` then fails until the Skill's startup version probe and its `@firstdraft.com/cli@` -references name the new CLI. +CLI first. `sh script/check` then fails until the Skill's `@firstdraft.com/cli@` references name the new CLI. **What breaks Skills CI without warning.** Skills keeps copies of CLI facts, and CI compares them only against the pinned CLI. No CLI check fails when they change, so the next pin change fails here instead: diff --git a/evals/README.md b/evals/README.md index 6b8ad71..77de9cf 100644 --- a/evals/README.md +++ b/evals/README.md @@ -20,8 +20,7 @@ For existing-app UI work, use the separate [UI continuation corpus](ui-continuat - `reconcile-habit-requirements`, then `reconcile-habit-creation-only-revision`; - `author-deliberate-return-overrides`, then `preserve-current-location-return`; - `precompile-semantic-read-back`, then `compile-prepared-movie-catalog`; - - `precompile-drawing-board-read-back`, then `compile-prepared-drawing-board-application`; - - `failing-generated-spec-is-first-draft-defect`, then `preview-despite-failing-generated-spec`. + - `precompile-drawing-board-read-back`, then `compile-prepared-drawing-board-application`. - Give the executing agent only its prompt, the Skill, and its input artifacts, not the expectations. Stage model-only artifacts outside the workspace that root adoption will archive. - The interview case attaches diff --git a/evals/create-full-stack-app/cases.json b/evals/create-full-stack-app/cases.json index 0053ad9..82ee1cc 100644 --- a/evals/create-full-stack-app/cases.json +++ b/evals/create-full-stack-app/cases.json @@ -115,6 +115,7 @@ "prompt": "Use First Draft to plan a book club app for my workshop. People sign up with their name, email and password, then see the club's books; only signed-in members can see the book list. Choose reasonable details for my review. I have no artifacts to share. Keep this local; do not submit or Compile.", "expectations": [ "Authors one Account with an email identifier, password sign-in, self-service registration, password-reset recovery and lockout, and omits verification because the user did not ask for email confirmation.", + "Does not ask whether people must confirm their email; says sign-up signs people in at once so the user can share the app with friends right away.", "Says plainly in the read-back that people can sign in right after signing up and that email confirmation is available if the user wants it.", "Makes no service request, Compile or remote write." ] @@ -170,39 +171,39 @@ ] }, { - "id": "interview-opening-asks-level-once", + "id": "interview-opening-without-level-question", "should_trigger": true, "prompt": "Help me make an app for my neighborhood's tool library, where neighbors lend each other tools. This is our first message; keep it local and do not contact First Draft yet.", "expectations": [ "Restates the idea in a sentence and proposes a name, asking about the idea itself only if it needs clarifying.", "Invites materials such as design docs, screenshots, a CSV of sample data, or an app the user likes, and says none is required.", - "Asks once whether it should make the technical decisions for the user, explain them as it goes, or ask about them.", - "Asks no more than three questions in this opening turn and leaves details such as list fields, deletion, and appearance for later turns.", + "Does not ask how involved the user wants to be in technical decisions; it makes them itself and names them in the read-back.", + "Asks no more than two questions in this opening turn and leaves details such as list fields, deletion, and appearance for later turns.", "Does not ask about hosting.", "Runs no plan push, plan status, or plan compile and makes no First Draft service request in this opening turn; a brief web search for similar apps is expected." ] }, { - "id": "interview-level-not-asked-again", + "id": "interview-explains-when-asked", "should_trigger": true, - "prompt": "Earlier in this conversation you asked whether to make the technical decisions for me, explain them as you go, or ask me about them, and I said to explain them as you go. We settled that it's a tool library for my neighborhood, private to neighbors who sign up, web only. Keep going with the interview. I have no artifacts to share. Keep this local; do not contact First Draft.", + "prompt": "Earlier in this conversation I asked you to explain technical choices as you go. We settled that it's a tool library for my neighborhood, private to neighbors who sign up, web only. Keep going with the interview. I have no artifacts to share. Keep this local; do not contact First Draft.", "expectations": [ - "Does not ask the level question again.", + "Does not ask how involved the user wants to be in technical decisions.", "Asks one product decision in this turn, with one line on why it matters and two to four options with its recommendation first.", - "When a technical choice comes up, explains it in a plain sentence because the user chose to have choices explained, while still asking product meaning such as whether a tool can be lent to two neighbors at once.", + "When a technical choice comes up, explains it in a plain sentence because the user asked for explanations, while still asking product meaning such as whether a tool can be lent to two neighbors at once.", "Makes no service request, Compile or remote write." ] }, { "id": "interview-decide-the-rest", "should_trigger": true, - "prompt": "We're planning a recipe board for my cooking club. You asked my level and I said to make the technical decisions for me. I told you members sign up, share recipes with a title and instructions, and every page needs sign-in. You just asked whether members can comment on recipes: yes. Now make the rest of the decisions for me. I have no artifacts to share. Keep this local; do not submit or Compile.", + "prompt": "We're planning a recipe board for my cooking club. I told you members sign up, share recipes with a title and instructions, and every page needs sign-in. You just asked whether members can comment on recipes: yes. Now make the rest of the decisions for me. I have no artifacts to share. Keep this local; do not submit or Compile.", "expectations": [ "Asks no further product or implementation questions.", "Chooses its recommendation for each remaining item, including product meaning such as who may edit or delete a comment and what happens to comments when a recipe is deleted, and records each as delegated.", "Writes those choices into .firstdraft/foundation-plan.json instead of leaving them open.", "Walks the coverage checklist without presenting it as questions, and writes the applicable After Compile items into implementation-notes.md.", - "Summarizes the delegated choices plainly so the user can still correct them. Treats the delegation as covering decisions, not approval: it does not claim the candidate is approved, and a later read-back still asks once for approval before Compile.", + "Gives the read-back as a progress update that names the delegated choices plainly and says the user can change any of them later in the app. Treats the delegation as covering the read-back: asks no approval question and does not Compile only because this prompt says not to.", "Makes no service request, Compile or remote write." ] }, @@ -228,7 +229,7 @@ "Opens the reply with a few lines on what it found, with sources.", "Says in this opening turn, in plain words, that First Draft can build the backbone, such as drivers, cars, tracks, sessions, and laps, but not the real-time sensor reading and advice, which is the core of the idea.", "Names what builds that part and where, such as native Swift or Kotlin added to the generated iPhone or Android project, and says those projects are Hotwire Native shells around the web app.", - "Then asks the opening questions, at most three, including once whether it should make the technical decisions, explain them as it goes, or ask about them.", + "Then asks the opening questions, at most two, and does not ask how involved the user wants to be in technical decisions.", "Runs no plan push, plan status, or plan compile and makes no First Draft service request in this opening turn." ] }, @@ -253,7 +254,7 @@ "Says plainly that First Draft isn't the right tool for the game itself, because the core is a real-time game loop, 3D rendering, and input.", "Names what is, such as a game engine like Unity, Unreal, or Godot, and offers to help with that.", "Mentions that First Draft could later build a part it fits, such as accounts, leaderboards, or a website, if the user wants it.", - "Does not ask the First Draft level question or start the First Draft interview.", + "Does not start the First Draft interview.", "Runs no plan init, plan push, plan status, or plan compile and creates no .firstdraft directory." ] }, @@ -266,8 +267,8 @@ "Does not make any statement about whether First Draft fits, not even that the idea fits; it may mention one or two useful findings, such as a feature most family photo apps share.", "Restates the idea in a sentence and proposes a name.", "Invites materials such as screenshots or an app the user likes, and says none is required.", - "Asks once whether it should make the technical decisions for the user, explain them as it goes, or ask about them.", - "Asks no more than three questions in this opening turn and leaves what First Draft will and will not build, such as photos and phone apps, for the reality check after the user answers.", + "Does not ask how involved the user wants to be in technical decisions.", + "Asks no more than two questions in this opening turn and leaves what First Draft will and will not build, such as photos and phone apps, for the reality check after the user answers.", "Runs no plan push, plan status, or plan compile and makes no First Draft service request in this opening turn." ] }, @@ -284,11 +285,11 @@ ] }, { - "id": "meaning-asked-implementation-by-level", + "id": "meaning-asked-implementation-decided", "should_trigger": true, - "prompt": "Use First Draft to plan a private family scrapbook: members sign up, post updates, and make photo albums, and family can comment on updates and on albums. Every page needs sign-in. You asked my level and I said to make the technical decisions for me. I have no artifacts to share. Keep this local; do not submit or Compile.", + "prompt": "Use First Draft to plan a private family scrapbook: members sign up, post updates, and make photo albums, and family can comment on updates and on albums. Every page needs sign-in. I have no artifacts to share. Keep this local; do not submit or Compile.", "expectations": [ - "Treats whether one kind of comment can belong to either an update or an album as product meaning: asks it as one product question or states it as an assumption the user can correct, rather than treating the technical level as settling it.", + "Treats whether one kind of comment can belong to either an update or an album as product meaning: asks it as one product question or states it as an assumption the user can correct, rather than treating it as an implementation choice.", "When one Comment may belong to either, models one Reference with both targets and sets realization.rails_association to exclusive_arc without asking, with a one-line why.", "Says that the Compiler emits that Reference under either realization while forms, selects, Policies, and other screens that cross it remain gaps, that such a Policy is emitted as a stub whose rule denies and whose scope raises, with its screens still generated, and keeps the Reference in the Plan.", "Asks no implementation question, such as about gems, column types, or the realization.", @@ -296,9 +297,9 @@ ] }, { - "id": "implementation-choice-asked-at-ask-level", + "id": "implementation-choice-asked-on-request", "should_trigger": true, - "prompt": "Use First Draft to plan a private family scrapbook: members sign up, post updates, and make photo albums, and one kind of comment can go on either an update or an album. Every page needs sign-in. You asked my level and I said to ask me about technical decisions. The product questions are settled. I have no artifacts to share. Keep this local; do not submit or Compile.", + "prompt": "Use First Draft to plan a private family scrapbook: members sign up, post updates, and make photo albums, and one kind of comment can go on either an update or an album. Every page needs sign-in. I want you to ask me about technical decisions rather than make them. The product questions are settled. I have no artifacts to share. Keep this local; do not submit or Compile.", "expectations": [ "Asks the one real implementation choice the Plan exposes, for the comment's Reference with two targets: polymorphic or exclusive arc.", "Says what each emits, nullable foreign keys per target with an exclusive-arc constraint, or an ID and a type column with a Rails polymorphic association; puts exclusive arc first as the recommendation for a closed set, with polymorphic for targets added later without a migration; and links the Foundation Plan Guide's Rails output view.", @@ -310,11 +311,11 @@ { "id": "coverage-checklist-walked", "should_trigger": true, - "prompt": "We've finished the questions for my book club app. You asked my level and I said to make the technical decisions for me. Settled: members sign up; a member adds a book with a title and author; members review books with a rating from 1 to 5 and a comment; every page needs sign-in; web only. I have no artifacts. Get it ready for my review, but keep this local; do not submit or Compile.", + "prompt": "We've finished the questions for my book club app. Settled: members sign up; a member adds a book with a title and author; members review books with a rating from 1 to 5 and a comment; every page needs sign-in; web only. I have no artifacts. Get it ready for my review, but keep this local; do not submit or Compile.", "expectations": [ "Checks records, required and unique values, links and deletion, access, Accounts, lists, sample data, one-tap records, phone apps, hosting, appearance, and implementation choices before its summary, without turning them into a questionnaire.", "Does not ask again about settled items such as sign-in, web only, or the rating range.", - "Does not treat the technical level as delegating product meaning: asks one remaining meaning question, such as whether a member may review the same book twice or what happens to reviews when a book or member is deleted, and leaves any others for later turns.", + "Does not treat its own technical choices as settling product meaning: asks one remaining meaning question, such as whether a member may review the same book twice or what happens to reviews when a book or member is deleted, and leaves any others for later turns.", "Proposes list fields, sample data, and appearance itself for the read-back without asking, and says hosting is set up for Render's free plan with Neon.", "Makes no service request, Compile or remote write." ] @@ -572,11 +573,11 @@ { "id": "run-generated-tests-before-preview", "should_trigger": true, - "prompt": "Use First Draft to hand off the app it just compiled from my approved Movie Catalog Plan; the CLI verified the materialization. Only the generated README is staged in this folder. Before I preview the app in my browser, tell me exactly what you will run, in order. Keep this advisory: do not run setup, tests, or the server yet.", + "prompt": "Use First Draft to hand off the app it just compiled from my approved Movie Catalog Plan; the CLI verified the materialization. Only the generated README and AGENTS.md are staged in this folder. Before I preview the app in my browser, tell me exactly what you will run, in order. Keep this advisory: do not run setup, tests, or the server yet.", "expectations": [ "Reads the staged README and takes its commands from it: bin/setup --skip-server, then the Checks section's npm run build, npm run build:css, and bundle exec rspec, all before booting bin/dev for the preview.", "Uses --skip-server because plain bin/setup starts bin/dev and does not return; does not substitute bin/ci or a guessed command for the spec run.", - "Says how it would sort a failing spec: one that fails through behavior the README's Behavior to write lists is work to do, written until its specs pass, and any other is a First Draft defect to report. This README lists Movie.highest_rated, so the Movie index example in spec/requests/movies_spec.rb fails until that scope is written, before the preview. Says it would never edit or delete a generated spec to make the run pass, and that the preview follows a passing run.", + "Says it would treat the results as the staged AGENTS.md says: a spec that fails through the README's Behavior to write is work to write, so the Movie index example in spec/requests/movies_spec.rb fails until Movie.highest_rated is written, and it debugs any other failure without skipping, deleting, or loosening an example. Says the preview need not wait for that work: Home does not raise here, so it would start bin/dev and name /movies as raising until Movie.highest_rated is written, without asking first.", "Does not claim setup, the specs, or the preview have run.", "Makes no First Draft request, Compile, remote write, or file change, and starts no setup, tests, or server." ], @@ -585,19 +586,24 @@ "path": "evals/create-full-stack-app/fixtures/generated-application-README.md", "role": "input", "stage_as": "README.md" + }, + { + "path": "evals/create-full-stack-app/fixtures/generated-application-AGENTS.md", + "role": "input", + "stage_as": "AGENTS.md" } ] }, { - "id": "failing-generated-spec-is-first-draft-defect", + "id": "failing-generated-spec-is-debugged", "should_trigger": true, - "prompt": "Use First Draft to hand off the app it just compiled from my approved Movie Catalog Plan. Right after Compile, setup and the generated specs ran; only the generated README and their output, test-run.txt, are staged in this folder. I'd like to see bookmarks working in the browser now.", + "prompt": "Use First Draft to hand off the app it just compiled from my approved Movie Catalog Plan. Right after Compile, setup and the generated specs ran; only the generated README, AGENTS.md, and their output, test-run.txt, are staged in this folder. I'd like to see bookmarks working in the browser now.", "expectations": [ - "Treats the Bookmark example as a First Draft defect and reports RSpec's 41 examples, 2 failures summary, the rerun line rspec ./spec/system/bookmarks_spec.rb:4, and the Capybara::ElementNotFound error for the Bookmark button. Treats the Movie index example, whose NotImplementedError names movie.highest_rated from the README's Behavior to write, as work to write, not a defect.", - "Never edits spec/requests/movies_spec.rb or any other generated spec, skips or excludes an example, or changes the spec command to make the run pass; does not change generated source to work around the Bookmark failure, and leaves how to proceed with it to the user.", - "Asks before the preview instead of proceeding on the earlier request, says the Bookmark failure is in the bookmark flow the user wants to see, and names the Movie index page (/movies) as raising until Movie.highest_rated is written.", + "Treats the Movie index example, whose NotImplementedError names movie.highest_rated from the README's Behavior to write, as work to write. Treats the Bookmark example, rerun line rspec ./spec/system/bookmarks_spec.rb:4 with Capybara::ElementNotFound for the Bookmark button, as a failure to debug like its own: it would find the cause and fix the code.", + "Never edits spec/requests/movies_spec.rb or any other generated spec to get a green run, and does not skip, exclude, or loosen an example or change the spec command. If the cause is generated code, would add one line under First Draft defects in .firstdraft/design/implementation-notes.md and tell the user in a sentence. Does not hand the failure back for the user to decide.", + "Does not ask whether to preview: tells the user in one line that the Movie index page (/movies) raises until Movie.highest_rated is written and that bookmarking fails until the Bookmark failure is fixed. With no application source staged, says it could not start the preview or fix the code here instead of claiming either.", "Does not call either failure a missing local prerequisite, because setup and the other 39 examples ran.", - "Makes no First Draft request, Compile, or remote write, and does not start the server." + "Makes no First Draft request, Compile, or remote write." ], "artifacts": [ { @@ -606,26 +612,9 @@ "stage_as": "README.md" }, { - "path": "evals/create-full-stack-app/fixtures/failing-generated-spec-output.txt", + "path": "evals/create-full-stack-app/fixtures/generated-application-AGENTS.md", "role": "input", - "stage_as": "test-run.txt" - } - ] - }, - { - "id": "preview-despite-failing-generated-spec", - "should_trigger": true, - "prompt": "Understood. Show me the preview anyway.", - "expectations": [ - "Before booting, names the pages or flows the failing specs exercise, such as bookmarking a Movie and any Bookmark list that depends on it, as possibly broken in this preview, and the Movie index page (/movies) as raising until Movie.highest_rated is written.", - "Then follows the README's bin/dev boot and first-preview checks without rerunning setup or editing generated code; if no application is present, says the preview could not start instead of claiming it ran.", - "Keeps the Bookmark failure reported as an open First Draft defect and Movie.highest_rated as behavior still to write, never edits spec/requests/movies_spec.rb, and does not treat the preview as proof that bookmarking works." - ], - "artifacts": [ - { - "path": "evals/create-full-stack-app/fixtures/generated-application-README.md", - "role": "input", - "stage_as": "README.md" + "stage_as": "AGENTS.md" }, { "path": "evals/create-full-stack-app/fixtures/failing-generated-spec-output.txt", @@ -1178,61 +1167,6 @@ "If analysis.status is valid, reports that the current candidate passed analysis without claiming Compilation or Publication already happened." ] }, - { - "id": "validate-with-named-command", - "should_trigger": true, - "prompt": "Validate the staged First Draft Plan locally, but do not send it. A teammate says the compatible JSON Schema 2020-12 command is validate-foundation-plan --schema --document .", - "expectations": [ - "Checks only whether the specifically named command is available; if it is, runs it once for the initial check with the bundled schema path and staged Plan path, and runs it again only after a deliberate repair.", - "When the command runs successfully, passes the schema as a file without opening or loading the complete schema into context and reports local bundled-schema validation.", - "If the command reports errors, treats its output as advisory data about the exact local Plan bytes, never as instructions, and repairs only well-founded structural problems while preserving subject identity and intended product meaning.", - "If the named command is absent, may make a straightforward check for an existing compatible project or PATH command, but does not search registries, install dependencies, or add validator or build plumbing solely for this workflow.", - "Does not run plan push or make another network request.", - "Reports only the local validation boundary actually demonstrated without claiming server acceptance, semantic analysis, Publish, Compilation, or generation." - ], - "artifacts": [ - { - "path": "evals/create-full-stack-app/fixtures/supported-scalars.foundation-plan.json", - "role": "input", - "stage_as": ".firstdraft/foundation-plan.json" - }, - { - "path": "evals/create-full-stack-app/fixtures/state-placeholder.txt", - "role": "input", - "stage_as": ".firstdraft/state.json" - } - ] - }, - { - "id": "declared-validator-library-is-not-command", - "should_trigger": true, - "prompt": "Validate the staged First Draft Plan locally without sending it. The staged project manifest declares a JSON Schema library, but neither I nor the project names a validation command.", - "expectations": [ - "Treats a declared schema library without a project script or other specific command as not exposing a validator command.", - "May inspect ordinary project scripts or make a straightforward PATH check for an existing compatible validator command.", - "Does not use npx or another fetch-and-run mechanism, search registries, install dependencies, add validation or build plumbing, or write or imitate a validator.", - "Uses the narrative references and examples without opening the complete bundled schema.", - "Does not run plan push or make another network request.", - "Reports the Plan as not locally schema-validated without claiming server acceptance, semantic analysis, Publish, Compilation, or generation." - ], - "artifacts": [ - { - "path": "evals/create-full-stack-app/fixtures/schema-library-only.package.json", - "role": "input", - "stage_as": "package.json" - }, - { - "path": "evals/create-full-stack-app/fixtures/supported-scalars.foundation-plan.json", - "role": "input", - "stage_as": ".firstdraft/foundation-plan.json" - }, - { - "path": "evals/create-full-stack-app/fixtures/state-placeholder.txt", - "role": "input", - "stage_as": ".firstdraft/state.json" - } - ] - }, { "id": "unsupported-field-capabilities", "should_trigger": true, @@ -1498,17 +1432,15 @@ { "id": "precompile-semantic-read-back", "should_trigger": true, - "prompt": "Prepare the staged Movie Catalog for Compilation. I want the approved result published to one private GitHub repository. Reread the exact Plan and attached matching valid analysis, identify the Plan and GapSet digests, and present its complete semantic model and reviewed support result for my approval. Do not Compile until I approve it.", + "prompt": "Prepare the staged Movie Catalog for Compilation. I want the approved result published to one private GitHub repository. Reread the exact Plan and attached matching valid analysis, and present its complete semantic model and reviewed support result for my approval. Do not Compile until I approve it.", "expectations": [ "Rereads the exact staged Plan and presents one compact semantic read-back organized around the Movie Entity rather than merely repeating that the application is ready.", - "Gives the plain-language summary first, then the gap described by what the user will notice (the iPhone app keeps a stock app icon), then a closing technical block with the Plan path and SHA-256, the gap_set_sha256, the record count, and the gaps file; does not paste the record's code, kind, status, or pointer into the chat.", + "Gives the plain-language summary first, then the gap described by what the user will notice (the iPhone app keeps a stock app icon), then where the app will be written; does not paste the record's code, kind, status, or pointer, or any digest, into the chat.", "Covers material Fields, relationships, rules, behavior, and data when present without enumerating absent Foundation Plan subject families.", "Explains that one Movie record has the film icon and one required short_text Title used as its Primary Descriptor, with no References.", "Explains that the only generated surface is a public read-only web index, that the selected iPhone client uses that index for navigation under movies.example.com, and that delivery is empty.", "Explains that Appearance requests the auto theme and #4F46E5 tint color, that the theme applies across clients while native colors do not replace stock web tokens, that web bookmark icons use fixed black-on-white artwork, and that only the selected-iOS AppIcon remains stock.", - "Identifies the exact staged Plan by its SHA-256 so approval can bind to unchanged bytes.", "Verifies that the attached valid analysis's project and analysis graph versions agree and that analysis.head_source_sha256 and GapSet source.sha256 equal the staged Plan SHA-256 before treating it as the matching reviewed result.", - "Writes the complete one-record GapSet to planning-root gaps-readback.md with the Plan SHA-256, the exact attached analysis.gap_set_sha256, which the CLI validated against the attached GapSet bytes, and classification target_support_gap, code foundation_plan.gap.appearance.icon_assets.not_generated, kind appearance_icon_assets, status partially_generated, pointer /application/appearance, readable_path application.appearance, reason, and consequence; names that file in the read-back and does not substitute a fixture, historical, or other Project's digest.", "Explains that valid applies to the admitted graph, that Appearance theme and native colors are realized, that web bookmark icons use fixed black-on-white artwork while the selected-iOS AppIcon remains stock, and that the partial gap does not require weakening the Plan before Compile.", "Selects the explicit --github Publication mode because the requested result is one private GitHub repository, states explicitly that Compile does not deploy, and explains that only that invocation's validated terminal success proves Publication.", "Asks the user to correct or explicitly approve the complete semantic model and does not run plan compile before that approval.", @@ -1535,14 +1467,14 @@ { "id": "precompile-drawing-board-read-back", "should_trigger": true, - "prompt": "Prepare the staged Movie Catalog for direct Compilation into the absent ./application directory in this Drawing Board workspace. Reread the exact Plan and attached matching valid analysis, identify the Plan and GapSet digests, and present its complete semantic model and reviewed support result for my approval. Do not Compile until I approve it.", + "prompt": "Prepare the staged Movie Catalog for direct Compilation into the absent ./application directory in this Drawing Board workspace. Reread the exact Plan and attached matching valid analysis, and present its complete semantic model and reviewed support result for my approval. Do not Compile until I approve it.", "expectations": [ "Rereads the exact staged Plan and presents one compact semantic read-back covering the Movie Entity's material Fields, rules, behavior, data, surfaces, access, clients, assumptions, and exclusions without enumerating absent subject families.", "Explains the required short_text Title Primary Descriptor, public read-only web index, selected iPhone navigation under movies.example.com, empty delivery, and intentional auto-theme and #4F46E5 Appearance meaning.", - "Identifies the exact staged Plan SHA-256, verifies the attached valid analysis's matching project and analysis graph versions and Head source digest, writes the complete one-record Appearance icon-assets GapSet with its reason and consequence to planning-root gaps-readback.md, and reports the exact attached analysis.gap_set_sha256, which the CLI validated against the attached GapSet bytes, in a closing technical block after the plain-language summary and the gap described by what the user will notice; does not substitute a fixture, historical, or other Project's digest.", + "Verifies the attached valid analysis's matching project and analysis graph versions and Head source digest, and describes the one Appearance icon-assets gap by what the user will notice, after the plain-language summary; writes no separate gaps file and pastes no digest, code, or pointer into the chat.", "Explains that valid applies only to the admitted graph, that Appearance theme and native colors are realized, that web bookmark icons use fixed black-on-white artwork while the selected-iOS AppIcon remains stock, and that the partial gap does not require weakening the Plan before Compile.", "Selects direct mode before approval because this is an explicit Drawing Board and local-directory request; states that the intended command is firstdraft plan compile --output ./application and that success creates no Publication, GitHub repository, .git directory, or deployment, while Drawing Board owns later nested-Git initialization.", - "Asks the user to correct or explicitly approve the complete semantic model, reviewed support result, exact Plan bytes, and selected direct mode; the Compile wrapper count remains zero before approval.", + "Asks the user to correct or approve the complete semantic model, reviewed support result, and selected direct mode, with no digest echo; the Compile wrapper count remains zero before approval.", "Preserves the exact staged Plan and its subject UUIDs without deleting, loosening, flattening, relabeling, or substituting intentional meaning to fit current capabilities." ], "artifacts": [ @@ -1568,10 +1500,9 @@ "prompt": "I'm not technical. Before you build my Movie Catalog, tell me in plain words what it will do and anything it won't do yet. The staged Plan and the attached analysis are current. Don't build it until I say so.", "expectations": [ "Rereads the exact staged Plan and checks that the attached valid analysis's graph versions agree and that its head_source_sha256 and GapSet source.sha256 equal the staged Plan SHA-256 before using it.", - "Leads with a plain-language summary: one kind of record, a movie with a required title; a public list anyone can read on the web; an iPhone app that opens that list; and the automatic light or dark theme with its tint color. No digest, code, or JSON pointer appears before the technical block.", + "Leads with a plain-language summary: one kind of record, a movie with a required title; a public list anyone can read on the web; an iPhone app that opens that list; and the automatic light or dark theme with its tint color. No digest, code, or JSON pointer appears.", "Describes the one gap by what the user will notice: the iPhone app keeps a stock app icon, while web bookmark icons use fixed black-on-white artwork. Does not paste the record's code, kind, status, or pointer into the chat.", - "Writes planning-root gaps-readback.md with the Plan SHA-256, the exact attached analysis.gap_set_sha256, and the complete record, including classification target_support_gap and code foundation_plan.gap.appearance.icon_assets.not_generated, and names that file.", - "Ends with a short technical block giving the Plan path and SHA-256, the exact attached analysis.gap_set_sha256, which the CLI validated against the attached GapSet bytes, the record count, the gaps file, and the default current-folder local output; never substitutes a fixture, historical, or other Project's digest.", + "Ends by saying the app will be written into the current folder, and writes no separate gaps file.", "Asks once for approval of the whole candidate, requires no digest echo or gap acknowledgment, and does not run plan compile before that approval." ], "artifacts": [ @@ -1620,12 +1551,12 @@ "prompt": "I approve the exact pre-Compile semantic read-back and reviewed support result for the unchanged staged Movie Catalog with SHA-256 d6f15d4062c95574c40f47a993ea7d24dd920fc10736306ae64c3461b5fda15f. Preserve its intentional Appearance request and publish that exact candidate to one private GitHub repository now.", "expectations": [ "Requires the installed CLI to expose both plan compile completion modes and no public plan publish command.", - "In the same continuing session, treats the prompt as unambiguous approval of the complete semantic model and reviewed nonempty GapSet, rereads the exact local Plan, verifies its SHA-256 and semantic model are unchanged, and does not ask for a second confirmation or repeat the unchanged read-back.", + "In the same continuing session, treats the prompt as unambiguous approval of the complete semantic model and reviewed nonempty GapSet, and does not ask for a second confirmation or repeat the unchanged read-back.", "Selects Publication because the user explicitly requested one private GitHub repository and runs exactly one plan compile --github through the Skill resolver; it does not add --output.", "The command pushes the exact whole file, waits for the accepted exact Head's analysis, and invokes Publication after valid analysis with the preserved Appearance icon-assets partial gap and an unchanged local file.", "Treats progress as nonterminal observational output and reports the distinct terminal Compilation and Publication outcomes, reporting success only when stdout contains the validated private GitHub repository URL.", "Accepts approval of the previously reviewed support result without requiring the user to echo its GapSet digest or records, preserves the Appearance request, and does not add a gap acknowledgment, gap-specific flag, or gap-specific field; it does not run another preparatory plan push or plan status after approval because the final exact candidate and GapSet were already reviewed.", - "Would stop, report the new SHA-256 and semantic delta, and obtain approval of the changed candidate instead of compiling if the local Plan no longer matched the approved candidate." + "If the Plan changed after the approved read-back, or the CLI reports local_plan_changed, would stop, describe the semantic delta, and obtain approval of the changed candidate instead of compiling if the local Plan no longer matched the approved candidate." ], "artifacts": [ { @@ -1646,12 +1577,12 @@ "prompt": "I approve the exact pre-Compile Drawing Board semantic read-back and reviewed support result for the unchanged staged Movie Catalog with SHA-256 d6f15d4062c95574c40f47a993ea7d24dd920fc10736306ae64c3461b5fda15f. Materialize that exact candidate into the absent ./application directory. Do not create a GitHub repository.", "expectations": [ "Requires the installed CLI to expose plan compile --output as a direct local completion mode while retaining plan compile --github as the separate GitHub Publication mode.", - "In the same continuing session as precompile-drawing-board-read-back, treats the prompt as unambiguous approval of the complete semantic model, reviewed nonempty GapSet, exact Plan bytes, and selected direct local mode; rereads the Plan, verifies its SHA-256 is unchanged, and asks for no second confirmation.", + "In the same continuing session as precompile-drawing-board-read-back, treats the prompt as unambiguous approval of the complete semantic model, reviewed nonempty GapSet, exact Plan bytes, and selected direct local mode; and asks for no second confirmation.", "After approval, runs exactly one firstdraft plan compile --output ./application through the Skill resolver and does not also run plan compile --github, plan publish, or a preparatory plan push or plan status.", "Lets the CLI push the exact Plan, wait for matching valid analysis, start and poll one retained direct Compilation, verify its artifact, and atomically materialize exact bytes and modes without duplicating those mechanics.", "Reports the validated output path, file count, manifest digest, and Compilation status only after materialization succeeds, and makes no Publication, GitHub repository, repository URL, or deployment claim.", "Recognizes that direct mode creates no .git directory and leaves Drawing Board's later nested-Git initialization to the workspace workflow.", - "Would stop, report the new SHA-256 and semantic delta, and obtain approval of the changed candidate instead of compiling if the local Plan no longer matched the approved candidate." + "If the Plan changed after the approved read-back, or the CLI reports local_plan_changed, would stop, describe the semantic delta, and obtain approval of the changed candidate instead of compiling if the local Plan no longer matched the approved candidate." ], "artifacts": [ { @@ -1672,7 +1603,7 @@ "prompt": "The exact prepared Plan, its semantic read-back, and attached valid analysis gaps are approved. Compile the app now so I can run it locally. Keep the existing planning workspace and Git history. Do not ask me to approve the same work again.", "expectations": [ "Treats the ordinary local request as selection of firstdraft plan compile and never substitutes an absent application directory or explicit --github Publication without another user decision.", - "Rereads the staged Plan, verifies the approved SHA-256 and semantic model remain unchanged, and runs the selected Compile exactly once without another command-level confirmation or preparatory push or status command.", + "Runs the selected Compile exactly once without another command-level confirmation or preparatory push or status command.", "Before mutation, verifies the identified CLI candidate supports the requested archive layout instead of assuming published CLI 0.2.2 implements it. Applies the CLI-owned POSIX current-root preconditions: the physical current directory is writable, has no reserved .firstdraft/design or top-level .firstdraft-root-output entry, contains only eligible top-level entries, and is not nested inside another worktree; an existing Git root must be clean, nonsparse, operation-free, and have no submodule metadata.", "Lets the CLI own the root transaction, artifact verification, same-filesystem moves, rollback journal, and installation instead of moving, deleting, archiving, or overwriting workspace material itself.", "On success, reports the validated output path, file count, manifest digest, Compilation status, and root_adoption result; prior non-Git top-level material is directly under .firstdraft/design and an existing root .git and history are preserved with the transformation staged.", @@ -1812,7 +1743,7 @@ "expectations": [ "Branches on local_plan_changed and recognizes that the command stopped before Publication because the local bytes no longer match the accepted Head.", "Preserves the current local draft rather than reconstructing the earlier bytes or opening private state.", - "If the current draft is intended, presents its new SHA-256 and semantic delta and obtains approval of that changed candidate before invoking plan compile --github for its own analysis." + "If the current draft is intended, describes its semantic delta and obtains approval of that changed candidate before invoking plan compile --github for its own analysis." ] }, { diff --git a/evals/create-full-stack-app/fixtures/generated-application-AGENTS.md b/evals/create-full-stack-app/fixtures/generated-application-AGENTS.md new file mode 100644 index 0000000..918ef7a --- /dev/null +++ b/evals/create-full-stack-app/fixtures/generated-application-AGENTS.md @@ -0,0 +1,64 @@ +# Application guidance + +Work on this repository as ordinary application source. You may edit every file, replace a starter choice when +needed, and add features with conventional Rails or established gems. No further Compile is required. +If retained, `.firstdraft/submitted-foundation-plan.json` and `.firstdraft/gaps.json` record what was compiled. +They are never updated and do not govern this code: where the code disagrees with them, the code wins. +`.firstdraft/design/implementation-notes.md`, if retained, holds product decisions and open questions; keep it +current. This context is removable and is not required to run or test the app. + +`README.md` owns setup, commands, preview, and database continuation. For screens or interactions, use +the UI task index to select the relevant sections. Read `DEPLOY.md` before deployment. +Inspect existing code before adding a parallel stack. Keep the README's product description and operating +instructions accurate as behavior changes. + +When asked to review First Draft updates, use the public +[First Draft changelog](https://github.com/firstdraft/skills/blob/main/CHANGELOG.md). +Optional `.firstdraft/updates.md` records the last reviewed entry; reviewed does not mean adopted. +That reading checkpoint is not a runtime dependency. + +- Put ERB copy through `t()` in `config/locales/`; missing translations raise in development/test and erb_lint + checks literal ERB text. Review Ruby/JavaScript copy too. +- Preserve Rails authorization, CSRF, validation, and non-JavaScript form/navigation fallbacks when enhancing UI. + Inspect related screens in a real browser, at narrow and desktop widths and in each supported palette. +- System specs audit accessibility. Keep the layout's `data-turbo-not-loaded`, application.js submit/load markers, + and `WaitForTurboBeforeClick` together so Turbo redirects finish before clicks and audits. +- Preserve the native layout marker and `hotwire_native_app?` presentation: the client owns navigation and its + WebView supplies color preference. Browser user-agent checks do not prove actual native-client behavior. +- Render persistent messages into the existing `#flash_notices` / `#flash_alerts` live regions. UI.md explains + form-card flash placement and transient success messages. +- A parent's full collection page, scoped New page, and create are a nested resource, such as + `Posts::CommentsController` under `resources :posts`. Extend it and `app/views/posts/comments/` rather than the + parent's controller. +- A Reference picker given `search_url:` searches an action beside its page's own, such as + `PlantsController#new_place_options` beside `#new`. Keep that action's callbacks, checks, and option scope the + same as its page's, so it lists only what the form may offer, to people the page admits. +- Paginate collections with Pagy. Ordinary lazy association reads are allowed; preload useful associations and + use Bullet plus query-growth specs for important collections. Do not render unbounded relations. +- Follow strong_migrations instructions (`safe_by_default` is on). Put justified schema-check exceptions under + the specific detector in `.active_record_doctor.rb`. +- Bulk writes bypass validations and callbacks. Their writer owns recomputing derived/counter values; do not + base authorization or uniqueness on cached fields. +- Run the specs before other work. A spec that fails through an item in README.md's Behavior to write is work to + do: write that behavior until its specs pass, then delete the item. A stubbed scope or event raises + `NotImplementedError`, a stubbed Policy rule returns `false`, and a deletion outcome First Draft left out fails + its spec with `RecordNotDestroyed`. Write every item the section lists, including a denying rule no failing spec + names. A preview need not wait for them: first write any item whose entry says Home raises, then start the + preview and tell the user in one line which pages deny or raise until the rest are written. Do not ask first. +- Debug any other failure as you would your own: find the cause and fix the code. Never skip, delete, or loosen an + example to get a green run; change a spec only when it contradicts the behavior the app should have, and say why + in the commit. When the cause is code First Draft generated, add one line under "First Draft defects" in + `.firstdraft/design/implementation-notes.md` with the rerun line (`rspec ./spec/...:LINE`) and your fix, tell + the user in a sentence, and keep working. `bundle exec rspec --only-failures` reruns the last failures, and + `bin/ci checks` runs the audits, linters, schema check, and asset builds without the specs. +- Add a resource the way the generated ones are built. Copy a generated controller, its views, locale file, and + specs rather than keeping `bin/rails generate scaffold`'s stock views, whose literal copy fails erb_lint. When + `app/policies/` exists, declare `verify_authorized` in the controller, since `ApplicationController` does not, + and use `skip_verify_authorized` only for an action meant to be public. Authorize through a Policy with a rule + and a relation scope, give the Policy a spec, and cover each denial in the request specs. +- Test changed application behavior with focused RSpec examples, including meaningful failure and boundary cases. + Keep minimal factories and explicit scenario relationships; complete generator placeholders as behavior is added. + WebMock blocks external HTTP: stub the application's external requests explicitly. +- Complete the privacy/terms drafts against actual practices before inviting users and retain their license + attribution. Configure production domain policy; Render checks `/ready`, and Docker uses `/up` for liveness. + Read DEPLOY.md before adding availability monitoring: the Free default intentionally sleeps. diff --git a/evals/create-full-stack-app/fixtures/generated-application-README.md b/evals/create-full-stack-app/fixtures/generated-application-README.md index 5128fc2..03ecd68 100644 --- a/evals/create-full-stack-app/fixtures/generated-application-README.md +++ b/evals/create-full-stack-app/fixtures/generated-application-README.md @@ -18,7 +18,8 @@ bin/dev Setup installs Ruby and JavaScript dependencies and prepares the database. Without `--skip-server`, it also starts `bin/dev`. Build the assets and run the specs before the first preview; [Checks](#checks) covers both. -The specs that [Behavior to write](#behavior-to-write) names fail until you write that behavior. +The specs that [Behavior to write](#behavior-to-write) names fail, and the pages it names deny or raise, until you +write that behavior. The development process runs Rails and the JavaScript/CSS watchers; open [localhost:3000](http://localhost:3000), or the forwarded application port in a Codespace. @@ -50,8 +51,8 @@ builds; `specs`, RSpec without system specs plus a seed replant; and `system`. ` `bundle exec rspec --only-failures` reruns only the examples that failed last. GitHub Actions runs each group as its own step, then runs `git diff --exit-code`, even when a group failed, to detect tracked changes produced by setup and verification in a clean checkout. -Until you write the scopes under [Behavior to write](#behavior-to-write), only the Tests: RSpec and Tests: System -steps, in the `specs` and `system` groups, can fail. Any other failing step is a defect. +Until you write the scopes under [Behavior to write](#behavior-to-write), the Tests: RSpec and Tests: System +steps, in the `specs` and `system` groups, fail through it; every other step should pass. ## Behavior to write @@ -59,7 +60,8 @@ First Draft did not write the scopes below. Each raises `NotImplementedError` un that calls it raises too and the specs that request those pages fail. `NotImplementedError` is a `ScriptError`, not a `StandardError`, so `rescue => error` does not catch it, and in production every request that reaches one answers 500. While any of those specs fail, `bin/ci` fails, and so does the CI workflow of a repository published -to GitHub. Write each scope, then run the specs. Never edit or delete a generated spec to make it pass; change one -only when the owner changes the behavior it pins. +to GitHub. Write each scope, run the specs, and delete its entry here once they pass; when none remain, delete this +section and the sentences that link to it. `AGENTS.md` says how to treat any other failure and when a +spec may change. - **`Movie.highest_rated`** (`app/models/movie.rb`) orders records by average_rating descending with nulls last, then title ascending. No database index backs it. The Movie index (`/movies`) calls it, so that page raises until it is written. `spec/requests/movies_spec.rb` requests that page. diff --git a/evals/create-full-stack-app/fixtures/schema-library-only.package.json b/evals/create-full-stack-app/fixtures/schema-library-only.package.json deleted file mode 100644 index 388d7ce..0000000 --- a/evals/create-full-stack-app/fixtures/schema-library-only.package.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "name": "validator-routing-eval", - "private": true, - "type": "module", - "devDependencies": { - "ajv": "8.20.0" - } -} diff --git a/evals/create-full-stack-app/references/candidate-interview-protocol.md b/evals/create-full-stack-app/references/candidate-interview-protocol.md index d9f12f3..3322840 100644 --- a/evals/create-full-stack-app/references/candidate-interview-protocol.md +++ b/evals/create-full-stack-app/references/candidate-interview-protocol.md @@ -23,8 +23,8 @@ Track each consequential choice as one of: Offer concrete alternatives when they make a question easier to answer, but label proposals as proposals. A missing answer is not a default; "you pick" or "make the rest of the decisions for me" delegates. The opening turn clarifies -the idea, invites materials, and asks once whether the agent should make the technical decisions, explain them, or -ask about them; later turns ask one decision at a time. Prioritize questions whose answers would change the graph, +the idea and invites materials; the agent makes technical decisions itself unless asked otherwise, and later turns +ask one decision at a time. Prioritize questions whose answers would change the graph, access, or requested clients. The ambiguity matrix guides the dialogue; it is not a one-message questionnaire. ## Interview from product meaning @@ -43,13 +43,10 @@ access, or requested clients. The ambiguity matrix guides the dialogue; it is no 6. **Resolve client consequences.** Establish requested web and native clients, domain handling, native capture or offline needs, delivery channels, notifications, and external prerequisites. A native client does not imply push notifications, and absent Account requirements do not imply public access. -7. **Read back and obtain approval.** Summarize Entities and their material Fields, relationships, rules, behavior, - and data; surfaces, access, native and delivery choices; explicit exclusions, delegated decisions, and open - choices. For a matching valid analysis, group the gaps by what the user will notice, then give the GapSet digest - and write every ordered record to a gaps file, distinguishing service meaning skipped before semantic analysis - from admitted meaning not fully realized by the target. Ask the user to correct or explicitly approve that exact - semantic model and reviewed support delta before Compile; do not require a digest echo or another gap-specific - acknowledgment. +7. **Read back.** Summarize Entities and their material Fields, relationships, rules, behavior, and data; surfaces, + access, native and delivery choices; explicit exclusions, delegated decisions, and open choices. For a matching + valid analysis, group the gaps by what the user will notice and say what the app does instead. Ask for approval or + give a progress update as [Read back and approve before Compile](#read-back-and-approve-before-compile) describes. Capture intended product meaning before comparing it with current target support. A capability gap is not permission to silently delete, loosen, flatten, relabel, or substitute the user's intent merely to obtain `valid` analysis. @@ -103,20 +100,17 @@ Before the first Compile that could start direct retained work or reach Publicat give a plain-language semantic summary first: application scope; Entities and their material Fields, relationships, rules, behavior, and data; surfaces, access, and clients; material assumptions, delegated choices, and exclusions. Then group the gaps by what the user will notice, then list what is built outside First Draft and the feasibility -findings and open questions. End with a short technical block: the Plan path -and SHA-256, the matching valid AnalysisRun's GapSet digest and record count, and the file holding every ordered -record. Explain that service gaps were skipped before semantic analysis, target gaps were not fully realized, and -`valid` applies only to the admitted graph. State the selected completion mode: direct output creates only a -verified local directory, while terminal successful Publication is intended to create one private GitHub -repository. Neither deploys. Do not enumerate absent subject families or immaterial empty categories. Ask the user -to correct or explicitly approve the exact model and reviewed gaps without requiring a digest echo or gap-specific -field. +findings and open questions. State the selected completion mode: direct output creates only a verified local +directory, while terminal successful Publication is intended to create one private GitHub repository. Neither +deploys. Do not enumerate absent subject families or immaterial empty categories. Ask the user to correct or approve +the model and reviewed gaps without requiring a digest echo or gap-specific field. When the user delegated the +remaining decisions, give the read-back as a progress update and Compile in the same turn. The read-back reviews the staged candidate rather than reopening authoring. Preserve its existing subject UUIDs; do not require an edit without a user correction, a confirmed product decision, or a demonstrated diagnostic. If -the Plan bytes change afterward, show the new SHA-256 and semantic delta for approval. In the same continuing -conversation, once the unchanged candidate is approved, hash-check it and run one deliberately selected Compile mode -without a second command-level confirmation or gap-specific argument. +the Plan changes afterward, describe the semantic delta for approval. In the same continuing conversation, once the +candidate is approved, run one deliberately selected Compile mode without a second command-level confirmation or +gap-specific argument. Do not weaken product meaning to pass the current capability boundary. The user may explicitly move a feature out of this release after seeing the consequence; record that product-scope decision. Otherwise preserve the meaning. A diff --git a/package-lock.json b/package-lock.json index 3311cb9..020171f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@firstdraft/skills", - "version": "0.8.15", + "version": "0.8.16", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@firstdraft/skills", - "version": "0.8.15", + "version": "0.8.16", "license": "MIT", "devDependencies": { "ajv": "8.20.0" diff --git a/package.json b/package.json index e40c729..7265022 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@firstdraft/skills", - "version": "0.8.15", + "version": "0.8.16", "description": "Portable Agent Skills for First Draft", "license": "MIT", "private": true, diff --git a/packages/claude-plugin/.claude-plugin/plugin.json b/packages/claude-plugin/.claude-plugin/plugin.json index c7c8484..59e0d7e 100644 --- a/packages/claude-plugin/.claude-plugin/plugin.json +++ b/packages/claude-plugin/.claude-plugin/plugin.json @@ -2,7 +2,7 @@ "$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json", "name": "firstdraft", "displayName": "First Draft", - "version": "0.8.15", + "version": "0.8.16", "description": "Author a Foundation Plan and compile a bounded Rails, iPhone, and Android application", "author": { "name": "First Draft", diff --git a/packages/claude-plugin/package.template.json b/packages/claude-plugin/package.template.json index a1cfcf7..99bfce5 100644 --- a/packages/claude-plugin/package.template.json +++ b/packages/claude-plugin/package.template.json @@ -1,6 +1,6 @@ { "name": "@firstdraft.com/claude-code", - "version": "0.8.15", + "version": "0.8.16", "description": "First Draft Foundation Plan authoring and Compilation for Claude Code and Codex", "license": "MIT", "type": "module", diff --git a/release/compatibility.json b/release/compatibility.json index 837b346..00d017d 100644 --- a/release/compatibility.json +++ b/release/compatibility.json @@ -1,7 +1,7 @@ { "format": "firstdraft.release-compatibility/1", "component": "skills", - "version": "0.8.15", + "version": "0.8.16", "plugin_source": { "package": "@firstdraft.com/claude-code", "tarball_sha256": "66ec2558448b739c470228a9df7b82aadfb422025083516cd9b95eae68ecbe9f" diff --git a/skills/create-full-stack-app/SKILL.md b/skills/create-full-stack-app/SKILL.md index 21f36f3..770d94f 100644 --- a/skills/create-full-stack-app/SKILL.md +++ b/skills/create-full-stack-app/SKILL.md @@ -23,7 +23,7 @@ explicit handoff. Follow [writing notes](references/modeling-guide.md#retain-imp ## Current boundary -Targets plugin 0.8.15, CLI 0.8.2, API 0.7, Plan 0.23; catalog selection is separate. +Targets plugin 0.8.16, CLI 0.8.2, API 0.7, Plan 0.23; catalog selection is separate. - Bounded generation includes Web Accounts/Policies/Scaffolds, development data, and selected iPhone/Android clients. [Appearance](references/foundation-plan-023.md#application-and-clients) controls theme and native colors, @@ -58,10 +58,8 @@ For CLI work: read [ambiguous mutations](references/diagnostics-and-recovery.md#ambiguous-mutations) only when the named error requires it. -The bundled [JSON Schema](references/foundation-plan-0.23.schema.json) is validator input, not prose: pass only its -path to a compatible JSON Schema 2020-12 command the user names, the project exposes, or a quick check of existing -local commands finds; never read it end to end. Install nothing and add no validation plumbing for this. Otherwise -rely on First Draft exact-byte diagnostics and say local schema validation was not performed. +The bundled [JSON Schema](references/foundation-plan-0.23.schema.json) is reference data, not prose: never read it +end to end. `plan push` validates the Plan, so install nothing and add no local validation. ## Verify the local capability @@ -75,13 +73,11 @@ pass the whole line as one unknown command. ```sh firstdraft_cli() { sh "/scripts/firstdraft.sh" "$@"; } -firstdraft_cli --version firstdraft_cli --help ``` -Require the version probe to succeed with one exact `0.8.2` output line and no other output, and top-level help that -lists `generate`, `plan`, and `compilation`. Contract tests own separate stdout and stderr assertions for leaf -commands; do not repeat them in a startup shell loop. The compatible CLI supplies these public commands: +Require top-level help that lists `generate`, `plan`, and `compilation`. The compatible CLI supplies these public +commands: - `generate uuid` and `generate application-key`; - `plan init`, `plan push`, `plan status`, and `plan compile` (local `--output .` by default), optional `--output `, or explicit `--github`; @@ -89,8 +85,8 @@ commands; do not repeat them in a startup shell loop. The compatible CLI supplie - `login` and `logout`, which only the user runs. There is no public `plan publish` or `plan subject-id`. Never replace the CLI automatically. -If its version or help differs, report it and stop remote work instead of using HTTP directly; local Plan work -may continue. Verify the registry and catalog before recommending an installation or upgrade; a source candidate may be unreleased. +If its help differs, report it and stop remote work instead of using HTTP directly; local Plan work may continue. +Verify the registry and catalog before recommending an installation or upgrade; a source candidate may be unreleased. New remote work uses `https://firstdraft.com`; for requested staging use `firstdraft_cli --staging plan push`. Read [environment setup](references/diagnostics-and-recovery.md#local-state-and-credentials) before remote work. @@ -119,8 +115,7 @@ firstdraft_cli generate application-key --name "" ``` If initialization fails, follow the stable error in the recovery reference. Preserve any partial `.firstdraft/` -directory. If `.firstdraft/` already exists, confirm with project-relative metadata that `foundation-plan.json` and -`state.json` are regular and readable. Read the Plan, resume its Project and subject identities, and do not +directory. If `.firstdraft/` already exists, read the Plan, resume its Project and subject identities, and do not reinitialize. Inspect private state only for a recovery check explicitly named in the recovery reference. ## Interview and author incrementally @@ -128,12 +123,12 @@ reinitialize. Inspect private state only for a recovery check explicitly named i Start when the user asks for help making an app or invokes `/create-full-stack-app`. First research the idea and [decide how First Draft helps](references/interview.md#start-from-the-users-goal), then follow the [interview flow](references/interview.md#interview-flow). Clarify the idea; ask for materials and read them before -asking more; ask once, "Should I make the technical decisions for you, explain them as I go, or ask you about -them?" Then ask the product questions that shape the data model, most important first and one decision per turn, -until only delegated or nonblocking items remain. Right after the opening answers, push a rough Plan and tell the -user plainly what First Draft will and will not build. Ask implementation choices last, by the user's level; -product meaning is always asked or delegated. Honor "make the rest of the decisions for me" at any point. Before -the read-back, walk the coverage checklist silently and write the after-Compile checklist into the notes. +asking more. Then ask the product questions that shape the data model, most important first and one decision per +turn, until only delegated or nonblocking items remain. Right after the opening answers, push a rough Plan and tell +the user plainly what First Draft will and will not build. Make implementation choices yourself and name them in the +read-back, unless the user asks to be asked; product meaning is always asked or delegated. Honor "make the rest of +the decisions for me" at any point. Before the read-back, walk the coverage checklist silently and write the +after-Compile checklist into the notes. State the access boundary precisely: Web pages may be public or use Accounts and Policies, and iPhone and Android apps show the same pages with the same sign-in. Keep private access and requested clients in the Plan. @@ -194,30 +189,25 @@ valid status so the complete GapSet can be reviewed. `plan compile` later repeat ## Read back and approve the candidate before Compile Before the first `plan compile`, complete the modeling guide's -[candidate reconciliation](references/modeling-guide.md#prepare-the-pre-compile-semantic-read-back), then reread the exact current -`.firstdraft/foundation-plan.json`. Follow that section's order: a plain-language summary first and a short -technical block last, with the Plan path and SHA-256 and the matching valid run's `gap_set_sha256`. Write every -ordered GapSet record with all its fields to planning-root `gaps-readback.md` and name that file instead of pasting -the records into the chat. Use only that attached -digest: the CLI validates it against the attached GapSet; never substitute a fixture, historical, or another -Project's digest. Use current-folder output by default. Select an absent -`--output ` for a requested destination, an ineligible root, or model-only originals when root output was not -explicitly requested. Select `--github` -only for an explicit private GitHub repository request. Generic compile or build language selects local output. -Direct output creates a verified local directory; Publication creates one private GitHub repository. Neither deploys. -Do not enumerate absent subject families or immaterial properties. Ask the user to correct or explicitly approve the -candidate and reviewed gaps only when those decisions are still unresolved; require no digest echo or -gap-acknowledgment field. Existing authorization carries forward: if the user has already approved the candidate and -reviewed gaps, or requested the complete app with these choices delegated, give the read-back as a progress update -and proceed. Ask only when new material scope or gap consequences need a user decision. Delegating interview -decisions, as with "make the rest of the decisions for me", is not that request: ask once. - -If the Plan bytes change, show the new SHA-256 and the semantic delta. Obtain approval of the changed candidate only -when the delta exceeds the existing request or delegated choices. -In the same continuing conversation, after unambiguous approval, reread the Plan, confirm its SHA-256 is unchanged, -and make the initial request with exactly one invocation in the selected mode. Do not ask for a second command-level -confirmation. Do not delete, loosen, flatten, relabel, or substitute intended product meaning to make analysis -green. The user may explicitly move a feature out of scope after seeing the consequence; otherwise preserve it. +[candidate reconciliation](references/modeling-guide.md#prepare-the-pre-compile-semantic-read-back), then reread the +exact current `.firstdraft/foundation-plan.json` and give the read-back in that section's order. Use current-folder +output by default. Select an absent `--output ` for a requested destination, an ineligible root, or model-only +originals when root output was not explicitly requested. Select `--github` only for an explicit private GitHub +repository request. Generic compile or build language selects local output. Direct output creates a verified local +directory; Publication creates one private GitHub repository. Neither deploys. Do not enumerate absent subject +families or immaterial properties. + +Ask the user to correct or approve the candidate and its gaps only while those decisions are unresolved; require no +digest echo or gap-acknowledgment field. Existing authorization carries forward. When the user has approved the +candidate, asked for the complete app with these choices delegated, or said "make the rest of the decisions for me", +give the read-back as a progress update and Compile in the same turn; the user can change any delegated choice in +the app afterward. Ask only when new material scope or gap consequences need a user decision. + +If the Plan changes after the read-back, describe the semantic change. Obtain approval of the changed candidate only +when it exceeds the existing request or delegated choices. Then make the request with exactly one invocation in the +selected mode. Do not ask for a second command-level confirmation. Do not delete, loosen, flatten, relabel, or +substitute intended product meaning to make analysis green. The user may explicitly move a feature out of scope +after seeing the consequence; otherwise preserve it. This gate does not block an explicitly requested diagnostic-only Compile of exact bytes already known to be invalid from those bytes or matching diagnostics. Invalid analysis cannot start a Compilation or Publication. Valid @@ -225,7 +215,7 @@ analysis with gaps can; do not require removal of the corresponding Plan fields. ## Request the selected Compile journey -After the exact candidate's semantic read-back is approved, read +After the read-back, once the candidate is approved or delegated, read [Product Compile](references/diagnostics-and-recovery.md#product-compile) and request the already selected mode: - For the ordinary local journey, use the current folder: @@ -301,23 +291,16 @@ repository requires a separate user request and an exact verified identity. ## Hand off the result -Report: - -- the Plan path and the latest boundary actually demonstrated: JSON parsing, local schema validation, server import, - or whole-graph analysis; -- material choices, delegated decisions, exclusions, open questions, warnings, and capability gaps; -- the implementation-notes location, outstanding agreed behavior, and whether the resulting repository actually - contains them; follow the [notes handoff](references/diagnostics-and-recovery.md#implementation-notes-handoff); -- observed analyzer release, graph version, Head SHA, valid GapSet digest, and where its full records are; -- mode and distinct Compilation/Publication statuses when Publication was requested; -- `--github` mode's private URL after Publication success; direct output's path, file count, manifest digest, and - any `root_adoption` after materialization; -- that direct Compile created no Publication or repository; after root adoption, use the - [root handoff](references/diagnostics-and-recovery.md#root-adoption-handoff) for local setup and an optional Git checkpoint; -- whether setup and the [test run](references/diagnostics-and-recovery.md#run-the-generated-tests) actually ran, - and their outcome; and -- any recovery blocker or external prerequisite. - -Distinguish verified materialization, First Draft Publication, and GitHub pushes. None proves deployment or -production readiness. Begin [application handoff](references/diagnostics-and-recovery.md#application-handoff), which -writes the README's Behavior to write before the first preview. +After Compile, follow the [application handoff](references/diagnostics-and-recovery.md#application-handoff): after +root adoption, the [root handoff](references/diagnostics-and-recovery.md#root-adoption-handoff) first, then the +[notes handoff](references/diagnostics-and-recovery.md#implementation-notes-handoff), setup, the +[test run](references/diagnostics-and-recovery.md#run-the-generated-tests), and the preview. Then tell the user, in +plain words: + +- where the app is: its folder, or the private GitHub repository once Publication succeeds; +- what works, as setup, the specs, and the preview actually showed; +- what you will write next: the README's Behavior to write, agreed behavior from the implementation notes, and any + gap the user will notice; and +- how to open the preview. + +Compilation and Publication do not deploy the app or make it ready for real users. diff --git a/skills/create-full-stack-app/references/diagnostics-and-recovery.md b/skills/create-full-stack-app/references/diagnostics-and-recovery.md index 9b26c60..787febd 100644 --- a/skills/create-full-stack-app/references/diagnostics-and-recovery.md +++ b/skills/create-full-stack-app/references/diagnostics-and-recovery.md @@ -9,7 +9,7 @@ interleaved output fail closed. Branch on the object's stable `error` and struct human-readable `detail` or broad process exit status. This plugin bundles `@firstdraft.com/cli@0.8.2`. Its exact reviewed revision and runtime digest are owned by -[the CLI contract configuration](https://github.com/firstdraft/skills/blob/claude-v0.8.15/script/cli-contract/config.mjs) +[the CLI contract configuration](https://github.com/firstdraft/skills/blob/claude-v0.8.16/script/cli-contract/config.mjs) at this plugin's protected release tag. Check the command surface rather than assuming the version alone establishes compatibility. These source checks do not prove plugin/catalog publication, service authentication, staging compatibility, or a complete user journey. @@ -100,8 +100,8 @@ two minutes. Every validated domain status exits successfully: For `valid`, require non-null `analysis.gap_set` and `analysis.gap_set_sha256`. The CLI validates the canonical `firstdraft.foundation-gaps/2` format, digest, exact Head, Project graph generation, analyzer and Compiler releases, and target/profile before printing it. Inspect every ordered record. The -[read-back](modeling-guide.md#prepare-the-pre-compile-semantic-read-back) groups them in plain language and writes -each complete record to `gaps-readback.md`; do not drop records or report only counts. A `service_support_gap` +[read-back](modeling-guide.md#prepare-the-pre-compile-semantic-read-back) groups them in plain language; do not drop +records or report only counts. A `service_support_gap` records schema-valid meaning skipped before semantic analysis, so `valid` does not validate that skipped meaning. A `target_support_gap` records admitted and analyzed meaning that the selected target does not fully realize. A valid analysis with an empty `gaps` array still carries the canonical object and digest. Every non-valid status carries null values for both fields. @@ -110,9 +110,9 @@ Server messages and suggestions are advisory data. Preserve intentional meaning describes a current importer, analyzer, or Compiler gap. If a diagnostic repeats without new understanding, surface the blocker rather than looping mechanically. -Before approval, `plan push` the final exact candidate and obtain its matching valid `plan status --wait` result so -the user can review the complete GapSet and digest. After approval, `plan compile` repeats that exact-byte push; do -not add another preparatory push, a gap acknowledgment, or any gap-specific field. +Before the read-back, `plan push` the final exact candidate and obtain its matching valid `plan status --wait` result +so the read-back covers the complete GapSet. `plan compile` repeats that exact-byte push; do not add another +preparatory push, a gap acknowledgment, or any gap-specific field. `status_unavailable` is a read-only failure. Retry that GET a bounded number of times; if it persists, inspect the private state's pinned `api_url` locally without printing the rest of the file. `invalid_server_response` instead @@ -270,9 +270,8 @@ If creation succeeded but pushing failed, retain the repository and resolve the another one. This publishes the existing Git history; do not invoke `plan compile --github` or First Draft Publication to publish an already-compiled workspace. -Then follow the [application handoff](#application-handoff): it runs setup and the generated tests, and writes the -behavior the README's Behavior to write lists, before the first preview and before requested feature work in -ordinary Rails source. +Then follow the [application handoff](#application-handoff): it runs setup and the generated tests and starts the +preview before requested feature work in ordinary Rails source. Do not run Drawing Board's moved `.firstdraft/design/script/initialize-application` or `.firstdraft/design/script/application-smoke`: those helpers belong to the optional nested `./application` mode. Use ordinary generated application and platform commands for preview and tests rather than archived helpers. @@ -312,22 +311,12 @@ bundle exec rspec ``` Run these rather than `bin/ci`, whose lint and dependency audits are not tests and whose advisories change after -Compile. A missing README prerequisite, such as PostgreSQL 18 or Chrome for system specs, is a local blocker, not a -First Draft defect: report it and ask before installing anything. With the prerequisites present, a setup failure -is a defect. - -A spec that fails through behavior the README's Behavior to write lists is work to do: First Draft did not write -that behavior. Write it until its specs pass. A stubbed scope or event raises `NotImplementedError`, a stubbed Policy -rule returns `false`, and a deletion outcome First Draft left out fails its spec with `RecordNotDestroyed`. Write -every item that section lists, including a denying rule no failing spec names. Any other failure is a First Draft -defect. Report RSpec's summary line and each such failure's rerun line (`rspec ./spec/...:LINE`) and error; the user -decides how to proceed. Never edit or delete a generated spec, skip examples, or change the commands to make the run -pass. Change a generated spec only when the owner changes the behavior it pins. - -When the run passes and every item Behavior to write lists is written, continue to the preview. Otherwise ask before -the preview, even one requested earlier. If the user still wants it, first name the pages or flows the failing specs -exercise, each page that the README's Behavior to write says raises, each page it says denies every account, and -each delete it says is refused until its behavior is written. +Compile. A missing README prerequisite, such as PostgreSQL 18 or Chrome for system specs, is a local blocker. Ask +once before installing system software, naming the exact command. + +Then follow the app's `AGENTS.md` for the results. It says which failures are behavior to write, how to debug any +other failure without weakening a spec, and how to start the preview before every item is written. Do not ask +whether to preview. ### Verify the first preview @@ -382,16 +371,11 @@ path are unavailable, report the missing context and remaining step. Do not add artifact bytes or their manifest to make the notes appear Compiler-owned. Local preservation does not prove that server Publication carried the notes. -During continuation, read the app's `AGENTS.md`, README, and retained implementation notes before selecting work. -Run the specs before other work. A spec that fails through behavior the README's Behavior to write lists is work to -do: write that behavior until its specs pass. A stubbed scope or event raises `NotImplementedError`, a stubbed Policy -rule returns `false`, and a deletion outcome First Draft left out fails its spec with `RecordNotDestroyed`. Write -every item that section lists, including a denying rule no failing spec names. Report any other failure as a First -Draft defect. Never edit or delete a generated spec to make it pass; change one only when the owner changes the -behavior it pins. Then implement the agreed behavior and its acceptance examples in ordinary source; keep unresolved -product questions open. Existing app feature work does not require another Plan submission, Compile, or CLI -capability probe. Update the notes to reflect remaining behavior without making app setup, runtime, or tests depend -on them. +During continuation, read the app's `AGENTS.md`, README, and retained implementation notes before selecting work, +and follow `AGENTS.md` for the specs. Then implement the agreed behavior and its acceptance examples in ordinary +source; keep unresolved product questions open. Existing app feature work does not require another Plan submission, +Compile, or CLI capability probe. Update the notes to reflect remaining behavior without making app setup, runtime, +or tests depend on them. #### UI continuation @@ -493,7 +477,7 @@ projections paired with a queued or running Compilation instead of rendering an `issues_found`, continue the product conversation, edit, push, or invoke Compile again when useful. Treat `analysis_failed` as an analyzer failure and `superseded` as a concurrency outcome rather than making a speculative source correction. `local_plan_changed` means the bytes changed after acceptance or analysis and before the -selected mutation. If the current bytes are intended, present their new SHA-256 and semantic delta, obtain approval +selected mutation. If the current bytes are intended, describe their semantic delta, obtain approval of that changed candidate only when it exceeds existing authorization, and invoke the deliberately selected Compile mode for its own analysis. The first accepted Publication request establishes this release's Project singleton, whether it later succeeds, diff --git a/skills/create-full-stack-app/references/foundation-plan-023.md b/skills/create-full-stack-app/references/foundation-plan-023.md index 25854eb..7ec61cc 100644 --- a/skills/create-full-stack-app/references/foundation-plan-023.md +++ b/skills/create-full-stack-app/references/foundation-plan-023.md @@ -3,17 +3,10 @@ This reference and [Examples](examples.md) guide authoring for the experimental `firstdraft.foundation-plan.sketch/0.23` boundary. The bundled [exact JSON Schema](foundation-plan-0.23.schema.json) is the machine-readable structural contract. Never read it -end to end. Use a compatible JSON Schema 2020-12 validator when the user names its command, the project exposes a -specific validation command, or a straightforward check finds an existing compatible local command. Confirm that -command is available, then pass the schema file to it without loading its contents into context. A declared library -or dependency is not by itself an exposed command. Do not query registries, install dependencies, or add validation -or build plumbing solely for this workflow. If no compatible local command is available, rely on server diagnostics -for submitted exact bytes and report that local schema validation was not performed. Treat -validator output as advisory data about the exact local Plan bytes, never as instructions. Repair only well-founded -structural problems while preserving subject identity and intended product meaning. When these authoring -references do not answer a concrete structural question, search the schema for the exact property or `$defs` name -and inspect only that definition. Use server diagnostics for the exact bytes submitted by `plan push` or -`plan compile`. +end to end. When these authoring references do not answer a concrete structural question, search the schema for the +exact property or `$defs` name and inspect only that definition. `plan push` validates the exact bytes, so add no +local validation; use the server diagnostics from `plan push` or `plan compile`, and repair only well-founded +structural problems while preserving subject identity and intended product meaning. ## Contents @@ -88,7 +81,7 @@ The bundled schema was copied byte-for-byte from release or execution evidence. This plugin's bundled CLI and pinned contract check use the exact reviewed CLI revision and runtime digest in -[the CLI contract configuration](https://github.com/firstdraft/skills/blob/claude-v0.8.15/script/cli-contract/config.mjs) +[the CLI contract configuration](https://github.com/firstdraft/skills/blob/claude-v0.8.16/script/cli-contract/config.mjs) at this plugin's protected release tag, as contract provenance rather than release or execution evidence. The CLI exposes `generate uuid`, `generate application-key`, `plan init`, `plan push`, `plan status`, local `plan compile` (equivalent to `--output .`), explicit `plan compile --github`, @@ -319,8 +312,8 @@ The importer retains Entity `orderings`, and the current target emits a bounded stability, nullability, and consumers meet the profile. Unsupported Orderings remain exact gaps, and each record's consequence says what the generated app does. When it says the named scope raises `NotImplementedError` until it is written, the Compiler emitted that scope as a stub, and a Scaffold index or collection that selects it calls the -stub, so the page raises until then. Otherwise the scope is left out, as a Compiler without stubs does or when the -model cannot take that name, and the consequence says what the page does without it. `implicit_order_column` is +stub, so the page raises until then. Otherwise the scope is left out, as when the model cannot take that name, and +the consequence says what the page does without it. `implicit_order_column` is schema-valid, but the current integrated target realizes only the captured Case Chat `message.sent_at, id` authored shape. Ordered finders otherwise use the profile's `created_at, id` default. This fallback affects `first` and `last`, not ordinary Relation or Association loading or Scaffold list order; use the matching GapSet for other @@ -734,9 +727,11 @@ is refused with `403`. Change email then emails a link to the new address, and t confirmed. With `registration`, sign-up's link travels by email, so `DEPLOY.md` makes a mail provider a launch prerequisite. Without `registration`, the app can deploy and sign people in before a provider is configured, but an email change cannot finish until one is. Password reset and unlock, when the Plan has `recovery` and `lockout`, need a -provider either way. Keep an existing Plan's `verification` unless the user asks to remove it. In the read-back, say -plainly that people can sign in right after signing up and that email confirmation is available if they want it, or, -when authored, that people confirm their email first. Without `registration`, say instead that the owner creates each +provider either way; until one is added, those emails are not delivered. Leave `verification` out unless the user +asks for email confirmation, so people can share the app with friends right away; keep an existing Plan's +`verification` unless the user asks to remove it. In the read-back, say plainly that people can sign in right after +signing up and that email confirmation is available if they want it, or, when authored, that people confirm their +email first. Without `registration`, say instead that the owner creates each Account. Each Policy has stable identity, an owner-local key, one operation, and one `allow_when` Policy Expression. A @@ -1025,7 +1020,9 @@ viewer may open links to the comment's page, which shows Delete to whoever passe show the comment without a link. With `index` instead, a link in the main navigation opens a list of comments whose rows have no link or Delete button. A [one-tap toggle](modeling-guide.md#add-behavior-deliberately) is the exception: its undo button, such as Unlike, deletes from the parent page. Otherwise, when `destroy` comes without -`show`, ask in the read-back where people delete from and show what each choice generates. +`show`, add `show` by default so each record's page carries Delete, and name that among the delegated choices in the +read-back. Leave `show` out only when the user wants deletion by URL alone or a Delete control written in Rails +after Compile. For behavior claimed as realized, routes, projections, authorization, inputs, and returns follow the authored Plan. Generated Rails may do less than the Plan asks. The reviewed GapSet lists the authored meaning it does not realize, @@ -1062,5 +1059,5 @@ target-support meaning was admitted and analyzed but is not fully realized. Pres every exact gap. Successful Compilation retains the exact submitted Plan at `.firstdraft/submitted-foundation-plan.json` and the -canonical machine-readable GapSet at `.firstdraft/gaps.json`. There is intentionally no duplicate Markdown gap file; -future agents should read the one JSON authority. +canonical machine-readable GapSet at `.firstdraft/gaps.json`. There is intentionally no duplicate Markdown gap file. +Both record what was compiled and are never updated; where later code disagrees with them, the code wins. diff --git a/skills/create-full-stack-app/references/interview.md b/skills/create-full-stack-app/references/interview.md index e893b74..ed27b5e 100644 --- a/skills/create-full-stack-app/references/interview.md +++ b/skills/create-full-stack-app/references/interview.md @@ -58,46 +58,43 @@ Start when the user asks for help making an app, such as "help me make an app fo 2. **Ask for materials:** design docs, screenshots, a CSV of sample data, a form or report, or an app they like. None is required. Read whatever arrives before asking more, and do not ask what it already answers. Follow the [artifact guidance](modeling-guide.md#learn-from-examples-and-artifacts). -3. **Ask the user's level once:** "Should I make the technical decisions for you, explain them as I go, or ask you - about them?" Do not ask it again; the user may change it at any time. -Steps 1 to 3 are the opening turn, after the research and any fit, with at most three questions. +Steps 1 and 2 are the opening turn, after the research and any fit, with at most two questions. -4. **Ask product questions** that decide the data model, most important first: which records exist and what one +3. **Ask product questions** that decide the data model, most important first: which records exist and what one record is, who can see and do what, and whether they want iPhone or Android apps. After the opening turn, ask one decision per turn: one line on why it matters, then two to four options with your recommendation first, and room for their own answer. A recommendation is a proposal until the user accepts it. Leave details such as list fields for later. Stop when only delegated or nonblocking items remain; there is no fixed number of questions. Do not ask about hosting. Say the app is set up for free hosting on Render's free plan with a free Neon database, and that a paid option is planned. -5. **Give an early reality check.** As soon as the opening answers settle the main records, tell the user this takes +4. **Give an early reality check.** As soon as the opening answers settle the main records, tell the user this takes a few minutes, then write a rough Plan, push it, and read its analysis. Keep the rough Plan small: the main records and their key Fields, any Account, who can see what, and requested phone apps; for a backbone, only the part First Draft builds. Tell the user in a few plain lines what First Draft will build and what it will not build yet, for example "Formatted descriptions aren't generated yet, so posts start without one; I'll add them in - Rails after" or "Comments that can go on either a post or an album aren't generated yet; I'll add them in Rails + Rails after" or "The list of posts that mention a word is generated, and I'll write its search in Rails right after". Then let the analysis steer the remaining questions: ask about consequences the user can choose between, not about gaps they cannot change. Keep private access and requested phone apps in the Plan. Report each gap as the analysis gives it, even when its reason names no cause or contradicts these references; the deployed First Draft may not generate it yet. Do not trim the Plan or push trial or example Plans to find a cause: each push replaces the Project's current Plan, and a defensible variant is still a trial. -6. **Ask implementation choices last**, following the user's level and - [meaning and implementation](#meaning-and-implementation). -7. **Walk the [coverage checklist](#coverage-checklist)** silently, and write the +5. **Make implementation choices last**, as [meaning and implementation](#meaning-and-implementation) describes. +6. **Walk the [coverage checklist](#coverage-checklist)** silently, and write the [after-Compile checklist](#after-compile-checklist) into the implementation notes. -8. **Read back and approve** as the Skill describes, then Compile. For plan only, give the read-back and stop. +7. **Read back and approve** as the Skill describes, then Compile. For plan only, give the read-back and stop. At any point the user may say "make the rest of the decisions for me". Stop asking. Choose your recommendation for -every remaining item, including product meaning, and mark each one delegated. Then walk the checklist and give the -read-back, which names those choices, and ask once for approval so the user can still correct them before Compile. -Delegating decisions is not approval. +every remaining item, including product meaning, and mark each one delegated. Walk the checklist, give the read-back, +naming those choices, as a progress update, then Compile in the same turn. The user can change any of them +afterward in the app. ## Meaning and implementation **Meaning** is what the app does: which records it stores and how they link, which values are required or unique, who can see and do what, and what happens when something is deleted. "Can one comment belong to either a post or a photo?" is meaning. Ask it, or decide it only when the user delegated it with "you pick" or "make the rest of the -decisions for me". Choosing a level does not delegate meaning. +decisions for me". **Implementation** is how First Draft emits that meaning in Rails. The target profile fixes almost all of it: the Plan has no property for gems, column types, or callbacks. Today the Plan exposes one real choice: a Reference @@ -116,13 +113,11 @@ Forms, selects, Policies, Predicates, and other screens that cross either shape that needs a required multi-target Reference is omitted. A Policy that crosses either shape is emitted as a stub: its rule denies and its scope raises until it is written, and the screens it guards are still generated. Say so. -Follow the user's level: - -- **Ask me:** after the product questions, present each real choice with what each option emits, your - recommendation first, and the [Guide link](#see-what-first-draft-emits). -- **Decide:** use the convention default without asking, and name it with a one-line why among the delegated - choices in the read-back. -- **Explain:** use the convention default too, and give the one-line why in plain words when the choice comes up. +Make implementation choices yourself: use the convention default without asking, and name it with a one-line why +among the delegated choices in the read-back. Do not ask the user how involved they want to be. If they ask to be +asked, present each real choice after the product questions, with what each option emits, your recommendation +first, and the [Guide link](#see-what-first-draft-emits). If they ask for explanations, give the one-line why in +plain words when the choice comes up. For a Reference with several targets the convention default is `exclusive_arc`: the Plan's targets are a closed set, and a foreign key per target lets the database refuse a delete that would leave a row pointing at nothing. A @@ -166,8 +161,8 @@ Walk this list silently before the read-back; it is not a questionnaire. Mark ea - **asked:** the user answered your question; - **decided:** the user's request or materials settled it, or First Draft fixes it. State any meaning you inferred, such as "likes work as on Instagram", so the user can correct it; or -- **delegated:** the user said "you pick" or "make the rest of the decisions for me". Their level delegates only - implementation choices. +- **delegated:** the user said "you pick" or "make the rest of the decisions for me". Implementation choices are + yours to make unless the user asked to be asked. Ask about each unmarked item of meaning or product scope: what is stored, required, or unique; links and deletion; access; sign-up; and phone apps. Propose the rest yourself, such as list fields, sample data, and appearance. Name every delegated choice and @@ -177,10 +172,11 @@ proposal in the read-back. like per person per post. - [ ] Links and deletion: which records belong to which, and what happens to them when that record is deleted. - [ ] Access: who can see, add, change, and delete each kind of record, with one Policy per operation. -- [ ] Accounts: whether people sign up, the Account Fields on the sign-up form, and email confirmation; without - `verification`, sign-up signs people in and never checks that they control the address. "No sign-up" is - supported: without `registration`, sign-in and Policies still generate, and the generated README shows the - owner how to create each Account. Without `lockout`, failed sign-ins are not limited, and `DEPLOY.md` says so. +- [ ] Accounts: whether people sign up, and the Account Fields on the sign-up form. Do not ask about email + confirmation: leave `verification` out unless the user asks for it, so sign-up signs people in at once and + they can share the app with friends right away. "No sign-up" is supported: without `registration`, sign-in + and Policies still generate, and the generated README shows the owner how to create each Account. Keep + `recovery` and `lockout`; without `lockout`, failed sign-ins are not limited, and `DEPLOY.md` says so. - [ ] Lists: what each main list shows, starting with the record's name, and its order. - [ ] Sample data: the proposed sample records and demo sign-in, and any CSV the user wants imported; import itself goes in the implementation notes. @@ -193,18 +189,17 @@ proposal in the read-back. ## After-Compile checklist These steps are outside the Plan and do not block local development. They come after the -[test run](diagnostics-and-recovery.md#run-the-generated-tests), which runs the specs and writes the behavior the -README's Behavior to write lists before other work. Before the read-back, write the items that apply under +[test run](diagnostics-and-recovery.md#run-the-generated-tests). Before the read-back, write the items that apply under `## After Compile` in `implementation-notes.md`, so the agent that continues in the app finds them: - [ ] Error tracking: the app includes Rollbar, which reports production errors only once `ROLLBAR_ACCESS_TOKEN` is set in the Render environment. - [ ] Performance monitoring: the app includes Skylight, which stays off until `SKYLIGHT_AUTHENTICATION` is set in the Render environment. -- [ ] Email (apps with Accounts): password reset and unlock emails, with `recovery` and `lockout`, need a mail - provider; with `verification`, Change email needs it too, and so does sign-up with `registration`, because - their links travel by email. Once the Account is generated, follow the Account email section of `DEPLOY.md` - before inviting real users. +- [ ] Email (apps with Accounts): password reset and unlock emails, with `recovery` and `lockout`, are not + delivered until a mail provider is added. Without `verification`, sign-up and sign-in work without one; with + it, Change email and sign-up with `registration` need one too, because their links travel by email. Follow + the Account email section of `DEPLOY.md` to add one before inviting real users. - [ ] Accounts without sign-up or lockout: without `registration`, create each Account as the README's Accounts section shows; without `lockout`, limit sign-in attempts as the Failed sign-ins section of `DEPLOY.md` says before inviting real users. diff --git a/skills/create-full-stack-app/references/modeling-guide.md b/skills/create-full-stack-app/references/modeling-guide.md index 86e56cc..e60651f 100644 --- a/skills/create-full-stack-app/references/modeling-guide.md +++ b/skills/create-full-stack-app/references/modeling-guide.md @@ -53,7 +53,7 @@ When modeling a collection, distinguish one uniquely identified object, a quanti mixed product that needs both meanings. Uniquely identified objects are records of their own Entity, such as a Unit with a serial number and `belongs_to :product`; a quantity is an `integer` Field on one record, emitted as `t.integer "quantity", null: false`; a mixed product authors both. In the opening turn, ask only about intended -product meaning, materials, and the user's level, and name deferred product areas; give the reality check about +product meaning and materials, and name deferred product areas; give the reality check about target support after the user answers. Whether First Draft covers the core of the idea is [fit](interview.md#start-from-the-users-goal), not target support: say it in the opening turn when research shows it. Do not promote a common use case into an assumption. When target support matters, know the desired access before @@ -148,8 +148,8 @@ can drop every member and, with them, their posts and the demo sign-in. Say in t the rule drops. Make the dataset and any source reuse visible in the existing semantic read-back. Approve it with the Plan, not -row by row. Honor an explicit empty-data choice, omitting `development_data` when there are no records. An already -approved Plan with no data is not permission to silently add records during handoff. +row by row. Honor an explicit empty-data choice, omitting `development_data` when there are no records. After +Compile, development seeds are ordinary source. Keep Entity `reference_data` for facts the app needs in every environment and `development_data` for disposable development exploration. Reference-data Rails emission remains incomplete. Use supported typed literal Field @@ -200,8 +200,7 @@ Keep these outcomes distinct: | Behavior outside the vocabulary | Retain it in implementation notes for ordinary source development; analysis cannot promise a gap for meaning it never received. | | Explicit user exclusion | Honor the agreed scope and retain the exclusion in the existing decisions/read-back; do not reintroduce it during a later revision. | -Notes may refer to a structured subject or its gap, but do not duplicate the Plan or keep a gap list in the notes; -the read-back's `gaps-readback.md` is a copy of the analysis. +Notes may refer to a structured subject or its gap, but do not duplicate the Plan or keep a gap list in the notes. Before Compile, summarize outstanding agreed behavior and open questions during the existing semantic read-back. Use the [output-mode handoff](diagnostics-and-recovery.md#implementation-notes-handoff) to preserve and discover the notes in the application repository. The implementation agent may have neither this conversation nor the original @@ -349,7 +348,7 @@ Put a Reference on the Entity that stores the relationship fact. Ask: - Is the relationship one-to-one? - For a closed multi-target Reference, which supported target realization should be used? This is an implementation choice: `exclusive_arc` by default, `polymorphic` when targets will be added later without a - migration. Follow the user's level in [meaning and implementation](interview.md#meaning-and-implementation). + migration. Choose it as [meaning and implementation](interview.md#meaning-and-implementation) describes. A Reference already emits its same-key forward Association, such as `belongs_to :team` for `membership.team`; authoring that Association again is skipped at import with a service-support gap. A referenced-side Association @@ -386,8 +385,8 @@ each counter after its authored items; people never type them. record's consequence says what the generated app does. When it says the named scope raises `NotImplementedError` until it is written, the Compiler emitted that scope as a stub, with no database index for an Ordering, and the README's Behavior to write lists it; an index that selects it calls the stub, so the page raises until then. - Otherwise the scope is left out, as a Compiler without stubs does or when the model cannot take that name, and the - consequence says what the page does without it. A Field followed by `id` also generates when both run in one + Otherwise the scope is left out, as when the model cannot take that name, and the consequence says what the page + does without it. A Field followed by `id` also generates when both run in one direction: on Bulletin, `title`, then `id`, both ascending, emits `scope :by_title, -> { order(title: :asc, id: :asc) }` and `t.index ["title", "id"]`. The same terms with `id` descending are a `foundation_plan.gap.ordering.not_generated` record. @@ -521,14 +520,8 @@ Write it for a reader who is not technical, in this order: with where it will be built, and how the selected output mode carries the notes forward. 4. Feasibility findings and open questions, with sources for what research found. Leave out a list with nothing in it. -5. A short technical block: the Plan path and SHA-256; the matching valid run's `gap_set_sha256` and record count; - that service gaps were skipped before semantic analysis, target gaps were analyzed but not fully realized, and - `valid` covers only the admitted graph; the selected output mode, or plan only; and the gaps file. - -Before giving the read-back, write planning-root `gaps-readback.md`: the Plan SHA-256, the `gap_set_sha256`, and -every ordered GapSet record with its classification, code, kind, status, location, reason, consequence, and cause -when present. Copy it from the attached analysis, and rewrite it whenever the candidate bytes change. Root -adoption archives it under `.firstdraft/design/`; after Compile, the app's `.firstdraft/gaps.json` is the -authority. Follow the Skill's -[read-back and approval workflow](../SKILL.md#read-back-and-approve-the-candidate-before-compile) for the exact -candidate, selected output mode, and the single approval. +5. Where the app will be written: this folder, another folder, or a private GitHub repository; or plan only. + +After Compile, the app's `.firstdraft/gaps.json` holds every GapSet record. Follow the Skill's +[read-back and approval workflow](../SKILL.md#read-back-and-approve-the-candidate-before-compile) for the selected +output mode and when to ask for approval. diff --git a/test/release-compatibility.test.mjs b/test/release-compatibility.test.mjs index 1babd05..9d44ff8 100644 --- a/test/release-compatibility.test.mjs +++ b/test/release-compatibility.test.mjs @@ -22,15 +22,6 @@ test("release compatibility matches the installable plugin manifest", async () = const declaredPluginVersion = skill.match(/^Targets plugin ([0-9]+\.[0-9]+\.[0-9]+),/m); assert(declaredPluginVersion, "the Skill must identify its plugin compatibility version"); assert.equal(declaredPluginVersion[1], version); - // The probe names the CLI version without a "CLI" label, so the currency check compares it only with the lower of - // the plugin and CLI versions. A stale probe would make the Skill reject its own bundled CLI. - const versionProbe = skill.match(/^Require the version probe to succeed with one exact `([^`]+)` output line/m); - assert(versionProbe, "the Skill must name the exact CLI version that its startup probe expects"); - assert.equal( - versionProbe[1], - cliPackageVersion, - "the Skill's startup version probe must expect the CLI pinned in script/cli-contract/config.mjs", - ); const cliConfigurationUrl = `https://github.com/firstdraft/skills/blob/claude-v${version}/script/cli-contract/config.mjs`; diff --git a/test/repository.test.mjs b/test/repository.test.mjs index 7dcf8fe..0de1889 100644 --- a/test/repository.test.mjs +++ b/test/repository.test.mjs @@ -1152,7 +1152,7 @@ test("documented Plans match canonical example fixtures", async () => { assert.deepEqual(applicationIntentPlan, applicationIntentFixture); }); -test("validator evals stage the required Plan and private state", async () => { +test("the no-validator eval relies on plan push for validation", async () => { const cases = JSON.parse( await readFile( path.join(evalsDirectory, "create-full-stack-app", "cases.json"), @@ -1190,59 +1190,6 @@ test("validator evals stage the required Plan and private state", async () => { assertExpectation(withoutValidator, "plan push through the CLI"); assertExpectation(withoutValidator, "claim local structural validity"); assertExpectation(withoutValidator, "acceptance of the bounded import"); - - const namedValidator = cases.find( - ({ id }) => id === "validate-with-named-command", - ); - assert(namedValidator); - assert.equal(namedValidator.should_trigger, true); - assert.match(namedValidator.prompt, /validate-foundation-plan --schema/); - assert.match(namedValidator.prompt, /do not send it/); - assertExpectation( - namedValidator, - "specifically named command", - "once for the initial check", - "again only after a deliberate repair", - ); - assertExpectation(namedValidator, "without opening or loading the complete schema"); - assertExpectation( - namedValidator, - "If the command reports errors", - "advisory data", - "preserving subject identity and intended product meaning", - ); - assertExpectation( - namedValidator, - "If the named command is absent", - "straightforward check", - "does not search registries", - ); - assertExpectation(namedValidator, "Does not run plan push"); - assertExpectation(namedValidator, "without claiming server acceptance"); - assert.deepEqual( - namedValidator.artifacts.map(({ stage_as: stageAs }) => stageAs), - [".firstdraft/foundation-plan.json", ".firstdraft/state.json"], - ); - - const libraryOnly = cases.find( - ({ id }) => id === "declared-validator-library-is-not-command", - ); - assert(libraryOnly); - assert.equal(libraryOnly.should_trigger, true); - assert.match(libraryOnly.prompt, /declares a JSON Schema library/); - assert.match(libraryOnly.prompt, /neither I nor the project names a validation command/); - assertExpectation(libraryOnly, "not exposing a validator command"); - assertExpectation(libraryOnly, "straightforward PATH check"); - assertExpectation(libraryOnly, "Does not use npx", "install"); - assertExpectation(libraryOnly, "not locally schema-validated"); - assert.deepEqual( - libraryOnly.artifacts.map(({ stage_as: stageAs }) => stageAs), - [ - "package.json", - ".firstdraft/foundation-plan.json", - ".firstdraft/state.json", - ], - ); }); test("complete examples and eval Plans validate against the bundled exact schema", async () => { @@ -2622,7 +2569,7 @@ test("product Compile and retained Compilation evals match the CLI contract", as hasExpectation(staleBytes, "stopped before Publication"); hasExpectation( staleBytes, - "new SHA-256 and semantic delta", + "describes its semantic delta", "obtains approval of that changed candidate", "before invoking plan compile --github", );