publish-npm stages instead of publishing; a maintainer approves each version with 2FA (nxf 6j6v.c7dd) - #2
Merged
Conversation
…version with 2FA (nxf 6j6v.c7dd) The first release from the public repo failed only at npm: a trusted publisher created since 2026-09-03 is stage-only by default, and the job ran `npm publish`, so npm answered 403 "OIDC permission denied for this action" after the token exchange and the provenance had worked. Follow npm's way instead of ticking direct publish: `npm stage publish` (npm >= 11.15.0) puts the version on npm unavailable to the public, and only a maintainer's 2FA approval makes it live. No CI run can put a package in front of npx users on its own. The job summary carries the approval steps. The runbook in release-management.md §12 item 9 now covers the allowed-actions setting, the repo binding and the approval. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NhwrYjEtdnS3jCneb57X3k
This was referenced Sep 26, 2026
Merged
cabcookie
added a commit
that referenced
this pull request
Oct 2, 2026
A re-ship with no user impact: since v0.200.0 only CI and the changelog feed changed (#2-#6). It is the first release through staged npm publishing (6j6v.c7dd) and the first tag whose promote.yml opens the stable feed PR (#3). Claude-Session: https://claude.ai/code/session_018Sipejn8YQhKgngxeHpMhT Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
cabcookie
added a commit
that referenced
this pull request
Oct 3, 2026
…p knows the old phrases (nxf 6j6v.jfgy) - sweep-retired-vocabulary.sh lists the four retired phrases of the old notice, each on its own, with the supersession reason (Code Quality #1). - The facade test now pins the shape as well as the volume: the notice leads with `Parents: <ids>` and carries no second sentence after the ids, where an imperative could sit. Mutation-checked: "… Read them first" turns it red (Test Quality #3). - The CLI tests share one PARENTS_NOTICE_LEAD: the positive test asserts it is present, the negative tests that it is absent, so a rewording cannot leave them checking for a string nobody prints (Test Quality #4). - Two doc comments no longer call the notice "verbatim" (Code Quality #2). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018Sipejn8YQhKgngxeHpMhT
cabcookie
added a commit
that referenced
this pull request
Oct 3, 2026
… order (nxf 6j6v.jfgy) (#11) * nxf show points at an item's parents in a neutral line, not an urgent order (nxf 6j6v.jfgy) The parents_notice said "URGENT RECOMMENDATION: ALSO READ THESE ITEMS TO GET THE COMPLETE PICTURE!!!". Downstream, two independent agent roles flagged it as a possible prompt injection in the ticket data, and agents learned to skim the urgent line at the end of board output, which blunts them against a real one (reported upstream from the agents project, 6gfd.cpw4). It now reads "Parents: <ids> (read for full context)", in the human output and in the --json / facade field alike; the field's name and when it appears are unchanged. This supersedes the verbatim wording 6j6v.zvd0 specified. A facade test pins the principle itself: no exclamation mark, no word in capitals. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018Sipejn8YQhKgngxeHpMhT * Mitigate the review of PR #11: the notice's shape is pinned, the sweep knows the old phrases (nxf 6j6v.jfgy) - sweep-retired-vocabulary.sh lists the four retired phrases of the old notice, each on its own, with the supersession reason (Code Quality #1). - The facade test now pins the shape as well as the volume: the notice leads with `Parents: <ids>` and carries no second sentence after the ids, where an imperative could sit. Mutation-checked: "… Read them first" turns it red (Test Quality #3). - The CLI tests share one PARENTS_NOTICE_LEAD: the positive test asserts it is present, the negative tests that it is absent, so a rewording cannot leave them checking for a string nobody prints (Test Quality #4). - Two doc comments no longer call the notice "verbatim" (Code Quality #2). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018Sipejn8YQhKgngxeHpMhT --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
cabcookie
added a commit
that referenced
this pull request
Oct 4, 2026
…ly policy reads, named revoked-trust cause, group stop - A build reads a user-level folder only under a NAMED development instance, never the production one, and an unresolvable home or instance means no folder rather than an error (Code #2, #3; Integrity #3, #4). Guard test: a build under the production instance does not see personas planted in the production folder. - An existing but unreadable user-level folder is an error, not a silence (Integrity #5). - `threads show`, `search`, `Engine::thread` and `Engine::search` read the merged channels only (`merged_channels`), so a malformed persona file cannot make a thread unreadable (Code #1). - `nxc prime`, `Engine::prime_as` and `nxs prime --persona` resolve the catalogue once (`prime_with`) (Code #5). - The revoked-trust cancel fires only on an answer not yet served, so a question delivered before the revocation does not cancel; two negative controls, mutation-checked (Test #1, Integrity #7). - A stuck peer handover runs in its own process group, which is killed as a whole and then reaped by polling; the sidecar it started has a group of its own and survives; start-idempotence rests on the admission claim (Code #7, Integrity #6). Test drops the wall-clock assertion and gates `true` on unix (Test #3, #4). - The freeze test now edits a user-level hurdle too (Code #6); loader failing cases for channels, a missing and an unreadable folder, a dangling member (Test #2). - A user-level `external` admits only from workspaces the running repository trusts — tested through the binary and written in the guide (Integrity #2); the guide no longer calls a hiding "never silent" but says where it is shown (Integrity #1, the lock question filed as 6j6v.3mgy). - Stale prose and wraps (Code #4, #9). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018Sipejn8YQhKgngxeHpMhT
cabcookie
added a commit
that referenced
this pull request
Oct 4, 2026
…s (nxf 6j6v.7k58, 6j6v.dcpd) (#17) * One persona definition for every repository: a user-level declaration folder, merged per name (nxf 6j6v.7k58) Beside a workspace's own `.nxs-personas/`, every workspace reads the user-level folder `<service home>/personas` — `~/.nexusflow/personas` for the installed suite and an embedding app, `~/.nexusflow-<name>/personas` for a development build. A persona or channel the repository declares hides the user-level one of the same name; everything else is added. - The merge lives in `Definitions::resolve` alone, so the CLI, every `Engine` verb, `nxs prime` and a spawned persona's own `nxc` see one team. Duplicates are judged per folder (naming it); handle form and flow cycles on the merged team. - `DeclarationSource` carries `user_path`, `from_user` and `shadowed`, all off the wire when there is no user-level declaration, so such a machine reads exactly as before (point 8). - `nxc list` / `Engine::directory` stamp `origin: user` per entry and print the account whenever the user-level folder takes part; `nxs prime` says it under "Declarations". - A user-level persona's session start says where its declaration lives: a relative path in a prompt means the repository the session runs in, never the declaration's folder. - The freeze projects the merged catalogue, so it holds for user-level hurdles and prompts; proved by an edit mid-operation. - The readers that loaded the folder directly (thread/search channel policy, list, prime) go through the merged catalogue now. Proved through the real binary: two repositories without a pm file both run the user-level pm, the commission scenario runs on it, a repository file hides it out loud; the live test with real sessions now uses one user-level pm for both repositories (22 s, green). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018Sipejn8YQhKgngxeHpMhT * Border follow-ups from the review of PR #14: revoked trust is named, a stuck handover is stopped, the cooperative depth is written down (nxf 6j6v.dcpd) 1. When the caller's workspace stops trusting the receiver while a border thread is open, the receiver's newest message is unvouched and steers nothing. The caller's coordinator now cancels at once with "the answer arrived from <peer>, a workspace no longer trusted here" and wakes the commissioner, instead of "no sign of life" two hours later. 2. The depth across the border rests on the trusted coordinator's stamp — within the trust model (spec section 4); said where `external` and the depth guard are documented. 3. A peer handover past HANDOVER_WAIT is killed and reaped, so the long-lived service no longer accumulates stuck children. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018Sipejn8YQhKgngxeHpMhT * Pin the in-process home through pinned_home_env, and mark the dcpd fragment's facade impact The two single-test binaries set HOME by hand, which the source gate every_pinned_home_pins_the_instance refuses: a pinned home without the instance resolves another directory under this repo's .envrc. They now apply nxs_test_support::pinned_home_env() to their own process. The dcpd fragment says `facade: changed` (a behaviour change behind unchanged signatures: an unvouched answer now cancels the border thread). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018Sipejn8YQhKgngxeHpMhT * Mitigate the review of PR #17: hermetic user-level folder, channel-only policy reads, named revoked-trust cause, group stop - A build reads a user-level folder only under a NAMED development instance, never the production one, and an unresolvable home or instance means no folder rather than an error (Code #2, #3; Integrity #3, #4). Guard test: a build under the production instance does not see personas planted in the production folder. - An existing but unreadable user-level folder is an error, not a silence (Integrity #5). - `threads show`, `search`, `Engine::thread` and `Engine::search` read the merged channels only (`merged_channels`), so a malformed persona file cannot make a thread unreadable (Code #1). - `nxc prime`, `Engine::prime_as` and `nxs prime --persona` resolve the catalogue once (`prime_with`) (Code #5). - The revoked-trust cancel fires only on an answer not yet served, so a question delivered before the revocation does not cancel; two negative controls, mutation-checked (Test #1, Integrity #7). - A stuck peer handover runs in its own process group, which is killed as a whole and then reaped by polling; the sidecar it started has a group of its own and survives; start-idempotence rests on the admission claim (Code #7, Integrity #6). Test drops the wall-clock assertion and gates `true` on unix (Test #3, #4). - The freeze test now edits a user-level hurdle too (Code #6); loader failing cases for channels, a missing and an unreadable folder, a dangling member (Test #2). - A user-level `external` admits only from workspaces the running repository trusts — tested through the binary and written in the guide (Integrity #2); the guide no longer calls a hiding "never silent" but says where it is shown (Integrity #1, the lock question filed as 6j6v.3mgy). - Stale prose and wraps (Code #4, #9). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018Sipejn8YQhKgngxeHpMhT --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
The first release from the public repo (v0.200.0, run 36008146938) was green except for
publish-npm:404 … PUT @nexus-flow/mcp: the trusted-publisher entry still pointed at the pre-cutover repo. The owner re-added it.403 … OIDC permission denied for this action: trusted publishers created since 2026-09-03 allow only staged publishing by default, and the job rannpm publish.The token exchange and the provenance both worked (sigstore logIndex 2943855459), so it is not the immutable-subject problem npm/cli#9969, which fails earlier, at the exchange.
What
Follow npm's way instead of allowing direct publish again:
npm stage publish --access public --provenance: the version lands on npm unavailable to the public until a maintainer approves it with 2FA (npmjs.com, ornpm stage approve <id>).>=11.15.0 <12(staged publishing).docs/specs/release-management.md§12 item 9: stage-only allowed actions (c), npm version (f), the approval step (g), and the finding that the trusted-publisher entry is bound to the repository, not just its name.Staging rehearsals are unchanged (
npm pack, registry-free).Evidence
actionlint .github/workflows/release.ymlparses the file; its four info-level shellcheck notes are at lines 720 and 815, which this diff does not touch. The staged path itself can only be exercised by a real tag release. A rerun of 36008146938 runs the tagged commit's oldnpm publish, so the first staged version will be the next release.skip-changelog:release.ymlis a carved-out delivery file, but nothing a user installs changes. The npm package still appears, just after an approval.🤖 Generated with Claude Code
https://claude.ai/code/session_01NhwrYjEtdnS3jCneb57X3k