{"v":[{"id":943,"html_url":"https:\/\/www-s01.apinet.com\/codeforge\/apiintl\/hhmanager\/issues\/127#issuecomment-943","pull_request_url":"","issue_url":"https:\/\/www-s01.apinet.com\/codeforge\/apiintl\/hhmanager\/issues\/127","user":{"id":1,"login":"charles","login_name":"","source_id":0,"full_name":"Charles Willgren","email":"charles@noreply.www-s01.apinet.com","avatar_url":"https:\/\/www-s01.apinet.com\/codeforge\/avatars\/d3c894f7297c5a18eb3f6ac837c335b11a00aa9cc0961323771632b1e2d61bb2","html_url":"https:\/\/www-s01.apinet.com\/codeforge\/charles","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2025-12-08T10:03:41-06:00","restricted":false,"active":false,"prohibit_login":false,"location":"","pronouns":"","website":"","description":"","visibility":"public","followers_count":0,"following_count":0,"starred_repos_count":0,"username":"charles"},"original_author":"","original_author_id":0,"body":"**Built (2026-10-05), not yet committed.**\n\n`scripts\/form-v2-pipeline.php --interview=SOC_AO_V2` (or `--packet=SOC_AO`) runs the whole chain:\n\n- **Import.** The packet's form definitions, placements and signing lines go through the existing importers. The interview comes from `docs\/form-v2-interviews\/`. The import is idempotent: a file that already matches the draft or the published version writes nothing. An interview draft edited on screen is not overwritten unless `--replace` is given.\n- **Publish.** `form_v2_pipeline_run()` publishes the definitions, then the maps, then the interview (through the editor's gate), then a release (`SOC_AO-20261005`, numbered if the code is taken). All of it is one transaction, using the screens' own publishers. It commits only if nothing was refused and the #130 check passes on the release it produced.\n- **Modes.** The default is a dry run: the chain runs and is rolled back, so the output is the actual release rather than a prediction. `--import` writes drafts only. `--apply --as=EMAIL` publishes.\n- **Activation.** `--activate=9,10` activates afterwards. It is refused on production (see #128).\n- **Idempotent.** If the content is the same as the last release, no new release is made.\n\nReview page: `\/admin\/form-v2-publish` (see #130).\n\nTwo limits:\n- The placement proposer reads the *published* definition. A form that gains a new field therefore needs its definition published before its placement can be proposed. The pipeline refuses this case and names it; it does not guess.\n- Packets are not imported or published by the chain. They keep `import-form-packets.php --publish`.\n\nAlso fixed: `form-publish.php` judged a later form's map against the *old* definition when it published several forms in one run, because of a per-request cache.","assets":[],"created_at":"2026-10-05T10:06:03-05:00","updated_at":"2026-10-05T10:06:03-05:00"},{"id":948,"html_url":"https:\/\/www-s01.apinet.com\/codeforge\/apiintl\/hhmanager\/issues\/127#issuecomment-948","pull_request_url":"","issue_url":"https:\/\/www-s01.apinet.com\/codeforge\/apiintl\/hhmanager\/issues\/127","user":{"id":1,"login":"charles","login_name":"","source_id":0,"full_name":"Charles Willgren","email":"charles@noreply.www-s01.apinet.com","avatar_url":"https:\/\/www-s01.apinet.com\/codeforge\/avatars\/d3c894f7297c5a18eb3f6ac837c335b11a00aa9cc0961323771632b1e2d61bb2","html_url":"https:\/\/www-s01.apinet.com\/codeforge\/charles","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2025-12-08T10:03:41-06:00","restricted":false,"active":false,"prohibit_login":false,"location":"","pronouns":"","website":"","description":"","visibility":"public","followers_count":0,"following_count":0,"starred_repos_count":0,"username":"charles"},"original_author":"","original_author_id":0,"body":"**Update: the \"new field\" limitation is gone.**\n\nThe placement and signing-line proposers now read the definition *about to be* published: each form's newest draft wherever it differs from the published version. `--published` restores the old reading.\n\nSo a field added to a form gets its boxes in the same `--import`, and the one-button publish carries the form and its placement together. Publishing still judges each map against the definition published at that moment, which in the pipeline is the one it has just published.\n\nProved on dev:\n- I added a tick box to a draft of *Things Your Attendant May Not Do*.\n- One rehearsal published the definition (\"New field\") and the map (\"Now printed\").\n- The check refused only because the interview didn't ask the new field yet, which is correct.\n\nThe test drafts were removed afterwards. The regression is pinned in `test-form-v2-pipeline-state.php`, which now has 24 checks.","assets":[],"created_at":"2026-10-05T10:12:28-05:00","updated_at":"2026-10-05T10:12:28-05:00"},{"id":1020,"html_url":"https:\/\/www-s01.apinet.com\/codeforge\/apiintl\/hhmanager\/issues\/127#issuecomment-1020","pull_request_url":"","issue_url":"https:\/\/www-s01.apinet.com\/codeforge\/apiintl\/hhmanager\/issues\/127","user":{"id":1,"login":"charles","login_name":"","source_id":0,"full_name":"Charles Willgren","email":"charles@noreply.www-s01.apinet.com","avatar_url":"https:\/\/www-s01.apinet.com\/codeforge\/avatars\/d3c894f7297c5a18eb3f6ac837c335b11a00aa9cc0961323771632b1e2d61bb2","html_url":"https:\/\/www-s01.apinet.com\/codeforge\/charles","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2025-12-08T10:03:41-06:00","restricted":false,"active":false,"prohibit_login":false,"location":"","pronouns":"","website":"","description":"","visibility":"public","followers_count":0,"following_count":0,"starred_repos_count":0,"username":"charles"},"original_author":"","original_author_id":0,"body":"**Closing \u2014 committed and verified (2026-10-05).**\n\nThe pipeline is on `main` (`ef52232`, `745cfee`, `3bbf2db`): `scripts\/form-v2-pipeline.php`, `code\/form_v2_pipeline.inc.php`, `\/admin\/form-v2-publish`, and `scripts\/test-form-v2-pipeline-state.php` (25 passed, 0 failed).\n\nChecked against the issue:\n- **import \u2192 validate \u2192 publish \u2192 release \u2192 (activate):** one command, one transaction. Activation is refused on production and is #128's.\n- **Dry run by default, `--apply` to write:** yes. The dry run is a rehearsal that gets rolled back.\n- **Idempotent:** an unchanged file writes nothing, and unchanged content makes no new release.\n- **Same checks as the screens, refusals printed:** it uses the screens' own publishers and the #130 check.\n- **Interview publish, release assembly, single command:** all built.\n\nStill outside the chain, on purpose: packets (`import-form-packets.php --publish`).","assets":[],"created_at":"2026-10-05T15:41:54-05:00","updated_at":"2026-10-05T15:41:54-05:00"}]}